From 45613661bc478488f15646c76bf54c33332497e1 Mon Sep 17 00:00:00 2001 From: Kurtis Moxley Date: Tue, 5 Jul 2022 14:25:26 +0800 Subject: [PATCH] Update Coc.nvim --- .../coc.nvim/.all-contributorsrc | 1853 +++ sources_non_forked/coc.nvim/.editorconfig | 22 + sources_non_forked/coc.nvim/.eslintignore | 5 + sources_non_forked/coc.nvim/.eslintrc.js | 339 + .../coc.nvim/.github/.codecov.yml | 3 + .../coc.nvim/.github/FUNDING.yml | 4 + .../.github/ISSUE_TEMPLATE/bug_report.md | 45 + .../.github/ISSUE_TEMPLATE/feature_request.md | 17 + .../coc.nvim/.github/workflows/ci.yml | 73 + .../coc.nvim/.github/workflows/lint.yml | 35 + sources_non_forked/coc.nvim/.gitignore | 13 +- sources_non_forked/coc.nvim/.ignore | 1 + sources_non_forked/coc.nvim/.npmignore | 16 + sources_non_forked/coc.nvim/.prettierignore | 1 + sources_non_forked/coc.nvim/.swcrc | 16 + .../coc.nvim/.vim/coc-settings.json | 7 + sources_non_forked/coc.nvim/Backers.md | 207 + sources_non_forked/coc.nvim/CONTRIBUTING.md | 142 + sources_non_forked/coc.nvim/LICENSE.md | 47 +- .../coc.nvim/{Readme.md => README.md} | 0 .../coc.nvim/autoload/coc/helper.vim | 148 - .../coc.nvim/autoload/coc/notify.vim | 5 +- .../coc.nvim/autoload/coc/util.vim | 47 +- sources_non_forked/coc.nvim/build/index.js | 337 - sources_non_forked/coc.nvim/esbuild.js | 77 + sources_non_forked/coc.nvim/history.md | 4 + sources_non_forked/coc.nvim/jest.js | 21 + sources_non_forked/coc.nvim/package.json | 111 +- sources_non_forked/coc.nvim/requirements.txt | 0 .../__tests__/autoload/coc/source/email.vim | 17 + .../src/__tests__/client/changedFiles.test.ts | 62 + .../src/__tests__/client/connection.test.ts | 139 + .../src/__tests__/client/converter.test.ts | 86 + .../src/__tests__/client/delayer.test.ts | 72 + .../src/__tests__/client/features.test.ts | 1054 ++ .../src/__tests__/client/integration.test.ts | 123 + .../client/server/testFileWatcher.js | 35 + .../client/server/testInitializeResult.js | 36 + .../src/__tests__/client/server/testServer.js | 409 + .../coc.nvim/src/__tests__/coc-settings.json | 4 + .../src/__tests__/completion/basic.test.ts | 1154 ++ .../src/__tests__/completion/float.test.ts | 198 + .../src/__tests__/completion/language.test.ts | 317 + .../src/__tests__/completion/sources.test.ts | 65 + .../src/__tests__/completion/util.test.ts | 144 + .../src/__tests__/core/autocmds.test.ts | 68 + .../src/__tests__/core/documents.test.ts | 85 + .../src/__tests__/core/editors.test.ts | 169 + .../__tests__/core/fileSystemWatcher.test.ts | 380 + .../coc.nvim/src/__tests__/core/files.test.ts | 813 ++ .../coc.nvim/src/__tests__/core/funcs.test.ts | 94 + .../src/__tests__/core/keymaps.test.ts | 79 + .../src/__tests__/core/locations.test.ts | 148 + .../src/__tests__/core/terminals.test.ts | 136 + .../coc.nvim/src/__tests__/core/ui.test.ts | 92 + .../__tests__/core/workspaceFolder.test.ts | 290 + .../src/__tests__/extensions/global/index.js | 7 + .../__tests__/extensions/global/package.json | 7 + .../src/__tests__/extensions/package.json | 6 + .../coc.nvim/src/__tests__/extensions/root.js | 7 + .../src/__tests__/extensions/test/index.js | 13 + .../__tests__/extensions/test/package.json | 33 + .../__tests__/extensions/vim/local/index.js | 7 + .../extensions/vim/local/package.json | 7 + .../__tests__/handler/callHierarchy.test.ts | 390 + .../src/__tests__/handler/codeActions.test.ts | 414 + .../src/__tests__/handler/codelens.test.ts | 316 + .../src/__tests__/handler/colors.test.ts | 264 + .../src/__tests__/handler/commands.test.ts | 82 + .../src/__tests__/handler/fold.test.ts | 77 + .../src/__tests__/handler/format.test.ts | 252 + .../src/__tests__/handler/highlights.test.ts | 140 + .../src/__tests__/handler/hover.test.ts | 178 + .../src/__tests__/handler/index.test.ts | 93 + .../src/__tests__/handler/inlayHint.test.ts | 233 + .../__tests__/handler/linkedEditing.test.ts | 157 + .../src/__tests__/handler/links.test.ts | 137 + .../src/__tests__/handler/locations.test.ts | 323 + .../src/__tests__/handler/outline.test.ts | 467 + .../coc.nvim/src/__tests__/handler/parser.ts | 118 + .../src/__tests__/handler/refactor.test.ts | 677 ++ .../src/__tests__/handler/rename.test.ts | 262 + .../src/__tests__/handler/search.test.ts | 101 + .../__tests__/handler/selectionRange.test.ts | 144 + .../__tests__/handler/semanticTokens.test.ts | 584 + .../src/__tests__/handler/signature.test.ts | 369 + .../src/__tests__/handler/symbols.test.ts | 280 + .../src/__tests__/handler/workspace.test.ts | 99 + .../coc.nvim/src/__tests__/helper.test.ts | 22 + .../coc.nvim/src/__tests__/helper.ts | 360 + .../src/__tests__/list/commandTask.test.ts | 136 + .../src/__tests__/list/manager.test.ts | 508 + .../src/__tests__/list/mappings.test.ts | 764 ++ .../src/__tests__/list/session.test.ts | 304 + .../src/__tests__/list/sources.test.ts | 666 + .../coc.nvim/src/__tests__/list/ui.test.ts | 274 + .../src/__tests__/list/worker.test.ts | 226 + .../src/__tests__/markdown/index.test.ts | 265 + .../src/__tests__/markdown/renderer.test.ts | 119 + .../coc.nvim/src/__tests__/memos.json | 1 + .../src/__tests__/modules/attach.test.ts | 53 + .../src/__tests__/modules/chars.test.ts | 74 + .../__tests__/modules/configurations.test.ts | 617 + .../src/__tests__/modules/cursors.test.ts | 686 ++ .../coc.nvim/src/__tests__/modules/db.test.ts | 60 + .../modules/diagnosticBuffer.test.ts | 348 + .../modules/diagnosticCollection.test.ts | 101 + .../modules/diagnosticManager.test.ts | 677 ++ .../src/__tests__/modules/dialog.test.ts | 60 + .../src/__tests__/modules/document.test.ts | 712 ++ .../src/__tests__/modules/events.test.ts | 128 + .../src/__tests__/modules/extensions.test.ts | 231 + .../src/__tests__/modules/fetch.test.ts | 86 + .../__tests__/modules/floatFactory.test.ts | 254 + .../coc.nvim/src/__tests__/modules/fs.test.ts | 216 + .../src/__tests__/modules/installer.test.ts | 125 + .../src/__tests__/modules/memos.test.ts | 45 + .../src/__tests__/modules/menu.test.ts | 163 + .../src/__tests__/modules/mru.test.ts | 43 + .../__tests__/modules/outputChannel.test.ts | 82 + .../src/__tests__/modules/picker.test.ts | 161 + .../src/__tests__/modules/plugin.test.ts | 48 + .../src/__tests__/modules/quickpick.test.ts | 325 + .../src/__tests__/modules/regions.test.ts | 74 + .../src/__tests__/modules/sandbox/log.js | 9 + .../modules/semanticTokensBuilder.test.ts | 80 + .../src/__tests__/modules/settings.json | 12 + .../src/__tests__/modules/sources.test.ts | 198 + .../src/__tests__/modules/task.test.ts | 151 + .../src/__tests__/modules/terminal.test.ts | 53 + .../src/__tests__/modules/util.test.ts | 1111 ++ .../src/__tests__/modules/window.test.ts | 722 ++ .../src/__tests__/modules/workspace.test.ts | 714 ++ sources_non_forked/coc.nvim/src/__tests__/rg | 38 + .../__tests__/sample/.vim/coc-settings.json | 3 + .../src/__tests__/snippets/manager.test.ts | 302 + .../src/__tests__/snippets/parser.test.ts | 1013 ++ .../src/__tests__/snippets/session.test.ts | 544 + .../src/__tests__/snippets/snippet.test.ts | 600 + .../src/__tests__/snippets/string.test.ts | 78 + .../src/__tests__/tree/basicProvider.test.ts | 541 + .../src/__tests__/tree/treeView.test.ts | 1176 ++ .../coc.nvim/src/__tests__/ultisnips.py | 280 + .../coc.nvim/src/__tests__/vimrc | 64 + sources_non_forked/coc.nvim/src/attach.ts | 137 + sources_non_forked/coc.nvim/src/commands.ts | 426 + .../coc.nvim/src/completion/complete.ts | 407 + .../coc.nvim/src/completion/floating.ts | 68 + .../coc.nvim/src/completion/index.ts | 600 + .../coc.nvim/src/completion/match.ts | 98 + .../coc.nvim/src/completion/mru.ts | 56 + .../coc.nvim/src/completion/util.ts | 50 + .../src/configuration/configuration.ts | 71 + .../coc.nvim/src/configuration/index.ts | 417 + .../coc.nvim/src/configuration/model.ts | 65 + .../coc.nvim/src/configuration/shape.ts | 61 + .../coc.nvim/src/configuration/util.ts | 292 + .../coc.nvim/src/core/autocmds.ts | 105 + .../coc.nvim/src/core/channels.ts | 80 + .../coc.nvim/src/core/contentProvider.ts | 74 + .../coc.nvim/src/core/documents.ts | 592 + .../coc.nvim/src/core/editors.ts | 142 + .../coc.nvim/src/core/fileSystemWatcher.ts | 197 + sources_non_forked/coc.nvim/src/core/files.ts | 526 + sources_non_forked/coc.nvim/src/core/funcs.ts | 158 + .../coc.nvim/src/core/keymaps.ts | 98 + .../coc.nvim/src/core/locations.ts | 56 + .../coc.nvim/src/core/terminals.ts | 65 + sources_non_forked/coc.nvim/src/core/ui.ts | 104 + .../coc.nvim/src/core/watchers.ts | 90 + .../coc.nvim/src/core/watchman.ts | 184 + .../coc.nvim/src/core/workspaceFolder.ts | 186 + .../coc.nvim/src/cursors/index.ts | 126 + .../coc.nvim/src/cursors/session.ts | 391 + .../coc.nvim/src/cursors/textRange.ts | 93 + .../coc.nvim/src/cursors/util.ts | 110 + .../coc.nvim/src/diagnostic/buffer.ts | 436 + .../coc.nvim/src/diagnostic/collection.ts | 96 + .../coc.nvim/src/diagnostic/manager.ts | 681 ++ .../coc.nvim/src/diagnostic/util.ts | 176 + sources_non_forked/coc.nvim/src/events.ts | 285 + sources_non_forked/coc.nvim/src/extensions.ts | 1110 ++ .../coc.nvim/src/handler/callHierarchy.ts | 258 + .../coc.nvim/src/handler/codeActions.ts | 149 + .../coc.nvim/src/handler/codelens/buffer.ts | 233 + .../coc.nvim/src/handler/codelens/index.ts | 75 + .../src/handler/colors/colorBuffer.ts | 129 + .../coc.nvim/src/handler/colors/index.ts | 144 + .../coc.nvim/src/handler/commands.ts | 54 + .../coc.nvim/src/handler/fold.ts | 35 + .../coc.nvim/src/handler/format.ts | 212 + .../coc.nvim/src/handler/highlights.ts | 132 + .../coc.nvim/src/handler/hover.ts | 245 + .../coc.nvim/src/handler/index.ts | 218 + .../coc.nvim/src/handler/inlayHint/buffer.ts | 114 + .../coc.nvim/src/handler/inlayHint/index.ts | 51 + .../coc.nvim/src/handler/linkedEditing.ts | 160 + .../coc.nvim/src/handler/links.ts | 122 + .../coc.nvim/src/handler/locations.ts | 178 + .../coc.nvim/src/handler/refactor/buffer.ts | 672 + .../coc.nvim/src/handler/refactor/changes.ts | 33 + .../coc.nvim/src/handler/refactor/index.ts | 234 + .../coc.nvim/src/handler/refactor/search.ts | 190 + .../coc.nvim/src/handler/rename.ts | 71 + .../coc.nvim/src/handler/selectionRange.ts | 84 + .../src/handler/semanticTokens/buffer.ts | 475 + .../src/handler/semanticTokens/index.ts | 242 + .../coc.nvim/src/handler/signature.ts | 277 + .../coc.nvim/src/handler/symbols/buffer.ts | 91 + .../coc.nvim/src/handler/symbols/index.ts | 174 + .../coc.nvim/src/handler/symbols/outline.ts | 343 + .../coc.nvim/src/handler/symbols/util.ts | 63 + .../coc.nvim/src/handler/workspace.ts | 104 + sources_non_forked/coc.nvim/src/index.ts | 152 + sources_non_forked/coc.nvim/src/inlayHint.ts | 179 + .../coc.nvim/src/language-client/LICENSE.txt | 23 + .../src/language-client/callHierarchy.ts | 116 + .../coc.nvim/src/language-client/client.ts | 4430 +++++++ .../src/language-client/colorProvider.ts | 107 + .../src/language-client/configuration.ts | 95 + .../src/language-client/declaration.ts | 61 + .../src/language-client/fileOperations.ts | 430 + .../src/language-client/foldingRange.ts | 81 + .../src/language-client/implementation.ts | 59 + .../coc.nvim/src/language-client/index.ts | 655 + .../src/language-client/linkedEditingRange.ts | 65 + .../coc.nvim/src/language-client/progress.ts | 39 + .../src/language-client/progressPart.ts | 110 + .../src/language-client/selectionRange.ts | 64 + .../src/language-client/semanticTokens.ts | 196 + .../src/language-client/typeDefinition.ts | 68 + .../src/language-client/utils/async.ts | 88 + .../src/language-client/utils/converter.ts | 125 + .../src/language-client/utils/uuid.ts | 6 + .../src/language-client/workspaceFolders.ts | 166 + sources_non_forked/coc.nvim/src/languages.ts | 482 + sources_non_forked/coc.nvim/src/list/basic.ts | 323 + .../coc.nvim/src/list/commandTask.ts | 62 + .../coc.nvim/src/list/configuration.ts | 121 + .../coc.nvim/src/list/formatting.ts | 56 + .../coc.nvim/src/list/history.ts | 84 + .../coc.nvim/src/list/manager.ts | 523 + .../coc.nvim/src/list/mappings.ts | 313 + .../coc.nvim/src/list/prompt.ts | 215 + .../coc.nvim/src/list/session.ts | 582 + .../coc.nvim/src/list/source/commands.ts | 56 + .../coc.nvim/src/list/source/diagnostics.ts | 59 + .../coc.nvim/src/list/source/extensions.ts | 179 + .../coc.nvim/src/list/source/folders.ts | 50 + .../coc.nvim/src/list/source/links.ts | 77 + .../coc.nvim/src/list/source/lists.ts | 54 + .../coc.nvim/src/list/source/location.ts | 93 + .../coc.nvim/src/list/source/outline.ts | 161 + .../coc.nvim/src/list/source/services.ts | 49 + .../coc.nvim/src/list/source/sources.ts | 77 + .../coc.nvim/src/list/source/symbols.ts | 103 + sources_non_forked/coc.nvim/src/list/ui.ts | 512 + .../coc.nvim/src/list/worker.ts | 420 + sources_non_forked/coc.nvim/src/main.ts | 26 + .../coc.nvim/src/markdown/index.ts | 201 + .../coc.nvim/src/markdown/renderer.ts | 359 + .../coc.nvim/src/markdown/styles.ts | 38 + .../coc.nvim/src/model/bufferSync.ts | 94 + .../coc.nvim/src/model/chars.ts | 189 + sources_non_forked/coc.nvim/src/model/db.ts | 134 + .../coc.nvim/src/model/dialog.ts | 123 + .../coc.nvim/src/model/document.ts | 731 ++ .../coc.nvim/src/model/download.ts | 144 + .../coc.nvim/src/model/editInspect.ts | 216 + .../coc.nvim/src/model/fetch.ts | 269 + .../coc.nvim/src/model/floatFactory.ts | 242 + .../coc.nvim/src/model/highligher.ts | 136 + .../coc.nvim/src/model/input.ts | 142 + .../coc.nvim/src/model/installBuffer.ts | 152 + .../coc.nvim/src/model/installer.ts | 299 + .../coc.nvim/src/model/memos.ts | 64 + sources_non_forked/coc.nvim/src/model/menu.ts | 282 + sources_non_forked/coc.nvim/src/model/mru.ts | 92 + .../coc.nvim/src/model/notification.ts | 105 + .../coc.nvim/src/model/outputChannel.ts | 88 + .../coc.nvim/src/model/picker.ts | 241 + .../coc.nvim/src/model/popup.ts | 104 + .../coc.nvim/src/model/progress.ts | 69 + .../coc.nvim/src/model/quickpick.ts | 318 + .../coc.nvim/src/model/regions.ts | 72 + .../coc.nvim/src/model/relativePattern.ts | 35 + .../coc.nvim/src/model/resolver.ts | 46 + .../src/model/semanticTokensBuilder.ts | 208 + .../coc.nvim/src/model/status.ts | 97 + sources_non_forked/coc.nvim/src/model/task.ts | 91 + .../coc.nvim/src/model/terminal.ts | 120 + .../coc.nvim/src/model/textdocument.ts | 127 + .../coc.nvim/src/model/textline.ts | 66 + sources_non_forked/coc.nvim/src/plugin.ts | 262 + .../src/provider/callHierarchyManager.ts | 46 + .../src/provider/codeActionManager.ts | 91 + .../coc.nvim/src/provider/codeLensManager.ts | 59 + .../src/provider/declarationManager.ts | 33 + .../src/provider/definitionManager.ts | 65 + .../src/provider/documentColorManager.ts | 38 + .../src/provider/documentHighlightManager.ts | 32 + .../src/provider/documentLinkManager.ts | 52 + .../src/provider/documentSymbolManager.ts | 38 + .../src/provider/foldingRangeManager.ts | 28 + .../coc.nvim/src/provider/formatManager.ts | 39 + .../src/provider/formatRangeManager.ts | 36 + .../coc.nvim/src/provider/hoverManager.ts | 37 + .../src/provider/implementationManager.ts | 35 + .../coc.nvim/src/provider/index.ts | 860 ++ .../coc.nvim/src/provider/inlayHintManager.ts | 97 + .../src/provider/linkedEditingRangeManager.ts | 30 + .../coc.nvim/src/provider/manager.ts | 80 + .../src/provider/onTypeFormatManager.ts | 55 + .../coc.nvim/src/provider/referenceManager.ts | 36 + .../coc.nvim/src/provider/renameManager.ts | 48 + .../src/provider/selectionRangeManager.ts | 38 + .../src/provider/semanticTokensManager.ts | 69 + .../provider/semanticTokensRangeManager.ts | 36 + .../coc.nvim/src/provider/signatureManager.ts | 43 + .../src/provider/typeDefinitionManager.ts | 35 + .../src/provider/workspaceSymbolsManager.ts | 48 + sources_non_forked/coc.nvim/src/services.ts | 569 + .../coc.nvim/src/snippets/eval.ts | 165 + .../coc.nvim/src/snippets/manager.ts | 208 + .../coc.nvim/src/snippets/parser.ts | 1776 +++ .../coc.nvim/src/snippets/session.ts | 383 + .../coc.nvim/src/snippets/snippet.ts | 458 + .../coc.nvim/src/snippets/string.ts | 103 + .../coc.nvim/src/snippets/variableResolve.ts | 164 + .../coc.nvim/src/sources/index.ts | 421 + .../coc.nvim/src/sources/keywords.ts | 75 + .../coc.nvim/src/sources/native/around.ts | 99 + .../coc.nvim/src/sources/native/buffer.ts | 88 + .../coc.nvim/src/sources/native/file.ts | 160 + .../coc.nvim/src/sources/source-language.ts | 353 + .../coc.nvim/src/sources/source-vim.ts | 98 + .../coc.nvim/src/sources/source.ts | 151 + .../coc.nvim/src/tree/BasicDataProvider.ts | 262 + .../coc.nvim/src/tree/TreeItem.ts | 63 + .../coc.nvim/src/tree/TreeView.ts | 1031 ++ .../coc.nvim/src/tree/filter.ts | 96 + sources_non_forked/coc.nvim/src/tree/index.ts | 258 + sources_non_forked/coc.nvim/src/types.ts | 1153 ++ .../coc.nvim/src/util/ansiparse.ts | 249 + sources_non_forked/coc.nvim/src/util/array.ts | 115 + sources_non_forked/coc.nvim/src/util/async.ts | 89 + .../coc.nvim/src/util/charCode.ts | 425 + sources_non_forked/coc.nvim/src/util/color.ts | 33 + .../coc.nvim/src/util/convert.ts | 61 + sources_non_forked/coc.nvim/src/util/diff.ts | 204 + .../coc.nvim/src/util/errors.ts | 29 + .../coc.nvim/src/util/extensions.ts | 16 + .../coc.nvim/src/util/factory.ts | 179 + sources_non_forked/coc.nvim/src/util/fs.ts | 277 + sources_non_forked/coc.nvim/src/util/fuzzy.ts | 50 + sources_non_forked/coc.nvim/src/util/fzy.ts | 202 + sources_non_forked/coc.nvim/src/util/index.ts | 163 + sources_non_forked/coc.nvim/src/util/is.ts | 59 + .../coc.nvim/src/util/lodash.ts | 53 + .../coc.nvim/src/util/logger.ts | 70 + sources_non_forked/coc.nvim/src/util/mutex.ts | 47 + .../coc.nvim/src/util/object.ts | 138 + .../coc.nvim/src/util/platform.ts | 79 + .../coc.nvim/src/util/position.ts | 114 + .../coc.nvim/src/util/processes.ts | 51 + sources_non_forked/coc.nvim/src/util/score.ts | 142 + .../coc.nvim/src/util/string.ts | 149 + .../coc.nvim/src/util/textedit.ts | 312 + sources_non_forked/coc.nvim/src/window.ts | 935 ++ sources_non_forked/coc.nvim/src/workspace.ts | 552 + sources_non_forked/coc.nvim/tsconfig.json | 28 + sources_non_forked/coc.nvim/typings/LICENSE | 19 + sources_non_forked/coc.nvim/typings/Readme.md | 18 + .../coc.nvim/typings/index.d.ts | 10107 ++++++++++++++++ sources_non_forked/coc.nvim/yarn.lock | 3736 ++++++ sources_non_forked/rust.vim/test/run-tests | 0 376 files changed, 93665 insertions(+), 505 deletions(-) create mode 100644 sources_non_forked/coc.nvim/.all-contributorsrc create mode 100644 sources_non_forked/coc.nvim/.editorconfig create mode 100644 sources_non_forked/coc.nvim/.eslintignore create mode 100644 sources_non_forked/coc.nvim/.eslintrc.js create mode 100644 sources_non_forked/coc.nvim/.github/.codecov.yml create mode 100644 sources_non_forked/coc.nvim/.github/FUNDING.yml create mode 100644 sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 sources_non_forked/coc.nvim/.github/workflows/ci.yml create mode 100644 sources_non_forked/coc.nvim/.github/workflows/lint.yml create mode 100644 sources_non_forked/coc.nvim/.ignore create mode 100644 sources_non_forked/coc.nvim/.npmignore create mode 100644 sources_non_forked/coc.nvim/.prettierignore create mode 100644 sources_non_forked/coc.nvim/.swcrc create mode 100644 sources_non_forked/coc.nvim/.vim/coc-settings.json create mode 100644 sources_non_forked/coc.nvim/Backers.md create mode 100644 sources_non_forked/coc.nvim/CONTRIBUTING.md rename sources_non_forked/coc.nvim/{Readme.md => README.md} (100%) delete mode 100644 sources_non_forked/coc.nvim/autoload/coc/helper.vim delete mode 100644 sources_non_forked/coc.nvim/build/index.js create mode 100644 sources_non_forked/coc.nvim/esbuild.js create mode 100644 sources_non_forked/coc.nvim/jest.js create mode 100644 sources_non_forked/coc.nvim/requirements.txt create mode 100644 sources_non_forked/coc.nvim/src/__tests__/autoload/coc/source/email.vim create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/changedFiles.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/connection.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/converter.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/delayer.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/features.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/integration.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/server/testFileWatcher.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/server/testInitializeResult.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/client/server/testServer.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/coc-settings.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/completion/basic.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/completion/float.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/completion/language.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/completion/sources.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/completion/util.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/autocmds.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/documents.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/editors.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/fileSystemWatcher.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/files.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/funcs.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/keymaps.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/locations.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/terminals.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/ui.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/core/workspaceFolder.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/global/index.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/global/package.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/package.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/root.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/test/index.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/test/package.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/index.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/package.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/callHierarchy.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/codeActions.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/codelens.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/colors.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/commands.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/fold.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/format.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/highlights.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/hover.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/index.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/inlayHint.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/linkedEditing.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/links.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/locations.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/outline.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/parser.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/refactor.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/rename.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/search.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/selectionRange.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/semanticTokens.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/signature.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/symbols.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/handler/workspace.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/helper.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/helper.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/commandTask.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/manager.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/mappings.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/session.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/sources.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/ui.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/list/worker.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/markdown/index.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/markdown/renderer.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/memos.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/attach.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/chars.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/configurations.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/cursors.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/db.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/dialog.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/document.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/events.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/extensions.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/fetch.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/floatFactory.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/fs.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/installer.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/memos.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/menu.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/mru.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/outputChannel.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/picker.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/plugin.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/quickpick.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/regions.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/sandbox/log.js create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/semanticTokensBuilder.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/settings.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/sources.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/task.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/terminal.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/util.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/window.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/modules/workspace.test.ts create mode 100755 sources_non_forked/coc.nvim/src/__tests__/rg create mode 100644 sources_non_forked/coc.nvim/src/__tests__/sample/.vim/coc-settings.json create mode 100644 sources_non_forked/coc.nvim/src/__tests__/snippets/manager.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/snippets/parser.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/snippets/session.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/snippets/snippet.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/snippets/string.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/tree/basicProvider.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/tree/treeView.test.ts create mode 100644 sources_non_forked/coc.nvim/src/__tests__/ultisnips.py create mode 100644 sources_non_forked/coc.nvim/src/__tests__/vimrc create mode 100644 sources_non_forked/coc.nvim/src/attach.ts create mode 100644 sources_non_forked/coc.nvim/src/commands.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/complete.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/floating.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/index.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/match.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/mru.ts create mode 100644 sources_non_forked/coc.nvim/src/completion/util.ts create mode 100644 sources_non_forked/coc.nvim/src/configuration/configuration.ts create mode 100644 sources_non_forked/coc.nvim/src/configuration/index.ts create mode 100644 sources_non_forked/coc.nvim/src/configuration/model.ts create mode 100644 sources_non_forked/coc.nvim/src/configuration/shape.ts create mode 100644 sources_non_forked/coc.nvim/src/configuration/util.ts create mode 100644 sources_non_forked/coc.nvim/src/core/autocmds.ts create mode 100644 sources_non_forked/coc.nvim/src/core/channels.ts create mode 100644 sources_non_forked/coc.nvim/src/core/contentProvider.ts create mode 100644 sources_non_forked/coc.nvim/src/core/documents.ts create mode 100644 sources_non_forked/coc.nvim/src/core/editors.ts create mode 100644 sources_non_forked/coc.nvim/src/core/fileSystemWatcher.ts create mode 100644 sources_non_forked/coc.nvim/src/core/files.ts create mode 100644 sources_non_forked/coc.nvim/src/core/funcs.ts create mode 100644 sources_non_forked/coc.nvim/src/core/keymaps.ts create mode 100644 sources_non_forked/coc.nvim/src/core/locations.ts create mode 100644 sources_non_forked/coc.nvim/src/core/terminals.ts create mode 100644 sources_non_forked/coc.nvim/src/core/ui.ts create mode 100644 sources_non_forked/coc.nvim/src/core/watchers.ts create mode 100644 sources_non_forked/coc.nvim/src/core/watchman.ts create mode 100644 sources_non_forked/coc.nvim/src/core/workspaceFolder.ts create mode 100644 sources_non_forked/coc.nvim/src/cursors/index.ts create mode 100644 sources_non_forked/coc.nvim/src/cursors/session.ts create mode 100644 sources_non_forked/coc.nvim/src/cursors/textRange.ts create mode 100644 sources_non_forked/coc.nvim/src/cursors/util.ts create mode 100644 sources_non_forked/coc.nvim/src/diagnostic/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/diagnostic/collection.ts create mode 100644 sources_non_forked/coc.nvim/src/diagnostic/manager.ts create mode 100644 sources_non_forked/coc.nvim/src/diagnostic/util.ts create mode 100644 sources_non_forked/coc.nvim/src/events.ts create mode 100644 sources_non_forked/coc.nvim/src/extensions.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/callHierarchy.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/codeActions.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/codelens/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/codelens/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/colors/colorBuffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/colors/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/commands.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/fold.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/format.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/highlights.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/hover.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/inlayHint/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/inlayHint/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/linkedEditing.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/links.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/locations.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/refactor/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/refactor/changes.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/refactor/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/refactor/search.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/rename.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/selectionRange.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/semanticTokens/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/semanticTokens/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/signature.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/symbols/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/symbols/index.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/symbols/outline.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/symbols/util.ts create mode 100644 sources_non_forked/coc.nvim/src/handler/workspace.ts create mode 100644 sources_non_forked/coc.nvim/src/index.ts create mode 100644 sources_non_forked/coc.nvim/src/inlayHint.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/LICENSE.txt create mode 100644 sources_non_forked/coc.nvim/src/language-client/callHierarchy.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/client.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/colorProvider.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/configuration.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/declaration.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/fileOperations.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/foldingRange.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/implementation.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/index.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/linkedEditingRange.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/progress.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/progressPart.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/selectionRange.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/semanticTokens.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/typeDefinition.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/utils/async.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/utils/converter.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/utils/uuid.ts create mode 100644 sources_non_forked/coc.nvim/src/language-client/workspaceFolders.ts create mode 100644 sources_non_forked/coc.nvim/src/languages.ts create mode 100644 sources_non_forked/coc.nvim/src/list/basic.ts create mode 100644 sources_non_forked/coc.nvim/src/list/commandTask.ts create mode 100644 sources_non_forked/coc.nvim/src/list/configuration.ts create mode 100644 sources_non_forked/coc.nvim/src/list/formatting.ts create mode 100644 sources_non_forked/coc.nvim/src/list/history.ts create mode 100644 sources_non_forked/coc.nvim/src/list/manager.ts create mode 100644 sources_non_forked/coc.nvim/src/list/mappings.ts create mode 100644 sources_non_forked/coc.nvim/src/list/prompt.ts create mode 100644 sources_non_forked/coc.nvim/src/list/session.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/commands.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/diagnostics.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/extensions.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/folders.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/links.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/lists.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/location.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/outline.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/services.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/sources.ts create mode 100644 sources_non_forked/coc.nvim/src/list/source/symbols.ts create mode 100644 sources_non_forked/coc.nvim/src/list/ui.ts create mode 100644 sources_non_forked/coc.nvim/src/list/worker.ts create mode 100755 sources_non_forked/coc.nvim/src/main.ts create mode 100644 sources_non_forked/coc.nvim/src/markdown/index.ts create mode 100644 sources_non_forked/coc.nvim/src/markdown/renderer.ts create mode 100644 sources_non_forked/coc.nvim/src/markdown/styles.ts create mode 100644 sources_non_forked/coc.nvim/src/model/bufferSync.ts create mode 100644 sources_non_forked/coc.nvim/src/model/chars.ts create mode 100644 sources_non_forked/coc.nvim/src/model/db.ts create mode 100644 sources_non_forked/coc.nvim/src/model/dialog.ts create mode 100644 sources_non_forked/coc.nvim/src/model/document.ts create mode 100644 sources_non_forked/coc.nvim/src/model/download.ts create mode 100644 sources_non_forked/coc.nvim/src/model/editInspect.ts create mode 100644 sources_non_forked/coc.nvim/src/model/fetch.ts create mode 100644 sources_non_forked/coc.nvim/src/model/floatFactory.ts create mode 100644 sources_non_forked/coc.nvim/src/model/highligher.ts create mode 100644 sources_non_forked/coc.nvim/src/model/input.ts create mode 100644 sources_non_forked/coc.nvim/src/model/installBuffer.ts create mode 100644 sources_non_forked/coc.nvim/src/model/installer.ts create mode 100644 sources_non_forked/coc.nvim/src/model/memos.ts create mode 100644 sources_non_forked/coc.nvim/src/model/menu.ts create mode 100644 sources_non_forked/coc.nvim/src/model/mru.ts create mode 100644 sources_non_forked/coc.nvim/src/model/notification.ts create mode 100644 sources_non_forked/coc.nvim/src/model/outputChannel.ts create mode 100644 sources_non_forked/coc.nvim/src/model/picker.ts create mode 100644 sources_non_forked/coc.nvim/src/model/popup.ts create mode 100644 sources_non_forked/coc.nvim/src/model/progress.ts create mode 100644 sources_non_forked/coc.nvim/src/model/quickpick.ts create mode 100644 sources_non_forked/coc.nvim/src/model/regions.ts create mode 100644 sources_non_forked/coc.nvim/src/model/relativePattern.ts create mode 100644 sources_non_forked/coc.nvim/src/model/resolver.ts create mode 100644 sources_non_forked/coc.nvim/src/model/semanticTokensBuilder.ts create mode 100644 sources_non_forked/coc.nvim/src/model/status.ts create mode 100644 sources_non_forked/coc.nvim/src/model/task.ts create mode 100644 sources_non_forked/coc.nvim/src/model/terminal.ts create mode 100644 sources_non_forked/coc.nvim/src/model/textdocument.ts create mode 100644 sources_non_forked/coc.nvim/src/model/textline.ts create mode 100644 sources_non_forked/coc.nvim/src/plugin.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/callHierarchyManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/codeActionManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/codeLensManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/declarationManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/definitionManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/documentColorManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/documentHighlightManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/documentLinkManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/documentSymbolManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/foldingRangeManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/formatManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/formatRangeManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/hoverManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/implementationManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/index.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/inlayHintManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/linkedEditingRangeManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/manager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/onTypeFormatManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/referenceManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/renameManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/selectionRangeManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/semanticTokensManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/semanticTokensRangeManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/signatureManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/typeDefinitionManager.ts create mode 100644 sources_non_forked/coc.nvim/src/provider/workspaceSymbolsManager.ts create mode 100644 sources_non_forked/coc.nvim/src/services.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/eval.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/manager.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/parser.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/session.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/snippet.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/string.ts create mode 100644 sources_non_forked/coc.nvim/src/snippets/variableResolve.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/index.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/keywords.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/native/around.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/native/buffer.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/native/file.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/source-language.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/source-vim.ts create mode 100644 sources_non_forked/coc.nvim/src/sources/source.ts create mode 100644 sources_non_forked/coc.nvim/src/tree/BasicDataProvider.ts create mode 100644 sources_non_forked/coc.nvim/src/tree/TreeItem.ts create mode 100644 sources_non_forked/coc.nvim/src/tree/TreeView.ts create mode 100644 sources_non_forked/coc.nvim/src/tree/filter.ts create mode 100644 sources_non_forked/coc.nvim/src/tree/index.ts create mode 100644 sources_non_forked/coc.nvim/src/types.ts create mode 100644 sources_non_forked/coc.nvim/src/util/ansiparse.ts create mode 100644 sources_non_forked/coc.nvim/src/util/array.ts create mode 100644 sources_non_forked/coc.nvim/src/util/async.ts create mode 100644 sources_non_forked/coc.nvim/src/util/charCode.ts create mode 100644 sources_non_forked/coc.nvim/src/util/color.ts create mode 100644 sources_non_forked/coc.nvim/src/util/convert.ts create mode 100644 sources_non_forked/coc.nvim/src/util/diff.ts create mode 100644 sources_non_forked/coc.nvim/src/util/errors.ts create mode 100644 sources_non_forked/coc.nvim/src/util/extensions.ts create mode 100644 sources_non_forked/coc.nvim/src/util/factory.ts create mode 100644 sources_non_forked/coc.nvim/src/util/fs.ts create mode 100644 sources_non_forked/coc.nvim/src/util/fuzzy.ts create mode 100644 sources_non_forked/coc.nvim/src/util/fzy.ts create mode 100644 sources_non_forked/coc.nvim/src/util/index.ts create mode 100644 sources_non_forked/coc.nvim/src/util/is.ts create mode 100644 sources_non_forked/coc.nvim/src/util/lodash.ts create mode 100644 sources_non_forked/coc.nvim/src/util/logger.ts create mode 100644 sources_non_forked/coc.nvim/src/util/mutex.ts create mode 100644 sources_non_forked/coc.nvim/src/util/object.ts create mode 100644 sources_non_forked/coc.nvim/src/util/platform.ts create mode 100644 sources_non_forked/coc.nvim/src/util/position.ts create mode 100644 sources_non_forked/coc.nvim/src/util/processes.ts create mode 100644 sources_non_forked/coc.nvim/src/util/score.ts create mode 100644 sources_non_forked/coc.nvim/src/util/string.ts create mode 100644 sources_non_forked/coc.nvim/src/util/textedit.ts create mode 100644 sources_non_forked/coc.nvim/src/window.ts create mode 100644 sources_non_forked/coc.nvim/src/workspace.ts create mode 100644 sources_non_forked/coc.nvim/tsconfig.json create mode 100644 sources_non_forked/coc.nvim/typings/LICENSE create mode 100644 sources_non_forked/coc.nvim/typings/Readme.md create mode 100644 sources_non_forked/coc.nvim/typings/index.d.ts create mode 100644 sources_non_forked/coc.nvim/yarn.lock mode change 100644 => 100755 sources_non_forked/rust.vim/test/run-tests diff --git a/sources_non_forked/coc.nvim/.all-contributorsrc b/sources_non_forked/coc.nvim/.all-contributorsrc new file mode 100644 index 00000000..4a15ee5d --- /dev/null +++ b/sources_non_forked/coc.nvim/.all-contributorsrc @@ -0,0 +1,1853 @@ +{ + "projectName": "coc.nvim", + "projectOwner": "neoclide", + "repoType": "github", + "repoHost": "https://github.com", + "files": [ + "README.md" + ], + "imageSize": 50, + "commit": false, + "commitConvention": "angular", + "contributors": [ + { + "login": "chemzqm", + "name": "Qiming zhao", + "avatar_url": "https://avatars.githubusercontent.com/u/251450?v=4", + "profile": "https://github.com/chemzqm", + "contributions": [ + "code" + ] + }, + { + "login": "fannheyward", + "name": "Heyward Fann", + "avatar_url": "https://avatars.githubusercontent.com/u/345274?v=4", + "profile": "https://fann.im/", + "contributions": [ + "code" + ] + }, + { + "login": "weirongxu", + "name": "Raidou", + "avatar_url": "https://avatars.githubusercontent.com/u/1709861?v=4", + "profile": "https://github.com/weirongxu", + "contributions": [ + "code" + ] + }, + { + "login": "kevinhwang91", + "name": "kevinhwang91", + "avatar_url": "https://avatars.githubusercontent.com/u/17562139?v=4", + "profile": "https://github.com/kevinhwang91", + "contributions": [ + "code" + ] + }, + { + "login": "iamcco", + "name": "年糕小豆汤", + "avatar_url": "https://avatars.githubusercontent.com/u/5492542?v=4", + "profile": "http://yuuko.cn/", + "contributions": [ + "code" + ] + }, + { + "login": "Avi-D-coder", + "name": "Avi Dessauer", + "avatar_url": "https://avatars.githubusercontent.com/u/29133776?v=4", + "profile": "https://github.com/Avi-D-coder", + "contributions": [ + "code" + ] + }, + { + "login": "voldikss", + "name": "最上川", + "avatar_url": "https://avatars.githubusercontent.com/u/20282795?v=4", + "profile": "https://github.com/voldikss", + "contributions": [ + "code" + ] + }, + { + "login": "yatli", + "name": "Yatao Li", + "avatar_url": "https://avatars.githubusercontent.com/u/20684720?v=4", + "profile": "https://www.microsoft.com/en-us/research/people/yatli/", + "contributions": [ + "code" + ] + }, + { + "login": "xiyaowong", + "name": "wongxy", + "avatar_url": "https://avatars.githubusercontent.com/u/47070852?v=4", + "profile": "https://github.com/xiyaowong", + "contributions": [ + "code" + ] + }, + { + "login": "sam-mccall", + "name": "Sam McCall", + "avatar_url": "https://avatars.githubusercontent.com/u/548993?v=4", + "profile": "https://github.com/sam-mccall", + "contributions": [ + "code" + ] + }, + { + "login": "pappasam", + "name": "Samuel Roeca", + "avatar_url": "https://avatars.githubusercontent.com/u/3723671?v=4", + "profile": "https://samroeca.com/pages/about.html#about", + "contributions": [ + "code" + ] + }, + { + "login": "amiralies", + "name": "Amirali Esmaeili", + "avatar_url": "https://avatars.githubusercontent.com/u/13261088?v=4", + "profile": "https://github.com/amiralies", + "contributions": [ + "code" + ] + }, + { + "login": "jrowlingson", + "name": "Jack Rowlingson", + "avatar_url": "https://avatars.githubusercontent.com/u/3051781?v=4", + "profile": "https://bit.ly/3cLKGE4", + "contributions": [ + "code" + ] + }, + { + "login": "tomtomjhj", + "name": "Jaehwang Jung", + "avatar_url": "https://avatars.githubusercontent.com/u/19489738?v=4", + "profile": "https://github.com/tomtomjhj", + "contributions": [ + "code" + ] + }, + { + "login": "antoinemadec", + "name": "Antoine", + "avatar_url": "https://avatars.githubusercontent.com/u/10830594?v=4", + "profile": "https://github.com/antoinemadec", + "contributions": [ + "code" + ] + }, + { + "login": "cosminadrianpopescu", + "name": "Cosmin Popescu", + "avatar_url": "https://avatars.githubusercontent.com/u/5187873?v=4", + "profile": "https://github.com/cosminadrianpopescu", + "contributions": [ + "code" + ] + }, + { + "login": "xuanduc987", + "name": "Duc Nghiem Xuan", + "avatar_url": "https://avatars.githubusercontent.com/u/1186411?v=4", + "profile": "https://ducnx.com/", + "contributions": [ + "code" + ] + }, + { + "login": "oblitum", + "name": "Francisco Lopes", + "avatar_url": "https://avatars.githubusercontent.com/u/1269815?v=4", + "profile": "https://nosubstance.me/", + "contributions": [ + "code" + ] + }, + { + "login": "daquexian", + "name": "daquexian", + "avatar_url": "https://avatars.githubusercontent.com/u/11607199?v=4", + "profile": "https://github.com/daquexian", + "contributions": [ + "code" + ] + }, + { + "login": "dependabot[bot]", + "name": "dependabot[bot]", + "avatar_url": "https://avatars.githubusercontent.com/in/29110?v=4", + "profile": "https://github.com/apps/dependabot", + "contributions": [ + "code" + ] + }, + { + "login": "greenkeeper[bot]", + "name": "greenkeeper[bot]", + "avatar_url": "https://avatars.githubusercontent.com/in/505?v=4", + "profile": "https://github.com/apps/greenkeeper", + "contributions": [ + "code" + ] + }, + { + "login": "ckipp01", + "name": "Chris Kipp", + "avatar_url": "https://avatars.githubusercontent.com/u/13974112?v=4", + "profile": "https://chris-kipp.io/", + "contributions": [ + "code" + ] + }, + { + "login": "dmitmel", + "name": "Dmytro Meleshko", + "avatar_url": "https://avatars.githubusercontent.com/u/15367354?v=4", + "profile": "https://dmitmel.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "kirillbobyrev", + "name": "Kirill Bobyrev", + "avatar_url": "https://avatars.githubusercontent.com/u/3352968?v=4", + "profile": "https://github.com/kirillbobyrev", + "contributions": [ + "code" + ] + }, + { + "login": "gbcreation", + "name": "Gontran Baerts", + "avatar_url": "https://avatars.githubusercontent.com/u/454315?v=4", + "profile": "https://github.com/gbcreation", + "contributions": [ + "code" + ] + }, + { + "login": "andys8", + "name": "Andy", + "avatar_url": "https://avatars.githubusercontent.com/u/13085980?v=4", + "profile": "https://andys8.de/", + "contributions": [ + "code" + ] + }, + { + "login": "GopherJ", + "name": "Cheng JIANG", + "avatar_url": "https://avatars.githubusercontent.com/u/33961674?v=4", + "profile": "https://www.alexcj96.com/", + "contributions": [ + "code" + ] + }, + { + "login": "cpearce-py", + "name": "Corin", + "avatar_url": "https://avatars.githubusercontent.com/u/53532946?v=4", + "profile": "https://github.com/cpearce-py", + "contributions": [ + "code" + ] + }, + { + "login": "wodesuck", + "name": "Daniel Zhang", + "avatar_url": "https://avatars.githubusercontent.com/u/3124581?v=4", + "profile": "https://github.com/wodesuck", + "contributions": [ + "code" + ] + }, + { + "login": "Ferdi265", + "name": "Ferdinand Bachmann", + "avatar_url": "https://avatars.githubusercontent.com/u/4077106?v=4", + "profile": "https://github.com/Ferdi265", + "contributions": [ + "code" + ] + }, + { + "login": "gou4shi1", + "name": "Guangqing Chen", + "avatar_url": "https://avatars.githubusercontent.com/u/16915589?v=4", + "profile": "https://goushi.me/", + "contributions": [ + "code" + ] + }, + { + "login": "iamruinous", + "name": "Jade Meskill", + "avatar_url": "https://avatars.githubusercontent.com/u/2108?v=4", + "profile": "http://jademeskill.com/", + "contributions": [ + "code" + ] + }, + { + "login": "jpoppe", + "name": "Jasper Poppe", + "avatar_url": "https://avatars.githubusercontent.com/u/65505?v=4", + "profile": "https://github.com/jpoppe", + "contributions": [ + "code" + ] + }, + { + "login": "jean", + "name": "Jean Jordaan", + "avatar_url": "https://avatars.githubusercontent.com/u/84800?v=4", + "profile": "https://github.com/jean", + "contributions": [ + "code" + ] + }, + { + "login": "kidonng", + "name": "Kid", + "avatar_url": "https://avatars.githubusercontent.com/u/44045911?v=4", + "profile": "https://xuann.wang/", + "contributions": [ + "code" + ] + }, + { + "login": "Kavantix", + "name": "Pieter van Loon", + "avatar_url": "https://avatars.githubusercontent.com/u/6243755?v=4", + "profile": "https://github.com/Kavantix", + "contributions": [ + "code" + ] + }, + { + "login": "rliebz", + "name": "Robert Liebowitz", + "avatar_url": "https://avatars.githubusercontent.com/u/5321575?v=4", + "profile": "https://github.com/rliebz", + "contributions": [ + "code" + ] + }, + { + "login": "megalithic", + "name": "Seth Messer", + "avatar_url": "https://avatars.githubusercontent.com/u/3678?v=4", + "profile": "https://megalithic.io/", + "contributions": [ + "code" + ] + }, + { + "login": "UncleBill", + "name": "UncleBill", + "avatar_url": "https://avatars.githubusercontent.com/u/1141198?v=4", + "profile": "https://github.com/UncleBill", + "contributions": [ + "code" + ] + }, + { + "login": "ZSaberLv0", + "name": "ZERO", + "avatar_url": "https://avatars.githubusercontent.com/u/6846867?v=4", + "profile": "http://zsaber.com/", + "contributions": [ + "code" + ] + }, + { + "login": "fsouza", + "name": "fsouza", + "avatar_url": "https://avatars.githubusercontent.com/u/108725?v=4", + "profile": "https://fsouza.blog/", + "contributions": [ + "code" + ] + }, + { + "login": "onichandame", + "name": "XiaoZhang", + "avatar_url": "https://avatars.githubusercontent.com/u/23728505?v=4", + "profile": "https://onichandame.com/", + "contributions": [ + "code" + ] + }, + { + "login": "whyreal", + "name": "whyreal", + "avatar_url": "https://avatars.githubusercontent.com/u/2084642?v=4", + "profile": "https://github.com/whyreal", + "contributions": [ + "code" + ] + }, + { + "login": "yehuohan", + "name": "yehuohan", + "avatar_url": "https://avatars.githubusercontent.com/u/17680752?v=4", + "profile": "https://github.com/yehuohan", + "contributions": [ + "code" + ] + }, + { + "login": "Bakudankun", + "name": "バクダンくん", + "avatar_url": "https://avatars.githubusercontent.com/u/4504807?v=4", + "profile": "http://www.bakudan.farm/", + "contributions": [ + "code" + ] + }, + { + "login": "glepnir", + "name": "Raphael", + "avatar_url": "https://avatars.githubusercontent.com/u/41671631?v=4", + "profile": "https://blog.gopherhub.org/", + "contributions": [ + "code" + ] + }, + { + "login": "tbodt", + "name": "tbodt", + "avatar_url": "https://avatars.githubusercontent.com/u/5678977?v=4", + "profile": "https://tbodt.com/", + "contributions": [ + "code" + ] + }, + { + "login": "aaronmcdaid", + "name": "Aaron McDaid", + "avatar_url": "https://avatars.githubusercontent.com/u/64350?v=4", + "profile": "https://aaronmcdaid.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "versi786", + "name": "Aasif Versi", + "avatar_url": "https://avatars.githubusercontent.com/u/7347942?v=4", + "profile": "https://github.com/versi786", + "contributions": [ + "code" + ] + }, + { + "login": "abnerf", + "name": "Abner Silva", + "avatar_url": "https://avatars.githubusercontent.com/u/56300?v=4", + "profile": "https://github.com/abnerf", + "contributions": [ + "code" + ] + }, + { + "login": "sheerun", + "name": "Adam Stankiewicz", + "avatar_url": "https://avatars.githubusercontent.com/u/292365?v=4", + "profile": "http://sheerun.net/", + "contributions": [ + "code" + ] + }, + { + "login": "adamansky", + "name": "Adamansky Anton", + "avatar_url": "https://avatars.githubusercontent.com/u/496683?v=4", + "profile": "https://wirow.io/", + "contributions": [ + "code" + ] + }, + { + "login": "ahmedelgabri", + "name": "Ahmed El Gabri", + "avatar_url": "https://avatars.githubusercontent.com/u/63876?v=4", + "profile": "https://gabri.me/", + "contributions": [ + "code" + ] + }, + { + "login": "theg4sh", + "name": "Alexandr Kondratev", + "avatar_url": "https://avatars.githubusercontent.com/u/5094691?v=4", + "profile": "http://theg4sh.ru/", + "contributions": [ + "code" + ] + }, + { + "login": "andrewkshim", + "name": "Andrew Shim", + "avatar_url": "https://avatars.githubusercontent.com/u/1403410?v=4", + "profile": "https://github.com/andrewkshim", + "contributions": [ + "code" + ] + }, + { + "login": "alindeman", + "name": "Andy Lindeman", + "avatar_url": "https://avatars.githubusercontent.com/u/395621?v=4", + "profile": "http://andylindeman.com/", + "contributions": [ + "code" + ] + }, + { + "login": "Augustin82", + "name": "Augustin", + "avatar_url": "https://avatars.githubusercontent.com/u/2370810?v=4", + "profile": "https://github.com/Augustin82", + "contributions": [ + "code" + ] + }, + { + "login": "Eijebong", + "name": "Bastien Orivel", + "avatar_url": "https://avatars.githubusercontent.com/u/3650385?v=4", + "profile": "https://bananium.fr/", + "contributions": [ + "code" + ] + }, + { + "login": "ayroblu", + "name": "Ben Lu", + "avatar_url": "https://avatars.githubusercontent.com/u/4915682?v=4", + "profile": "https://github.com/ayroblu", + "contributions": [ + "code" + ] + }, + { + "login": "vantreeseba", + "name": "Ben", + "avatar_url": "https://avatars.githubusercontent.com/u/316782?v=4", + "profile": "https://github.com/vantreeseba", + "contributions": [ + "code" + ] + }, + { + "login": "bmon", + "name": "Brendan Roy", + "avatar_url": "https://avatars.githubusercontent.com/u/2115272?v=4", + "profile": "https://github.com/bmon", + "contributions": [ + "code" + ] + }, + { + "login": "brianembry", + "name": "brianembry", + "avatar_url": "https://avatars.githubusercontent.com/u/35347666?v=4", + "profile": "https://github.com/brianembry", + "contributions": [ + "code" + ] + }, + { + "login": "b-", + "name": "br", + "avatar_url": "https://avatars.githubusercontent.com/u/284789?v=4", + "profile": "https://keybase.io/bri_", + "contributions": [ + "code" + ] + }, + { + "login": "casonadams", + "name": "Cason Adams", + "avatar_url": "https://avatars.githubusercontent.com/u/17597548?v=4", + "profile": "https://github.com/casonadams", + "contributions": [ + "code" + ] + }, + { + "login": "y9c", + "name": "Chang Y", + "avatar_url": "https://avatars.githubusercontent.com/u/5415510?v=4", + "profile": "https://github.com/y9c", + "contributions": [ + "code" + ] + }, + { + "login": "yous", + "name": "Chayoung You", + "avatar_url": "https://avatars.githubusercontent.com/u/853977?v=4", + "profile": "https://yous.be/", + "contributions": [ + "code" + ] + }, + { + "login": "chenlijun99", + "name": "Chen Lijun", + "avatar_url": "https://avatars.githubusercontent.com/u/20483759?v=4", + "profile": "https://github.com/chenlijun99", + "contributions": [ + "code" + ] + }, + { + "login": "beeender", + "name": "Chen Mulong", + "avatar_url": "https://avatars.githubusercontent.com/u/449296?v=4", + "profile": "https://github.com/beeender", + "contributions": [ + "code" + ] + }, + { + "login": "rsrchboy", + "name": "Chris Weyl", + "avatar_url": "https://avatars.githubusercontent.com/u/59620?v=4", + "profile": "http://weyl.io/", + "contributions": [ + "code" + ] + }, + { + "login": "dezza", + "name": "dezza", + "avatar_url": "https://avatars.githubusercontent.com/u/402927?v=4", + "profile": "https://github.com/dezza", + "contributions": [ + "code" + ] + }, + { + "login": "ceedubs", + "name": "Cody Allen", + "avatar_url": "https://avatars.githubusercontent.com/u/977929?v=4", + "profile": "https://github.com/ceedubs", + "contributions": [ + "code" + ] + }, + { + "login": "pyrho", + "name": "Damien Rajon", + "avatar_url": "https://avatars.githubusercontent.com/u/145502?v=4", + "profile": "https://www.25.wf/", + "contributions": [ + "code" + ] + }, + { + "login": "daern91", + "name": "Daniel Eriksson", + "avatar_url": "https://avatars.githubusercontent.com/u/6084427?v=4", + "profile": "https://github.com/daern91", + "contributions": [ + "code" + ] + }, + { + "login": "danjenson", + "name": "Daniel Jenson", + "avatar_url": "https://avatars.githubusercontent.com/u/4793438?v=4", + "profile": "https://github.com/danjenson", + "contributions": [ + "code" + ] + }, + { + "login": "davidmh", + "name": "David Mejorado", + "avatar_url": "https://avatars.githubusercontent.com/u/594302?v=4", + "profile": "https://github.com/davidmh", + "contributions": [ + "code" + ] + }, + { + "login": "pderichai", + "name": "Deric Pang", + "avatar_url": "https://avatars.githubusercontent.com/u/13430946?v=4", + "profile": "https://github.com/pderichai", + "contributions": [ + "code" + ] + }, + { + "login": "miyatsu", + "name": "Ding Tao", + "avatar_url": "https://avatars.githubusercontent.com/u/12852587?v=4", + "profile": "https://www.dingtao.org/blog", + "contributions": [ + "code" + ] + }, + { + "login": "doronbehar", + "name": "Doron Behar", + "avatar_url": "https://avatars.githubusercontent.com/u/10998835?v=4", + "profile": "https://github.com/doronbehar", + "contributions": [ + "code" + ] + }, + { + "login": "kovetskiy", + "name": "Egor Kovetskiy", + "avatar_url": "https://avatars.githubusercontent.com/u/8445924?v=4", + "profile": "https://github.com/kovetskiy", + "contributions": [ + "code" + ] + }, + { + "login": "elkowar", + "name": "ElKowar", + "avatar_url": "https://avatars.githubusercontent.com/u/5300871?v=4", + "profile": "https://github.com/elkowar", + "contributions": [ + "code" + ] + }, + { + "login": "demelev", + "name": "Emeliov Dmitrii", + "avatar_url": "https://avatars.githubusercontent.com/u/3952209?v=4", + "profile": "https://github.com/demelev", + "contributions": [ + "code" + ] + }, + { + "login": "sawmurai", + "name": "Fabian Becker", + "avatar_url": "https://avatars.githubusercontent.com/u/6454986?v=4", + "profile": "https://github.com/sawmurai", + "contributions": [ + "code" + ] + }, + { + "login": "FallenWarrior2k", + "name": "FallenWarrior2k", + "avatar_url": "https://avatars.githubusercontent.com/u/20320149?v=4", + "profile": "https://github.com/FallenWarrior2k", + "contributions": [ + "code" + ] + }, + { + "login": "fnune", + "name": "Fausto Núñez Alberro", + "avatar_url": "https://avatars.githubusercontent.com/u/16181067?v=4", + "profile": "https://fnune.com/", + "contributions": [ + "code" + ] + }, + { + "login": "FelipeCRamos", + "name": "Felipe Ramos", + "avatar_url": "https://avatars.githubusercontent.com/u/7572843?v=4", + "profile": "https://github.com/FelipeCRamos", + "contributions": [ + "code" + ] + }, + { + "login": "frbor", + "name": "Fredrik Borg", + "avatar_url": "https://avatars.githubusercontent.com/u/2320183?v=4", + "profile": "https://github.com/frbor", + "contributions": [ + "code" + ] + }, + { + "login": "gavsim", + "name": "Gavin Sim", + "avatar_url": "https://avatars.githubusercontent.com/u/812273?v=4", + "profile": "http://www.gavinsim.co.uk/", + "contributions": [ + "code" + ] + }, + { + "login": "gibfahn", + "name": "Gibson Fahnestock", + "avatar_url": "https://avatars.githubusercontent.com/u/15943089?v=4", + "profile": "https://fahn.co/", + "contributions": [ + "code" + ] + }, + { + "login": "giovannigiordano", + "name": "Giovanni Giordano", + "avatar_url": "https://avatars.githubusercontent.com/u/15145952?v=4", + "profile": "https://github.com/giovannigiordano", + "contributions": [ + "code" + ] + }, + { + "login": "qubbit", + "name": "Gopal Adhikari", + "avatar_url": "https://avatars.githubusercontent.com/u/1987473?v=4", + "profile": "https://github.com/qubbit", + "contributions": [ + "code" + ] + }, + { + "login": "hanh090", + "name": "Hanh Le", + "avatar_url": "https://avatars.githubusercontent.com/u/3643657?v=4", + "profile": "https://github.com/hanh090", + "contributions": [ + "code" + ] + }, + { + "login": "hedyhli", + "name": "hedy", + "avatar_url": "https://avatars.githubusercontent.com/u/50042066?v=4", + "profile": "https://github.com/hedyhli", + "contributions": [ + "code" + ] + }, + { + "login": "hendriklammers", + "name": "Hendrik Lammers", + "avatar_url": "https://avatars.githubusercontent.com/u/754556?v=4", + "profile": "https://www.hendriklammers.com/", + "contributions": [ + "code" + ] + }, + { + "login": "henrybarreto", + "name": "Henry Barreto", + "avatar_url": "https://avatars.githubusercontent.com/u/23109089?v=4", + "profile": "https://github.com/henrybarreto", + "contributions": [ + "code" + ] + }, + { + "login": "WhyNotHugo", + "name": "Hugo", + "avatar_url": "https://avatars.githubusercontent.com/u/730811?v=4", + "profile": "https://hugo.barrera.io/", + "contributions": [ + "code" + ] + }, + { + "login": "jackieli-tes", + "name": "Jackie Li", + "avatar_url": "https://avatars.githubusercontent.com/u/64778297?v=4", + "profile": "https://github.com/jackieli-tes", + "contributions": [ + "code" + ] + }, + { + "login": "MrQubo", + "name": "Jakub Nowak", + "avatar_url": "https://avatars.githubusercontent.com/u/16545322?v=4", + "profile": "https://github.com/MrQubo", + "contributions": [ + "code" + ] + }, + { + "login": "euoia", + "name": "James Pickard", + "avatar_url": "https://avatars.githubusercontent.com/u/1271216?v=4", + "profile": "https://github.com/euoia", + "contributions": [ + "code" + ] + }, + { + "login": "jsfaint", + "name": "Jia Sui", + "avatar_url": "https://avatars.githubusercontent.com/u/571829?v=4", + "profile": "https://github.com/jsfaint", + "contributions": [ + "code" + ] + }, + { + "login": "expipiplus1", + "name": "Ellie Hermaszewska", + "avatar_url": "https://avatars.githubusercontent.com/u/857308?v=4", + "profile": "https://github.com/expipiplus1", + "contributions": [ + "code" + ] + }, + { + "login": "cincodenada", + "name": "Joel Bradshaw", + "avatar_url": "https://avatars.githubusercontent.com/u/479715?v=4", + "profile": "https://cincodenada.com/", + "contributions": [ + "code" + ] + }, + { + "login": "irizwaririz", + "name": "John Carlo Roberto", + "avatar_url": "https://avatars.githubusercontent.com/u/10111643?v=4", + "profile": "https://github.com/irizwaririz", + "contributions": [ + "code" + ] + }, + { + "login": "Jomik", + "name": "Jonas Holst Damtoft", + "avatar_url": "https://avatars.githubusercontent.com/u/699655?v=4", + "profile": "https://github.com/Jomik", + "contributions": [ + "code" + ] + }, + { + "login": "jdlehman", + "name": "Jonathan Lehman", + "avatar_url": "https://avatars.githubusercontent.com/u/3144695?v=4", + "profile": "http://inlehmansterms.net/", + "contributions": [ + "code" + ] + }, + { + "login": "JoosepAlviste", + "name": "Joosep Alviste", + "avatar_url": "https://avatars.githubusercontent.com/u/9450943?v=4", + "profile": "https://joosep.xyz/", + "contributions": [ + "code" + ] + }, + { + "login": "josa42", + "name": "Josa Gesell", + "avatar_url": "https://avatars.githubusercontent.com/u/423234?v=4", + "profile": "https://github.com/josa42", + "contributions": [ + "code" + ] + }, + { + "login": "joshuarubin", + "name": "Joshua Rubin", + "avatar_url": "https://avatars.githubusercontent.com/u/194275?v=4", + "profile": "https://jawa.dev/", + "contributions": [ + "code" + ] + }, + { + "login": "perrin4869", + "name": "Julian Grinblat", + "avatar_url": "https://avatars.githubusercontent.com/u/5774716?v=4", + "profile": "https://github.com/perrin4869", + "contributions": [ + "code" + ] + }, + { + "login": "valentjn", + "name": "Julian Valentin", + "avatar_url": "https://avatars.githubusercontent.com/u/19839841?v=4", + "profile": "https://valentjn.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "KabbAmine", + "name": "KabbAmine", + "avatar_url": "https://avatars.githubusercontent.com/u/5658084?v=4", + "profile": "https://kabbamine.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "acro5piano", + "name": "Kay Gosho", + "avatar_url": "https://avatars.githubusercontent.com/u/10719495?v=4", + "profile": "https://moncargo.io/", + "contributions": [ + "code" + ] + }, + { + "login": "hkennyv", + "name": "Kenny Huynh", + "avatar_url": "https://avatars.githubusercontent.com/u/29909203?v=4", + "profile": "https://kennyvh.com/", + "contributions": [ + "code" + ] + }, + { + "login": "kevinrambaud", + "name": "Kevin Rambaud", + "avatar_url": "https://avatars.githubusercontent.com/u/7501477?v=4", + "profile": "https://github.com/kevinrambaud", + "contributions": [ + "code" + ] + }, + { + "login": "kiancross", + "name": "Kian Cross", + "avatar_url": "https://avatars.githubusercontent.com/u/11011464?v=4", + "profile": "https://github.com/kiancross", + "contributions": [ + "code" + ] + }, + { + "login": "kristijanhusak", + "name": "Kristijan Husak", + "avatar_url": "https://avatars.githubusercontent.com/u/1782860?v=4", + "profile": "https://ko-fi.com/kristijanhusak", + "contributions": [ + "code" + ] + }, + { + "login": "NullVoxPopuli", + "name": "NullVoxPopuli", + "avatar_url": "https://avatars.githubusercontent.com/u/199018?v=4", + "profile": "https://github.com/NullVoxPopuli", + "contributions": [ + "code" + ] + }, + { + "login": "lassepe", + "name": "Lasse Peters", + "avatar_url": "https://avatars.githubusercontent.com/u/10076790?v=4", + "profile": "https://github.com/lassepe", + "contributions": [ + "code" + ] + }, + { + "login": "Linerre", + "name": "Noel Errenil", + "avatar_url": "https://avatars.githubusercontent.com/u/49512984?v=4", + "profile": "https://github.com/Linerre", + "contributions": [ + "code" + ] + }, + { + "login": "LinArcX", + "name": "LinArcX", + "avatar_url": "https://avatars.githubusercontent.com/u/10884422?v=4", + "profile": "https://github.com/LinArcX", + "contributions": [ + "code" + ] + }, + { + "login": "liuchengxu", + "name": "Liu-Cheng Xu", + "avatar_url": "https://avatars.githubusercontent.com/u/8850248?v=4", + "profile": "https://paypal.me/liuchengxu", + "contributions": [ + "code" + ] + }, + { + "login": "foxtrot", + "name": "Marc", + "avatar_url": "https://avatars.githubusercontent.com/u/4153572?v=4", + "profile": "https://malloc.me/", + "contributions": [ + "code" + ] + }, + { + "login": "mgaw", + "name": "Marius Gawrisch", + "avatar_url": "https://avatars.githubusercontent.com/u/2177016?v=4", + "profile": "https://github.com/mgaw", + "contributions": [ + "code" + ] + }, + { + "login": "mhintz", + "name": "Mark Hintz", + "avatar_url": "https://avatars.githubusercontent.com/u/2789742?v=4", + "profile": "http://www.markhz.com/", + "contributions": [ + "code" + ] + }, + { + "login": "MatElGran", + "name": "Mathieu Le Tiec", + "avatar_url": "https://avatars.githubusercontent.com/u/1052778?v=4", + "profile": "https://github.com/MatElGran", + "contributions": [ + "code" + ] + }, + { + "login": "matt-fff", + "name": "Matt White", + "avatar_url": "https://avatars.githubusercontent.com/u/8656127?v=4", + "profile": "https://matt-w.net/", + "contributions": [ + "code" + ] + }, + { + "login": "ml-evs", + "name": "Matthew Evans", + "avatar_url": "https://avatars.githubusercontent.com/u/7916000?v=4", + "profile": "https://github.com/ml-evs", + "contributions": [ + "code" + ] + }, + { + "login": "Me1onRind", + "name": "Me1onRind", + "avatar_url": "https://avatars.githubusercontent.com/u/19531270?v=4", + "profile": "https://github.com/Me1onRind", + "contributions": [ + "code" + ] + }, + { + "login": "Qyriad", + "name": "Qyriad", + "avatar_url": "https://avatars.githubusercontent.com/u/1542224?v=4", + "profile": "https://github.com/Qyriad", + "contributions": [ + "code" + ] + }, + { + "login": "leonardssh", + "name": "Narcis B.", + "avatar_url": "https://avatars.githubusercontent.com/u/35312043?v=4", + "profile": "https://leo.is-a.dev/", + "contributions": [ + "code" + ] + }, + { + "login": "Neur1n", + "name": "Neur1n", + "avatar_url": "https://avatars.githubusercontent.com/u/17579247?v=4", + "profile": "https://github.com/Neur1n", + "contributions": [ + "code" + ] + }, + { + "login": "nicoder", + "name": "Nicolas Dermine", + "avatar_url": "https://avatars.githubusercontent.com/u/365210?v=4", + "profile": "https://github.com/nicoder", + "contributions": [ + "code" + ] + }, + { + "login": "NoahTheDuke", + "name": "Noah", + "avatar_url": "https://avatars.githubusercontent.com/u/603677?v=4", + "profile": "https://github.com/NoahTheDuke", + "contributions": [ + "code" + ] + }, + { + "login": "IndexXuan", + "name": "PENG Rui", + "avatar_url": "https://avatars.githubusercontent.com/u/6322673?v=4", + "profile": "https://github.com/IndexXuan", + "contributions": [ + "code" + ] + }, + { + "login": "paco0x", + "name": "Paco", + "avatar_url": "https://avatars.githubusercontent.com/u/6123425?v=4", + "profile": "https://liaoph.com/", + "contributions": [ + "code" + ] + }, + { + "login": "peng1999", + "name": "Peng Guanwen", + "avatar_url": "https://avatars.githubusercontent.com/u/12483662?v=4", + "profile": "https://github.com/peng1999", + "contributions": [ + "code" + ] + }, + { + "login": "ilAYAli", + "name": "Petter Wahlman", + "avatar_url": "https://avatars.githubusercontent.com/u/1106732?v=4", + "profile": "https://www.twitter.com/badeip", + "contributions": [ + "code" + ] + }, + { + "login": "pvonmoradi", + "name": "Pooya Moradi", + "avatar_url": "https://avatars.githubusercontent.com/u/1058151?v=4", + "profile": "https://github.com/pvonmoradi", + "contributions": [ + "code" + ] + }, + { + "login": "QuadeMorrison", + "name": "Quade Morrison", + "avatar_url": "https://avatars.githubusercontent.com/u/10917383?v=4", + "profile": "https://github.com/QuadeMorrison", + "contributions": [ + "code" + ] + }, + { + "login": "vogler", + "name": "Ralf Vogler", + "avatar_url": "https://avatars.githubusercontent.com/u/493741?v=4", + "profile": "https://github.com/vogler", + "contributions": [ + "code" + ] + }, + { + "login": "crccw", + "name": "Ran Chen", + "avatar_url": "https://avatars.githubusercontent.com/u/41463?v=4", + "profile": "https://github.com/crccw", + "contributions": [ + "code" + ] + }, + { + "login": "bigardone", + "name": "Ricardo García Vega", + "avatar_url": "https://avatars.githubusercontent.com/u/1090272?v=4", + "profile": "https://bigardone.dev/", + "contributions": [ + "code" + ] + }, + { + "login": "nomasprime", + "name": "Rick Jones", + "avatar_url": "https://avatars.githubusercontent.com/u/140855?v=4", + "profile": "https://github.com/nomasprime", + "contributions": [ + "code" + ] + }, + { + "login": "rschristian", + "name": "Ryan Christian", + "avatar_url": "https://avatars.githubusercontent.com/u/33403762?v=4", + "profile": "https://github.com/rschristian", + "contributions": [ + "code" + ] + }, + { + "login": "winterbesos", + "name": "Salo", + "avatar_url": "https://avatars.githubusercontent.com/u/4694263?v=4", + "profile": "http://salo.so/", + "contributions": [ + "code" + ] + }, + { + "login": "Hazelfire", + "name": "Sam Nolan", + "avatar_url": "https://avatars.githubusercontent.com/u/13807753?v=4", + "profile": "https://github.com/Hazelfire", + "contributions": [ + "code" + ] + }, + { + "login": "rickysaurav", + "name": "Saurav", + "avatar_url": "https://avatars.githubusercontent.com/u/13986039?v=4", + "profile": "https://github.com/rickysaurav", + "contributions": [ + "code" + ] + }, + { + "login": "smackesey", + "name": "Sean Mackesey", + "avatar_url": "https://avatars.githubusercontent.com/u/1531373?v=4", + "profile": "https://github.com/smackesey", + "contributions": [ + "code" + ] + }, + { + "login": "sheeldotme", + "name": "Sheel Patel", + "avatar_url": "https://avatars.githubusercontent.com/u/6991406?v=4", + "profile": "https://github.com/sheeldotme", + "contributions": [ + "code" + ] + }, + { + "login": "solomonwzs", + "name": "Solomon Ng", + "avatar_url": "https://avatars.githubusercontent.com/u/907942?v=4", + "profile": "https://github.com/solomonwzs", + "contributions": [ + "code" + ] + }, + { + "login": "kadimisetty", + "name": "Sri Kadimisetty", + "avatar_url": "https://avatars.githubusercontent.com/u/535947?v=4", + "profile": "https://github.com/kadimisetty", + "contributions": [ + "code" + ] + }, + { + "login": "stephenprater", + "name": "Stephen Prater", + "avatar_url": "https://avatars.githubusercontent.com/u/149870?v=4", + "profile": "https://github.com/stephenprater", + "contributions": [ + "code" + ] + }, + { + "login": "kibs", + "name": "Sune Kibsgaard", + "avatar_url": "https://avatars.githubusercontent.com/u/14085?v=4", + "profile": "https://kibs.dk/", + "contributions": [ + "code" + ] + }, + { + "login": "Aquaakuma", + "name": "Aquaakuma", + "avatar_url": "https://avatars.githubusercontent.com/u/31891793?v=4", + "profile": "https://github.com/Aquaakuma", + "contributions": [ + "code" + ] + }, + { + "login": "coil398", + "name": "Takumi Kawase", + "avatar_url": "https://avatars.githubusercontent.com/u/7694377?v=4", + "profile": "https://github.com/coil398", + "contributions": [ + "code" + ] + }, + { + "login": "theblobscp", + "name": "The Blob SCP", + "avatar_url": "https://avatars.githubusercontent.com/u/81673375?v=4", + "profile": "https://github.com/theblobscp", + "contributions": [ + "code" + ] + }, + { + "login": "przepompownia", + "name": "Tomasz N", + "avatar_url": "https://avatars.githubusercontent.com/u/11404453?v=4", + "profile": "https://github.com/przepompownia", + "contributions": [ + "code" + ] + }, + { + "login": "gasuketsu", + "name": "Tomoyuki Harada", + "avatar_url": "https://avatars.githubusercontent.com/u/15703757?v=4", + "profile": "https://github.com/gasuketsu", + "contributions": [ + "code" + ] + }, + { + "login": "tonyfettes", + "name": "Tony Fettes", + "avatar_url": "https://avatars.githubusercontent.com/u/29998228?v=4", + "profile": "https://github.com/tonyfettes", + "contributions": [ + "code" + ] + }, + { + "login": "tony", + "name": "Tony Narlock", + "avatar_url": "https://avatars.githubusercontent.com/u/26336?v=4", + "profile": "https://www.git-pull.com/", + "contributions": [ + "code" + ] + }, + { + "login": "wwwjfy", + "name": "Tony Wang", + "avatar_url": "https://avatars.githubusercontent.com/u/126527?v=4", + "profile": "https://blog.wwwjfy.net/", + "contributions": [ + "code" + ] + }, + { + "login": "Varal7", + "name": "Victor Quach", + "avatar_url": "https://avatars.githubusercontent.com/u/8019486?v=4", + "profile": "https://github.com/Varal7", + "contributions": [ + "code" + ] + }, + { + "login": "whisperity", + "name": "Whisperity", + "avatar_url": "https://avatars.githubusercontent.com/u/1969470?v=4", + "profile": "https://github.com/whisperity", + "contributions": [ + "code" + ] + }, + { + "login": "willtrnr", + "name": "William Turner", + "avatar_url": "https://avatars.githubusercontent.com/u/1878110?v=4", + "profile": "https://github.com/willtrnr", + "contributions": [ + "code" + ] + }, + { + "login": "damnever", + "name": "Xiaochao Dong", + "avatar_url": "https://avatars.githubusercontent.com/u/6223594?v=4", + "profile": "https://drafts.damnever.com/", + "contributions": [ + "code" + ] + }, + { + "login": "hyhugh", + "name": "Hugh Hou", + "avatar_url": "https://avatars.githubusercontent.com/u/16500351?v=4", + "profile": "https://github.com/hyhugh", + "contributions": [ + "code" + ] + }, + { + "login": "jackielii", + "name": "Jackie Li", + "avatar_url": "https://avatars.githubusercontent.com/u/360983?v=4", + "profile": "https://github.com/jackielii", + "contributions": [ + "code" + ] + }, + { + "login": "TheConfuZzledDude", + "name": "Zachary Freed", + "avatar_url": "https://avatars.githubusercontent.com/u/3160203?v=4", + "profile": "https://github.com/TheConfuZzledDude", + "contributions": [ + "code" + ] + }, + { + "login": "akiyosi", + "name": "akiyosi", + "avatar_url": "https://avatars.githubusercontent.com/u/8478977?v=4", + "profile": "https://github.com/akiyosi", + "contributions": [ + "code" + ] + }, + { + "login": "alexjg", + "name": "alexjg", + "avatar_url": "https://avatars.githubusercontent.com/u/224635?v=4", + "profile": "https://github.com/alexjg", + "contributions": [ + "code" + ] + }, + { + "login": "aste4", + "name": "aste4", + "avatar_url": "https://avatars.githubusercontent.com/u/47511385?v=4", + "profile": "https://github.com/aste4", + "contributions": [ + "code" + ] + }, + { + "login": "clyfish", + "name": "clyfish", + "avatar_url": "https://avatars.githubusercontent.com/u/541215?v=4", + "profile": "https://github.com/clyfish", + "contributions": [ + "code" + ] + }, + { + "login": "dev7ba", + "name": "dev7ba", + "avatar_url": "https://avatars.githubusercontent.com/u/93706552?v=4", + "profile": "https://github.com/dev7ba", + "contributions": [ + "code" + ] + }, + { + "login": "diartyz", + "name": "diartyz", + "avatar_url": "https://avatars.githubusercontent.com/u/4486152?v=4", + "profile": "https://github.com/diartyz", + "contributions": [ + "code" + ] + }, + { + "login": "doza-daniel", + "name": "doza-daniel", + "avatar_url": "https://avatars.githubusercontent.com/u/13752683?v=4", + "profile": "https://github.com/doza-daniel", + "contributions": [ + "code" + ] + }, + { + "login": "equal-l2", + "name": "equal-l2", + "avatar_url": "https://avatars.githubusercontent.com/u/8597717?v=4", + "profile": "https://github.com/equal-l2", + "contributions": [ + "code" + ] + }, + { + "login": "FongHou", + "name": "fong", + "avatar_url": "https://avatars.githubusercontent.com/u/13973254?v=4", + "profile": "https://github.com/FongHou", + "contributions": [ + "code" + ] + }, + { + "login": "hexh250786313", + "name": "hexh", + "avatar_url": "https://avatars.githubusercontent.com/u/26080416?v=4", + "profile": "https://blog.hexuhua.vercel.app/", + "contributions": [ + "code" + ] + }, + { + "login": "hhiraba", + "name": "hhiraba", + "avatar_url": "https://avatars.githubusercontent.com/u/4624806?v=4", + "profile": "https://github.com/hhiraba", + "contributions": [ + "code" + ] + }, + { + "login": "ic-768", + "name": "ic-768", + "avatar_url": "https://avatars.githubusercontent.com/u/83115125?v=4", + "profile": "https://github.com/ic-768", + "contributions": [ + "code" + ] + }, + { + "login": "javiertury", + "name": "javiertury", + "avatar_url": "https://avatars.githubusercontent.com/u/1520320?v=4", + "profile": "https://github.com/javiertury", + "contributions": [ + "code" + ] + }, + { + "login": "seiyeah78", + "name": "karasu", + "avatar_url": "https://avatars.githubusercontent.com/u/6185139?v=4", + "profile": "https://github.com/seiyeah78", + "contributions": [ + "code" + ] + }, + { + "login": "kevineato", + "name": "kevineato", + "avatar_url": "https://avatars.githubusercontent.com/u/13666221?v=4", + "profile": "https://github.com/kevineato", + "contributions": [ + "code" + ] + }, + { + "login": "m4c0", + "name": "Eduardo Costa", + "avatar_url": "https://avatars.githubusercontent.com/u/1664510?v=4", + "profile": "https://github.com/m4c0", + "contributions": [ + "code" + ] + }, + { + "login": "micchy326", + "name": "micchy326", + "avatar_url": "https://avatars.githubusercontent.com/u/23257067?v=4", + "profile": "https://github.com/micchy326", + "contributions": [ + "code" + ] + }, + { + "login": "midchildan", + "name": "midchildan", + "avatar_url": "https://avatars.githubusercontent.com/u/7343721?v=4", + "profile": "https://keybase.io/midchildan", + "contributions": [ + "code" + ] + }, + { + "login": "minefuto", + "name": "minefuto", + "avatar_url": "https://avatars.githubusercontent.com/u/46558834?v=4", + "profile": "https://github.com/minefuto", + "contributions": [ + "code" + ] + }, + { + "login": "miyanokomiya", + "name": "miyanokomiya", + "avatar_url": "https://avatars.githubusercontent.com/u/20733354?v=4", + "profile": "https://twitter.com/robokomy", + "contributions": [ + "code" + ] + }, + { + "login": "miyaviee", + "name": "miyaviee", + "avatar_url": "https://avatars.githubusercontent.com/u/15247561?v=4", + "profile": "https://github.com/miyaviee", + "contributions": [ + "code" + ] + }, + { + "login": "monkoose", + "name": "monkoose", + "avatar_url": "https://avatars.githubusercontent.com/u/6261276?v=4", + "profile": "https://github.com/monkoose", + "contributions": [ + "code", + "bug" + ] + }, + { + "login": "mujx", + "name": "mujx", + "avatar_url": "https://avatars.githubusercontent.com/u/6430350?v=4", + "profile": "https://github.com/mujx", + "contributions": [ + "code" + ] + }, + { + "login": "mvilim", + "name": "mvilim", + "avatar_url": "https://avatars.githubusercontent.com/u/40682862?v=4", + "profile": "https://github.com/mvilim", + "contributions": [ + "code" + ] + }, + { + "login": "naruaway", + "name": "naruaway", + "avatar_url": "https://avatars.githubusercontent.com/u/2931577?v=4", + "profile": "https://naruaway.com/", + "contributions": [ + "code" + ] + }, + { + "login": "piersy", + "name": "piersy", + "avatar_url": "https://avatars.githubusercontent.com/u/5087847?v=4", + "profile": "https://github.com/piersy", + "contributions": [ + "code" + ] + }, + { + "login": "ryantig", + "name": "ryantig", + "avatar_url": "https://avatars.githubusercontent.com/u/324810?v=4", + "profile": "https://github.com/ryantig", + "contributions": [ + "code" + ] + }, + { + "login": "rydesun", + "name": "rydesun", + "avatar_url": "https://avatars.githubusercontent.com/u/19602440?v=4", + "profile": "https://catcat.cc/", + "contributions": [ + "code" + ] + }, + { + "login": "sc00ter", + "name": "sc00ter", + "avatar_url": "https://avatars.githubusercontent.com/u/1271025?v=4", + "profile": "https://github.com/sc00ter", + "contributions": [ + "code" + ] + }, + { + "login": "smhc", + "name": "smhc", + "avatar_url": "https://avatars.githubusercontent.com/u/6404304?v=4", + "profile": "https://github.com/smhc", + "contributions": [ + "code" + ] + }, + { + "login": "stkaplan", + "name": "Sam Kaplan", + "avatar_url": "https://avatars.githubusercontent.com/u/594990?v=4", + "profile": "https://github.com/stkaplan", + "contributions": [ + "code" + ] + }, + { + "login": "tasuten", + "name": "tasuten", + "avatar_url": "https://avatars.githubusercontent.com/u/1623176?v=4", + "profile": "https://github.com/tasuten", + "contributions": [ + "code" + ] + }, + { + "login": "todesking", + "name": "todesking", + "avatar_url": "https://avatars.githubusercontent.com/u/112881?v=4", + "profile": "http://todesking.com/", + "contributions": [ + "code" + ] + }, + { + "login": "typicode", + "name": "typicode", + "avatar_url": "https://avatars.githubusercontent.com/u/5502029?v=4", + "profile": "https://github.com/typicode", + "contributions": [ + "code" + ] + }, + { + "login": "LiMingFei56", + "name": "李鸣飞", + "avatar_url": "https://avatars.githubusercontent.com/u/8553407?v=4", + "profile": "https://limingfei56.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "eltociear", + "name": "Ikko Ashimine", + "avatar_url": "https://avatars.githubusercontent.com/u/22633385?v=4", + "profile": "https://bandism.net/", + "contributions": [ + "doc" + ] + }, + { + "login": "rammiah", + "name": "Rammiah", + "avatar_url": "https://avatars.githubusercontent.com/u/26727562?v=4", + "profile": "https://github.com/rammiah", + "contributions": [ + "bug" + ] + } + ], + "contributorsPerLine": 7, + "skipCi": true +} diff --git a/sources_non_forked/coc.nvim/.editorconfig b/sources_non_forked/coc.nvim/.editorconfig new file mode 100644 index 00000000..158192a1 --- /dev/null +++ b/sources_non_forked/coc.nvim/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 + +[*.{js,ts}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +max_line_length = 120 + +[*.json] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.vim] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +max_line_length = 120 diff --git a/sources_non_forked/coc.nvim/.eslintignore b/sources_non_forked/coc.nvim/.eslintignore new file mode 100644 index 00000000..f38d5306 --- /dev/null +++ b/sources_non_forked/coc.nvim/.eslintignore @@ -0,0 +1,5 @@ +node_modules +coverage +build +lib +typings diff --git a/sources_non_forked/coc.nvim/.eslintrc.js b/sources_non_forked/coc.nvim/.eslintrc.js new file mode 100644 index 00000000..f6a76753 --- /dev/null +++ b/sources_non_forked/coc.nvim/.eslintrc.js @@ -0,0 +1,339 @@ +module.exports = { + "root": true, + "env": { + "es6": true, + "node": true, + "jest/globals": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "jsdoc", + "jest", + "@typescript-eslint" + ], + "rules": { + "comma-dangle": [ + 0 + ], + "guard-for-in": [ + 0 + ], + "no-dupe-class-members": [ + 0 + ], + "prefer-spread": [ + 0 + ], + "prefer-rest-params": [ + 0 + ], + "func-names": [ + 0 + ], + "require-atomic-updates": [ + 0 + ], + "no-empty": "off", + "no-console": "off", + "linebreak-style": [ + 1, + "unix" + ], + "no-prototype-builtins": [ + 0 + ], + "no-unused-vars": [ + 0 + ], + "no-async-promise-executor": [ + 0 + ], + "constructor-super": "error", + "for-direction": [ + "error" + ], + "getter-return": [ + "error" + ], + "no-case-declarations": [ + "error" + ], + "no-class-assign": [ + "error" + ], + "no-compare-neg-zero": [ + "error" + ], + "no-cond-assign": "error", + "no-const-assign": [ + "error" + ], + "no-constant-condition": [ + "error" + ], + "no-control-regex": [ + "error" + ], + "no-debugger": "error", + "no-delete-var": [ + "error" + ], + "no-dupe-args": [ + "error" + ], + "no-dupe-keys": [ + "error" + ], + "no-duplicate-case": [ + "error" + ], + "no-empty-character-class": [ + "error" + ], + "no-empty-pattern": [ + "error" + ], + "no-ex-assign": [ + "error" + ], + "no-extra-boolean-cast": [ + "error" + ], + "no-extra-semi": [ + "error" + ], + "no-fallthrough": "off", + "no-func-assign": [ + "error" + ], + "no-global-assign": [ + "error" + ], + "no-inner-declarations": [ + "error" + ], + "no-invalid-regexp": [ + "error" + ], + "no-irregular-whitespace": "error", + "no-misleading-character-class": [ + "error" + ], + "no-mixed-spaces-and-tabs": [ + "error" + ], + "no-new-symbol": [ + "error" + ], + "no-obj-calls": [ + "error" + ], + "no-octal": [ + "error" + ], + "no-redeclare": "error", + "no-regex-spaces": [ + "error" + ], + "no-self-assign": [ + "error" + ], + "no-shadow-restricted-names": [ + "error" + ], + "no-sparse-arrays": "error", + "no-this-before-super": [ + "error" + ], + "no-undef": [ + "off" + ], + "no-unexpected-multiline": [ + "error" + ], + "no-unreachable": [ + "warn" + ], + "no-unsafe-finally": "error", + "no-unsafe-negation": [ + "error" + ], + "no-unused-labels": "error", + "no-useless-catch": [ + "error" + ], + "no-useless-escape": [ + "error" + ], + "no-with": [ + "error" + ], + "require-yield": [ + "error" + ], + "use-isnan": "error", + "valid-typeof": "off", + "@typescript-eslint/no-unnecessary-boolean-literal-compare": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", + "@typescript-eslint/prefer-string-starts-ends-with": "off", + "@typescript-eslint/prefer-regexp-exec": "off", + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/array-type": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/restrict-plus-operands": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "explicit", + "overrides": { + "accessors": "explicit", + "constructors": "off" + } + } + ], + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/member-delimiter-style": "off", + "@typescript-eslint/camelcase": "off", + "@typescript-eslint/member-ordering": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-for-in-array": "error", + "@typescript-eslint/no-inferrable-types": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-unnecessary-qualifier": "error", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/prefer-for-of": "off", + "@typescript-eslint/prefer-function-type": "off", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/quotes": "off", + "@typescript-eslint/semi": [ + "error", + "never" + ], + "@typescript-eslint/triple-slash-reference": [ + "error", + { + "path": "always", + "types": "prefer-import", + "lib": "always" + } + ], + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/unified-signatures": "error", + "arrow-body-style": "off", + "arrow-parens": [ + "error", + "as-needed" + ], + "camelcase": "off", + "complexity": "off", + "curly": "off", + "dot-notation": "off", + "eol-last": "off", + "eqeqeq": [ + "off", + "always" + ], + "id-blacklist": [ + "error", + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined" + ], + "id-match": "error", + "jsdoc/check-alignment": "error", + "jsdoc/check-indentation": "error", + "jsdoc/newline-after-description": "error", + "max-classes-per-file": "off", + "new-parens": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-eval": "error", + "no-invalid-this": "off", + "no-magic-numbers": "off", + "no-multiple-empty-lines": [ + "error", + { + "max": 1 + } + ], + "no-new-wrappers": "error", + "no-shadow": [ + "off", + { + "hoist": "all" + } + ], + "no-template-curly-in-string": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-underscore-dangle": "off", + "no-unused-expressions": "off", + "no-var": "error", + "no-void": "off", + "object-shorthand": "error", + "one-var": [ + "error", + "never" + ], + "prefer-const": "off", + "prefer-template": "off", + "quote-props": [ + "error", + "as-needed" + ], + "radix": "error", + "space-before-function-paren": [ + "error", + { + "anonymous": "never", + "asyncArrow": "always", + "named": "never" + } + ], + "spaced-comment": [ + "error", + "always", + { + "markers": [ + "/" + ] + } + ] + }, + "settings": {} +} diff --git a/sources_non_forked/coc.nvim/.github/.codecov.yml b/sources_non_forked/coc.nvim/.github/.codecov.yml new file mode 100644 index 00000000..fa348a8f --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/.codecov.yml @@ -0,0 +1,3 @@ +coverage: + status: + patch: off diff --git a/sources_non_forked/coc.nvim/.github/FUNDING.yml b/sources_non_forked/coc.nvim/.github/FUNDING.yml new file mode 100644 index 00000000..bc74b9db --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +open_collective: cocnvim +patreon: chemzqm diff --git a/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/bug_report.md b/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..3b0eaebb --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,45 @@ +--- +name: Bug report +about: Create a report to help us improve +--- + + + +## Result from CocInfo + + + +## Describe the bug + +A clear and concise description of what the bug is. + +## Reproduce the bug + +**We will close your issue when you don't provide minimal vimrc and we can't +reproduce it** + +- Create file `mini.vim` with: + + ```vim + set nocompatible + set runtimepath^=/path/to/coc.nvim + filetype plugin indent on + syntax on + set hidden + ``` + +- Start (neo)vim with command: `vim -u mini.vim` + +- Operate vim. + +## Screenshots (optional) + +If applicable, add screenshots to help explain your problem. diff --git a/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/feature_request.md b/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..066b2d92 --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/sources_non_forked/coc.nvim/.github/workflows/ci.yml b/sources_non_forked/coc.nvim/.github/workflows/ci.yml new file mode 100644 index 00000000..eb0e1331 --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/workflows/ci.yml @@ -0,0 +1,73 @@ +name: Dev + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + test: + if: github.event.pull_request.draft == false + timeout-minutes: 60 + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + node: + - "16" + - "14" + nvim: + - "0.7.0" + include: + # only enable coverage on the fastest job + - node: "16" + ENABLE_CODE_COVERAGE: true + + env: + NODE_ENV: test + + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + with: + fetch-depth: 2 + + - name: Setup Node.js ${{ matrix.node }} + uses: actions/setup-node@v2.4.0 + with: + node-version: ${{ matrix.node }} + cache: "yarn" + + - name: Setup python3 + uses: actions/setup-python@v2 + with: + python-version: '3.9' + cache: 'pip' + - run: pip install pynvim + + - name: Install Dependencies + run: | + yarn global add typescript + yarn install --frozen-lockfile + + - name: Setup nvim ${{ matrix.nvim }} + run: | + sudo apt-get install -y xclip ripgrep ctags + xclip -version + rg --version + ctags --version + curl -LO https://github.com/neovim/neovim/releases/download/v${{ matrix.nvim }}/nvim-linux64.tar.gz + tar xzf nvim-linux64.tar.gz + export PATH="${PATH}:node_modules/.bin:$(pwd)/nvim-linux64/bin" + nvim --version + yarn test-build --maxWorkers=2 + + - name: Codecov + uses: codecov/codecov-action@v1 + if: ${{ matrix.ENABLE_CODE_COVERAGE }} + with: + fail_ci_if_error: true diff --git a/sources_non_forked/coc.nvim/.github/workflows/lint.yml b/sources_non_forked/coc.nvim/.github/workflows/lint.yml new file mode 100644 index 00000000..448bccb3 --- /dev/null +++ b/sources_non_forked/coc.nvim/.github/workflows/lint.yml @@ -0,0 +1,35 @@ +name: Lint + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + lint: + if: github.event.pull_request.draft == false + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Setup Node.js + uses: actions/setup-node@v2.4.0 + with: + cache: "yarn" + + - name: Install Dependencies + run: yarn install --frozen-lockfile + + - name: Check Types by TSC + run: yarn lint:typecheck + + - name: Lint ESLint + run: yarn lint + + - name: Check Lock File Changes + run: yarn && echo "Listing changed files:" && git diff --name-only --exit-code && echo "No files changed during lint." diff --git a/sources_non_forked/coc.nvim/.gitignore b/sources_non_forked/coc.nvim/.gitignore index f9ec5e3d..266844b7 100644 --- a/sources_non_forked/coc.nvim/.gitignore +++ b/sources_non_forked/coc.nvim/.gitignore @@ -1,13 +1,16 @@ lib +.cache *.map coverage __pycache__ .pyc .log -src -publish.sh +build doc/tags -doc/tags-cn +typings/package.json node_modules -src/__tests__/tags -typings +publish.sh +release.sh +!src/__tests__/tags +src/__tests__/extensions/db.json +package-lock.json diff --git a/sources_non_forked/coc.nvim/.ignore b/sources_non_forked/coc.nvim/.ignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/sources_non_forked/coc.nvim/.ignore @@ -0,0 +1 @@ +lib diff --git a/sources_non_forked/coc.nvim/.npmignore b/sources_non_forked/coc.nvim/.npmignore new file mode 100644 index 00000000..0193cd28 --- /dev/null +++ b/sources_non_forked/coc.nvim/.npmignore @@ -0,0 +1,16 @@ +*.map +.cache +lib/extensions +lib/__tests__ +plugin +autoload +rplugin +src +.github +build +coverage +data +tslint.json +tsconfig.json +.zip +.DS_Store diff --git a/sources_non_forked/coc.nvim/.prettierignore b/sources_non_forked/coc.nvim/.prettierignore new file mode 100644 index 00000000..8eba6c8d --- /dev/null +++ b/sources_non_forked/coc.nvim/.prettierignore @@ -0,0 +1 @@ +src/ diff --git a/sources_non_forked/coc.nvim/.swcrc b/sources_non_forked/coc.nvim/.swcrc new file mode 100644 index 00000000..6df4f6a9 --- /dev/null +++ b/sources_non_forked/coc.nvim/.swcrc @@ -0,0 +1,16 @@ +{ + "sourceMaps": false, + "module": { + "type": "es6" + }, + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "dynamicImport": false, + "decorators": false + }, + "loose": true, + "target": "es2016" + } +} diff --git a/sources_non_forked/coc.nvim/.vim/coc-settings.json b/sources_non_forked/coc.nvim/.vim/coc-settings.json new file mode 100644 index 00000000..7746fb78 --- /dev/null +++ b/sources_non_forked/coc.nvim/.vim/coc-settings.json @@ -0,0 +1,7 @@ +{ + "eslint.validate": ["typescript"], + "eslint.lintTask.options": [".", "--ext", ".ts"], + "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "typescript.suggestionActions.enabled": false +} diff --git a/sources_non_forked/coc.nvim/Backers.md b/sources_non_forked/coc.nvim/Backers.md new file mode 100644 index 00000000..b3cdb0b2 --- /dev/null +++ b/sources_non_forked/coc.nvim/Backers.md @@ -0,0 +1,207 @@ +# Backers + +❤️ coc.nvim? Help us keep it alive by [donating funds](https://www.bountysource.com/teams/coc-nvim)😘! + + + oblitum + + + free-easy + + + ruanyl + + + robjuffermans + + + iamcco + + + phcerdan + + + sarene + + + robtrac + + + raidou + + + tomspeak + + + taigacute + + + weirongxu + + + tbo + + + darthShadow + + + yatli + + + Matt Greer + + + malob + + + Emigre + + + OkanEsen + + + Lennaert Meijvogel + + + Nils Landt + + + dlants + + + RCVU + + + yatli + + + mikker + + + Velovix + + + stCarolas + + + Robbie Clarken + + + hallettj + + + appelgriebsch + + + cosminadrianpopescu + + + partizan + + + ksaldana1 + + + jesperryom + + + JackCA + + + peymanmortazavi + + + jonaustin + + + Yuriy Ivanyuk + + + abenz1267 + + + Sh3Rm4n + + + mwcz + + + Philipp-M + + + gvelchuru + + + JSamir + + + toby de havilland + + + viniciusarcanjo + + + Mike Hearn + + + darsto + + + pyrho + + + Frydac + + + gsa9 + + + _andys8 + + + iago-lito + + + ddaletski + + + jonatan-branting + + + yutakatay + + + kevinrambaud + + + tomaskallup + + + LewisSteele + + +## 微信扫码赞助者 + +- free-easy +- sarene +- tomspeak +- robtrac +- 葫芦小金刚 +- leo 陶 +- 飞翔的白斩鸡 +- mark_ll +- 火冷 +- Solomon +- 李宇星 +- Yus +- IndexXuan +- Sniper +- 陈达野 +- 胖听 +- Jimmy +- lightxue +- 小亦俊 +- 周慎敏 +- 凤鸣 +- Wilson +- Abel diff --git a/sources_non_forked/coc.nvim/CONTRIBUTING.md b/sources_non_forked/coc.nvim/CONTRIBUTING.md new file mode 100644 index 00000000..a3cac5f5 --- /dev/null +++ b/sources_non_forked/coc.nvim/CONTRIBUTING.md @@ -0,0 +1,142 @@ +# Contributing + +## How do I... + +- [Use This Guide](#introduction)? +- Make Something? 🤓👩🏽‍💻📜🍳 + - [Project Setup](#project-setup) + - [Contribute Documentation](#contribute-documentation) + - [Contribute Code](#contribute-code) +- Manage Something ✅🙆🏼💃👔 + - [Provide Support on Issues](#provide-support-on-issues) + - [Review Pull Requests](#review-pull-requests) + - [Join the Project Team](#join-the-project-team) + +## Introduction + +Thank you so much for your interest in contributing!. All types of contributions are encouraged and valued. See the [table of contents](#toc) for different ways to help and details about how this project handles them!📝 + +The [Project Team](#join-the-project-team) looks forward to your contributions. 🙌🏾✨ + +## Project Setup + +So you wanna contribute some code! That's great! This project uses GitHub Pull Requests to manage contributions, so [read up on how to fork a GitHub project and file a PR](https://guides.github.com/activities/forking) if you've never done it before. + +If this seems like a lot or you aren't able to do all this setup, you might also be able to [edit the files directly](https://help.github.com/articles/editing-files-in-another-user-s-repository/) without having to do any of this setup. Yes, [even code](#contribute-code). + +If you want to go the usual route and run the project locally, though: + +- [Install Node.js](https://nodejs.org/en/download/) +- [Install Yarn](https://yarnpkg.com) +- [Fork the project](https://guides.github.com/activities/forking/#fork) + +Then in your terminal: + +- Add coc.nvim to your vim's rtp by `set runtimepath^=/path/to/coc.nvim` +- `cd path/to/your/coc.nvim` +- `yarn install` +- Install [coc-tsserver](https://github.com/neoclide/coc-tsserver) by + `:CocInstall coc-tsserver` in your vim +- Install [coc-tslint-plugin](https://github.com/neoclide/coc-tslint-plugin) by + `:CocInstall coc-tslint-plugin` in your vim. + +And you should be ready to go! + +## Contribute Documentation + +Documentation is a super important, critical part of this project. Docs are how we keep track of what we're doing, how, and why. It's how we stay on the same page about our policies. And it's how we tell others everything they need in order to be able to use this project -- or contribute to it. So thank you in advance. + +Documentation contributions of any size are welcome! Feel free to file a PR even if you're just rewording a sentence to be more clear, or fixing a spelling mistake! + +To contribute documentation: + +- [Set up the project](#project-setup). +- Edit or add any relevant documentation. +- Make sure your changes are formatted correctly and consistently with the rest of the documentation. +- Re-read what you wrote, and run a spellchecker on it to make sure you didn't miss anything. +- In your commit message(s), begin the first line with `docs:`. For example: `docs: Adding a doc contrib section to CONTRIBUTING.md`. +- Write clear, concise commit message(s) using [conventional-changelog format](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md). Documentation commits should use `docs(): `. +- Go to https://github.com/neoclide/coc.nvim/pulls and open a new pull request with your changes. +- If your PR is connected to an open issue, add a line in your PR's description that says `Fixes: #123`, where `#123` is the number of the issue you're fixing. + +## Contribute Code + +We like code commits a lot! They're super handy, and they keep the project going and doing the work it needs to do to be useful to others. + +Code contributions of just about any size are acceptable! + +The main difference between code contributions and documentation contributions is that contributing code requires inclusion of relevant tests for the code being added or changed. Contributions without accompanying tests will be held off until a test is added, unless the maintainers consider the specific tests to be either impossible, or way too much of a burden for such a contribution. + +To contribute code: + +- [Set up the project](#project-setup). +- Make any necessary changes to the source code. +- Include any [additional documentation](#contribute-documentation) the changes might need. +- Make sure the code doesn't have lint issue by command `yarn lint` in your + terminal. +- Write tests that verify that your contribution works as expected when necessary. +- Make sure all tests passed by command `yarn jest` in your terminal. +- Write clear, concise commit message(s) using [conventional-changelog format](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md). +- Dependency updates, additions, or removals must be in individual commits, and the message must use the format: `(deps): PKG@VERSION`, where `` is any of the usual `conventional-changelog` prefixes, at your discretion. +- Go to https://github.com/neoclide/coc.nvim/pulls and open a new pull request with your changes. +- If your PR is connected to an open issue, add a line in your PR's description that says `Fixes: #123`, where `#123` is the number of the issue you're fixing. + +Once you've filed the PR: + +- Barring special circumstances, maintainers will not review PRs until all checks pass (Travis, AppVeyor, etc). +- One or more maintainers will use GitHub's review feature to review your PR. +- If the maintainer asks for any changes, edit your changes, push, and ask for another review. Additional tags (such as `needs-tests`) will be added depending on the review. +- If the maintainer decides to pass on your PR, they will thank you for the contribution and explain why they won't be accepting the changes. That's ok! We still really appreciate you taking the time to do it, and we don't take that lightly. 💚 +- If your PR gets accepted, it will be marked as such, and merged into the `latest` branch soon after. Your contribution will be distributed to the masses next time the maintainers [tag a release](#tag-a-release) + +## Provide Support on Issues + +[Needs Collaborator](#join-the-project-team): none + +Helping out other users with their questions is a really awesome way of contributing to any community. It's not uncommon for most of the issues on an open source projects being support-related questions by users trying to understand something they ran into, or find their way around a known bug. + +Sometimes, the `support` label will be added to things that turn out to actually be other things, like bugs or feature requests. In that case, suss out the details with the person who filed the original issue, add a comment explaining what the bug is, and change the label from `support` to `bug` or `feature`. If you can't do this yourself, @mention a maintainer so they can do it. + +In order to help other folks out with their questions: + +- Go to the issue tracker and [filter open issues by the `support` label](https://github.com/neoclide/coc.nvim/issues?q=is%3Aopen+is%3Aissue+label%3Asupport). +- Read through the list until you find something that you're familiar enough with to give an answer to. +- Respond to the issue with whatever details are needed to clarify the question, or get more details about what's going on. +- Once the discussion wraps up and things are clarified, either close the issue, or ask the original issue filer (or a maintainer) to close it for you. + +Some notes on picking up support issues: + +- Avoid responding to issues you don't know you can answer accurately. +- As much as possible, try to refer to past issues with accepted answers. Link to them from your replies with the `#123` format. +- Be kind and patient with users -- often, folks who have run into confusing things might be upset or impatient. This is ok. Try to understand where they're coming from, and if you're too uncomfortable with the tone, feel free to stay away or withdraw from the issue. (note: if the user is outright hostile or is violating the CoC, [refer to the Code of Conduct](CODE_OF_CONDUCT.md) to resolve the conflict). + +## Review Pull Requests + +[Needs Collaborator](#join-the-project-team): Issue Tracker + +While anyone can comment on a PR, add feedback, etc, PRs are only _approved_ by team members with Issue Tracker or higher permissions. + +PR reviews use [GitHub's own review feature](https://help.github.com/articles/about-pull-request-reviews/), which manages comments, approval, and review iteration. + +Some notes: + +- You may ask for minor changes ("nitpicks"), but consider whether they are really blockers to merging: try to err on the side of "approve, with comments". +- _ALL PULL REQUESTS_ should be covered by a test: either by a previously-failing test, an existing test that covers the entire functionality of the submitted code, or new tests to verify any new/changed behavior. All tests must also pass and follow established conventions. Test coverage should not drop, unless the specific case is considered reasonable by maintainers. +- Please make sure you're familiar with the code or documentation being updated, unless it's a minor change (spellchecking, minor formatting, etc). You may @mention another project member who you think is better suited for the review, but still provide a non-approving review of your own. +- Be extra kind: people who submit code/doc contributions are putting themselves in a pretty vulnerable position, and have put time and care into what they've done (even if that's not obvious to you!) -- always respond with respect, be understanding, but don't feel like you need to sacrifice your standards for their sake, either. Just don't be a jerk about it? + +## Join the Project Team + +### Ways to Join + +There are many ways to contribute! Most of them don't require any official status unless otherwise noted. That said, there's a couple of positions that grant special repository abilities, and this section describes how they're granted and what they do. + +All of the below positions are granted based on the project team's needs, as well as their consensus opinion about whether they would like to work with the person and think that they would fit well into that position. The process is relatively informal, and it's likely that people who express interest in participating can just be granted the permissions they'd like. + +You can spot a collaborator on the repo by looking for the `[Collaborator]` or `[Owner]` tags next to their names. + +| Permission | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Issue Tracker | Granted to contributors who express a strong interest in spending time on the project's issue tracker. These tasks are mainly [labeling issues](#label-issues), [cleaning up old ones](#clean-up-issues-and-prs), and [reviewing pull requests](#review-pull-requests), as well as all the usual things non-team-member contributors can do. Issue handlers should not merge pull requests, tag releases, or directly commit code themselves: that should still be done through the usual pull request process. Becoming an Issue Handler means the project team trusts you to understand enough of the team's process and context to implement it on the issue tracker. | +| Committer | Granted to contributors who want to handle the actual pull request merges, tagging new versions, etc. Committers should have a good level of familiarity with the codebase, and enough context to understand the implications of various changes, as well as a good sense of the will and expectations of the project team. | +| Admin/Owner | Granted to people ultimately responsible for the project, its community, etc. | diff --git a/sources_non_forked/coc.nvim/LICENSE.md b/sources_non_forked/coc.nvim/LICENSE.md index bee2bf1d..2faae0b1 100644 --- a/sources_non_forked/coc.nvim/LICENSE.md +++ b/sources_non_forked/coc.nvim/LICENSE.md @@ -1,7 +1,46 @@ -Copyright 2018-2018 by Qiming Zhao aaa +Copyright (c) <2022> -Permission 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: +"Anti 996" License Version 1.0 (Draft) -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +Permission is hereby granted to any individual or legal entity +obtaining a copy of this licensed work (including the source code, +documentation and/or related items, hereinafter collectively referred +to as the "licensed work"), free of charge, to deal with the licensed +work for any purpose, including without limitation, the rights to use, +reproduce, modify, prepare derivative works of, distribute, publish +and sublicense the licensed work, subject to the following conditions: -THE 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. +1. The individual or the legal entity must conspicuously display, + without modification, this License and the notice on each redistributed + or derivative copy of the Licensed Work. + +2. The individual or the legal entity must strictly comply with all + applicable laws, regulations, rules and standards of the jurisdiction + relating to labor and employment where the individual is physically + located or where the individual was born or naturalized; or where the + legal entity is registered or is operating (whichever is stricter). In + case that the jurisdiction has no such laws, regulations, rules and + standards or its laws, regulations, rules and standards are + unenforceable, the individual or the legal entity are required to + comply with Core International Labor Standards. + +3. The individual or the legal entity shall not induce, suggest or force + its employee(s), whether full-time or part-time, or its independent + contractor(s), in any methods, to agree in oral or written form, to + directly or indirectly restrict, weaken or relinquish his or her + rights or remedies under such laws, regulations, rules and standards + relating to labor and employment as mentioned above, no matter whether + such written or oral agreements are enforceable under the laws of the + said jurisdiction, nor shall such individual or the legal entity + limit, in any methods, the rights of its employee(s) or independent + contractor(s) from reporting or complaining to the copyright holder or + relevant authorities monitoring the compliance of the license about + its violation(s) of the said license. + +THE LICENSED WORK 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 COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE +LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK. diff --git a/sources_non_forked/coc.nvim/Readme.md b/sources_non_forked/coc.nvim/README.md similarity index 100% rename from sources_non_forked/coc.nvim/Readme.md rename to sources_non_forked/coc.nvim/README.md diff --git a/sources_non_forked/coc.nvim/autoload/coc/helper.vim b/sources_non_forked/coc.nvim/autoload/coc/helper.vim deleted file mode 100644 index 8bdc9b86..00000000 --- a/sources_non_forked/coc.nvim/autoload/coc/helper.vim +++ /dev/null @@ -1,148 +0,0 @@ -scriptencoding utf-8 -" Helper methods for viml - -function! coc#helper#get_charactor(line, col) abort - return strchars(strpart(a:line, 0, a:col - 1)) -endfunction - -function! coc#helper#last_character(line) abort - return strcharpart(a:line, strchars(a:line) - 1, 1) -endfunction - -function! coc#helper#obj_equal(one, two) abort - for key in keys(a:one) - if a:one[key] != a:two[key] - return 0 - endif - endfor - return 1 -endfunction - -" get change between two lines -function! coc#helper#str_diff(curr, previous, col) abort - let end = strpart(a:curr, a:col - 1) - let start = strpart(a:curr, 0, a:col -1) - let endOffset = 0 - let startOffset = 0 - let currLen = strchars(a:curr) - let prevLen = strchars(a:previous) - if len(end) - let endLen = strchars(end) - for i in range(min([prevLen, endLen])) - if strcharpart(end, endLen - 1 - i, 1) ==# strcharpart(a:previous, prevLen -1 -i, 1) - let endOffset = endOffset + 1 - else - break - endif - endfor - endif - let remain = endOffset == 0 ? a:previous : strcharpart(a:previous, 0, prevLen - endOffset) - if len(remain) - for i in range(min([strchars(remain), strchars(start)])) - if strcharpart(remain, i, 1) ==# strcharpart(start, i ,1) - let startOffset = startOffset + 1 - else - break - endif - endfor - endif - return { - \ 'start': startOffset, - \ 'end': prevLen - endOffset, - \ 'text': strcharpart(a:curr, startOffset, currLen - startOffset - endOffset) - \ } -endfunction - -function! coc#helper#str_apply(content, diff) abort - let totalLen = strchars(a:content) - let endLen = totalLen - a:diff['end'] - return strcharpart(a:content, 0, a:diff['start']).a:diff['text'].strcharpart(a:content, a:diff['end'], endLen) -endfunction - -" insert inserted to line at position, use ... when result is too long -" line should only contains character has strwidth equals 1 -function! coc#helper#str_compose(line, position, inserted) abort - let width = strwidth(a:line) - let text = a:inserted - let res = a:line - let need_truncate = a:position + strwidth(text) + 1 > width - if need_truncate - let remain = width - a:position - 3 - if remain < 2 - " use text for full line, use first & end of a:line, ignore position - let res = strcharpart(a:line, 0, 1) - let w = strwidth(res) - for i in range(strchars(text)) - let c = strcharpart(text, i, 1) - let a = strwidth(c) - if w + a <= width - 1 - let w = w + a - let res = res.c - endif - endfor - let res = res.strcharpart(a:line, w) - else - let res = strcharpart(a:line, 0, a:position) - let w = strwidth(res) - for i in range(strchars(text)) - let c = strcharpart(text, i, 1) - let a = strwidth(c) - if w + a <= width - 3 - let w = w + a - let res = res.c - endif - endfor - let res = res.'..' - let w = w + 2 - let res = res.strcharpart(a:line, w) - endif - else - let first = strcharpart(a:line, 0, a:position) - let res = first.text.strcharpart(a:line, a:position + strwidth(text)) - endif - return res -endfunction - -" Return new dict with keys removed -function! coc#helper#dict_omit(dict, keys) abort - let res = {} - for key in keys(a:dict) - if index(a:keys, key) == -1 - let res[key] = a:dict[key] - endif - endfor - return res -endfunction - -" Return new dict with keys only -function! coc#helper#dict_pick(dict, keys) abort - let res = {} - for key in keys(a:dict) - if index(a:keys, key) != -1 - let res[key] = a:dict[key] - endif - endfor - return res -endfunction - -" support for float values -function! coc#helper#min(first, ...) abort - let val = a:first - for i in range(0, len(a:000) - 1) - if a:000[i] < val - let val = a:000[i] - endif - endfor - return val -endfunction - -" support for float values -function! coc#helper#max(first, ...) abort - let val = a:first - for i in range(0, len(a:000) - 1) - if a:000[i] > val - let val = a:000[i] - endif - endfor - return val -endfunction diff --git a/sources_non_forked/coc.nvim/autoload/coc/notify.vim b/sources_non_forked/coc.nvim/autoload/coc/notify.vim index 562a02d5..89351fbe 100644 --- a/sources_non_forked/coc.nvim/autoload/coc/notify.vim +++ b/sources_non_forked/coc.nvim/autoload/coc/notify.vim @@ -292,8 +292,9 @@ function! coc#notify#close(winid) abort endif call coc#window#set_var(a:winid, 'closing', 1) call s:cancel(a:winid) - let curr = s:is_vim ? {'row': row} : {'winblend': coc#window#get_var(a:winid, 'winblend', 30)} - let dest = s:is_vim ? {'row': row + 1} : {'winblend': 60} + let winblend = coc#window#get_var(a:winid, 'winblend', 0) + let curr = s:is_vim ? {'row': row} : {'winblend': winblend} + let dest = s:is_vim ? {'row': row + 1} : {'winblend': winblend == 0 ? 0 : 60} call s:animate(a:winid, curr, dest, 0, 1) endfunction diff --git a/sources_non_forked/coc.nvim/autoload/coc/util.vim b/sources_non_forked/coc.nvim/autoload/coc/util.vim index c4b38b2a..2f343d92 100644 --- a/sources_non_forked/coc.nvim/autoload/coc/util.vim +++ b/sources_non_forked/coc.nvim/autoload/coc/util.vim @@ -182,14 +182,10 @@ function! coc#util#jump(cmd, filepath, ...) abort else exec 'drop '.fnameescape(file) endif - elseif a:cmd == 'edit' - if bufloaded(file) - exe 'b '.bufnr(file) - else - exe a:cmd.' '.fnameescape(file) - endif + elseif a:cmd == 'edit' && bufloaded(file) + exe 'b '.bufnr(file) else - exe a:cmd.' '.fnameescape(file) + call s:safer_open(a:cmd, file) endif if !empty(get(a:, 1, [])) let line = getline(a:1[0] + 1) @@ -208,6 +204,43 @@ function! coc#util#jump(cmd, filepath, ...) abort endif endfunction +function! s:safer_open(cmd, file) abort + " How to support :pedit and :drop? + let is_supported_cmd = index(["edit", "split", "vsplit", "tabe"], a:cmd) >= 0 + + " Special handling should be limited to URI. + let looks_like_uri = match(a:file, "^.*://") >= 0 + + if looks_like_uri && is_supported_cmd && has('win32') && has('nvim') + if bufloaded(a:file) + let buf = bufnr(a:file) + " Do not reload existing buffer + let reload_buffer = v:false + else + " Workaround a bug for Win32 paths (works in Neovim only). + " + " reference: + " - https://github.com/vim/vim/issues/541 + " - https://github.com/neoclide/coc-java/issues/82 + let buf = nvim_create_buf(v:true, v:false) + " Ignore swap file error occuring when, for example, file is a URI. + silent! call nvim_buf_set_name(buf, a:file) + let reload_buffer = v:true + endif + if a:cmd != 'edit' + " Open split, tab, etc. by a:cmd. + exe a:cmd + endif + " Set filename and reload file (or URI) contents by :edit. + exe 'keepjumps buffer ' . buf + if reload_buffer + exe 'keepjumps edit' + endif + else + exe a:cmd.' '.fnameescape(a:file) + endif +endfunction + function! coc#util#variables(bufnr) abort let info = getbufinfo(a:bufnr) let variables = empty(info) ? {} : copy(info[0]['variables']) diff --git a/sources_non_forked/coc.nvim/build/index.js b/sources_non_forked/coc.nvim/build/index.js deleted file mode 100644 index ad4d1e6e..00000000 --- a/sources_non_forked/coc.nvim/build/index.js +++ /dev/null @@ -1,337 +0,0 @@ -"use strict";(function () { - var v = process.version - var parts = v.slice(1).split('.') - var major = parseInt(parts[0], 10) - var minor = parseInt(parts[1], 10) - if (major < 12 || (major == 12 && minor < 12)) { - throw new Error('coc.nvim requires node >= v12.12.0, current version: ' + v) - } -})(); -var Vte=Object.create;var Jh=Object.defineProperty,eie=Object.defineProperties,tie=Object.getOwnPropertyDescriptor,iie=Object.getOwnPropertyDescriptors,nie=Object.getOwnPropertyNames,yR=Object.getOwnPropertySymbols,rie=Object.getPrototypeOf,wR=Object.prototype.hasOwnProperty,oie=Object.prototype.propertyIsEnumerable;var vR=(n,e,t)=>e in n?Jh(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,ge=(n,e)=>{for(var t in e||(e={}))wR.call(e,t)&&vR(n,t,e[t]);if(yR)for(var t of yR(e))oie.call(e,t)&&vR(n,t,e[t]);return n},Ba=(n,e)=>eie(n,iie(e)),DR=n=>Jh(n,"__esModule",{value:!0});var _=(n,e)=>()=>(n&&(e=n(n=0)),e);var m=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),xs=(n,e)=>{for(var t in e)Jh(n,t,{get:e[t],enumerable:!0})},xR=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of nie(e))!wR.call(n,r)&&(t||r!=="default")&&Jh(n,r,{get:()=>e[r],enumerable:!(i=tie(e,r))||i.enumerable});return n},C=(n,e)=>xR(DR(Jh(n!=null?Vte(rie(n)):{},"default",!e&&n&&n.__esModule?{get:()=>n.default,enumerable:!0}:{value:n,enumerable:!0})),n),Ha=(n=>(e,t)=>n&&n.get(e)||(t=xR(DR({}),e,1),n&&n.set(e,t),t))(typeof WeakMap!="undefined"?new WeakMap:0);var SR=m((QTe,CR)=>{var pu=1e3,mu=pu*60,bu=mu*60,qa=bu*24,sie=qa*7,aie=qa*365.25;CR.exports=function(n,e){e=e||{};var t=typeof n;if(t==="string"&&n.length>0)return lie(n);if(t==="number"&&isFinite(n))return e.long?cie(n):uie(n);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(n))};function lie(n){if(n=String(n),!(n.length>100)){var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(n);if(!!e){var t=parseFloat(e[1]),i=(e[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return t*aie;case"weeks":case"week":case"w":return t*sie;case"days":case"day":case"d":return t*qa;case"hours":case"hour":case"hrs":case"hr":case"h":return t*bu;case"minutes":case"minute":case"mins":case"min":case"m":return t*mu;case"seconds":case"second":case"secs":case"sec":case"s":return t*pu;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return t;default:return}}}}function uie(n){var e=Math.abs(n);return e>=qa?Math.round(n/qa)+"d":e>=bu?Math.round(n/bu)+"h":e>=mu?Math.round(n/mu)+"m":e>=pu?Math.round(n/pu)+"s":n+"ms"}function cie(n){var e=Math.abs(n);return e>=qa?yp(n,e,qa,"day"):e>=bu?yp(n,e,bu,"hour"):e>=mu?yp(n,e,mu,"minute"):e>=pu?yp(n,e,pu,"second"):n+" ms"}function yp(n,e,t,i){var r=e>=t*1.5;return Math.round(n/t)+" "+i+(r?"s":"")}});var Ex=m((KTe,TR)=>{function hie(n){t.debug=t,t.default=t,t.coerce=l,t.disable=o,t.enable=r,t.enabled=s,t.humanize=SR(),t.destroy=u,Object.keys(n).forEach(c=>{t[c]=n[c]}),t.names=[],t.skips=[],t.formatters={};function e(c){let h=0;for(let d=0;d{if(L==="%%")return"%";S++;let W=t.formatters[j];if(typeof W=="function"){let B=b[S];L=W.call(v,B),b.splice(S,1),S--}return L}),t.formatArgs.call(v,b),(v.log||t.log).apply(v,b)}return p.namespace=c,p.useColors=t.useColors(),p.color=t.selectColor(c),p.extend=i,p.destroy=t.destroy,Object.defineProperty(p,"enabled",{enumerable:!0,configurable:!1,get:()=>d!==null?d:(g!==t.namespaces&&(g=t.namespaces,f=t.enabled(c)),f),set:b=>{d=b}}),typeof t.init=="function"&&t.init(p),p}function i(c,h){let d=t(this.namespace+(typeof h>"u"?":":h)+c);return d.log=this.log,d}function r(c){t.save(c),t.namespaces=c,t.names=[],t.skips=[];let h,d=(typeof c=="string"?c:"").split(/[\s,]+/),g=d.length;for(h=0;h"-"+h)].join(",");return t.enable(""),c}function s(c){if(c[c.length-1]==="*")return!0;let h,d;for(h=0,d=t.skips.length;h{En.formatArgs=gie;En.save=fie;En.load=pie;En.useColors=die;En.storage=mie();En.destroy=(()=>{let n=!1;return()=>{n||(n=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();En.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function die(){return typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)?!0:typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function gie(n){if(n[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+n[0]+(this.useColors?"%c ":" ")+"+"+vp.exports.humanize(this.diff),!this.useColors)return;let e="color: "+this.color;n.splice(1,0,e,"color: inherit");let t=0,i=0;n[0].replace(/%[a-zA-Z%]/g,r=>{r!=="%%"&&(t++,r==="%c"&&(i=t))}),n.splice(i,0,e)}En.log=console.debug||console.log||(()=>{});function fie(n){try{n?En.storage.setItem("debug",n):En.storage.removeItem("debug")}catch{}}function pie(){let n;try{n=En.storage.getItem("debug")}catch{}return!n&&typeof process<"u"&&"env"in process&&(n=process.env.DEBUG),n}function mie(){try{return localStorage}catch{}}vp.exports=Ex()(En);var{formatters:bie}=vp.exports;bie.j=function(n){try{return JSON.stringify(n)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}});var PR=m((zTe,ER)=>{"use strict";ER.exports=(n,e=process.argv)=>{let t=n.startsWith("-")?"":n.length===1?"-":"--",i=e.indexOf(t+n),r=e.indexOf("--");return i!==-1&&(r===-1||i{"use strict";var yie=require("os"),_R=require("tty"),Yn=PR(),{env:oi}=process,Cs;Yn("no-color")||Yn("no-colors")||Yn("color=false")||Yn("color=never")?Cs=0:(Yn("color")||Yn("colors")||Yn("color=true")||Yn("color=always"))&&(Cs=1);"FORCE_COLOR"in oi&&(oi.FORCE_COLOR==="true"?Cs=1:oi.FORCE_COLOR==="false"?Cs=0:Cs=oi.FORCE_COLOR.length===0?1:Math.min(parseInt(oi.FORCE_COLOR,10),3));function Px(n){return n===0?!1:{level:n,hasBasic:!0,has256:n>=2,has16m:n>=3}}function _x(n,e){if(Cs===0)return 0;if(Yn("color=16m")||Yn("color=full")||Yn("color=truecolor"))return 3;if(Yn("color=256"))return 2;if(n&&!e&&Cs===void 0)return 0;let t=Cs||0;if(oi.TERM==="dumb")return t;if(process.platform==="win32"){let i=yie.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in oi)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some(i=>i in oi)||oi.CI_NAME==="codeship"?1:t;if("TEAMCITY_VERSION"in oi)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(oi.TEAMCITY_VERSION)?1:0;if(oi.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in oi){let i=parseInt((oi.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(oi.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(oi.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(oi.TERM)||"COLORTERM"in oi?1:t}function vie(n){let e=_x(n,n&&n.isTTY);return Px(e)}RR.exports={supportsColor:vie,stdout:Px(_x(!0,_R.isatty(1))),stderr:Px(_x(!0,_R.isatty(2)))}});var IR=m((fi,Dp)=>{var wie=require("tty"),wp=require("util");fi.init=Eie;fi.log=Sie;fi.formatArgs=xie;fi.save=Tie;fi.load=kie;fi.useColors=Die;fi.destroy=wp.deprecate(()=>{},"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");fi.colors=[6,2,3,4,5,1];try{let n=LR();n&&(n.stderr||n).level>=2&&(fi.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}fi.inspectOpts=Object.keys(process.env).filter(n=>/^debug_/i.test(n)).reduce((n,e)=>{let t=e.substring(6).toLowerCase().replace(/_([a-z])/g,(r,o)=>o.toUpperCase()),i=process.env[e];return/^(yes|on|true|enabled)$/i.test(i)?i=!0:/^(no|off|false|disabled)$/i.test(i)?i=!1:i==="null"?i=null:i=Number(i),n[t]=i,n},{});function Die(){return"colors"in fi.inspectOpts?Boolean(fi.inspectOpts.colors):wie.isatty(process.stderr.fd)}function xie(n){let{namespace:e,useColors:t}=this;if(t){let i=this.color,r="\x1B[3"+(i<8?i:"8;5;"+i),o=` ${r};1m${e} \x1B[0m`;n[0]=o+n[0].split(` -`).join(` -`+o),n.push(r+"m+"+Dp.exports.humanize(this.diff)+"\x1B[0m")}else n[0]=Cie()+e+" "+n[0]}function Cie(){return fi.inspectOpts.hideDate?"":new Date().toISOString()+" "}function Sie(...n){return process.stderr.write(wp.format(...n)+` -`)}function Tie(n){n?process.env.DEBUG=n:delete process.env.DEBUG}function kie(){return process.env.DEBUG}function Eie(n){n.inspectOpts={};let e=Object.keys(fi.inspectOpts);for(let t=0;te.trim()).join(" ")};FR.O=function(n){return this.inspectOpts.colors=this.useColors,wp.inspect(n,this.inspectOpts)}});var Ot=m((eke,Rx)=>{typeof process>"u"||process.type==="renderer"||process.browser===!0||process.__nwjs?Rx.exports=kR():Rx.exports=IR()});var AR=m((tke,jR)=>{"use strict";jR.exports=Pie;function yu(n){return n instanceof Buffer?Buffer.from(n):new n.constructor(n.buffer.slice(),n.byteOffset,n.length)}function Pie(n){if(n=n||{},n.circles)return _ie(n);return n.proto?i:t;function e(r,o){for(var s=Object.keys(r),a=new Array(s.length),l=0;l{var Rie=require("util"),Ya=Ot()("log4js:configuration"),xp=[],Cp=[],OR=n=>!n,MR=n=>n&&typeof n=="object"&&!Array.isArray(n),Lie=n=>/^[A-Za-z][A-Za-z0-9_]*$/g.test(n),Fie=n=>n&&typeof n=="number"&&Number.isInteger(n),Iie=n=>{Cp.push(n),Ya(`Added listener, now ${Cp.length} listeners`)},jie=n=>{xp.push(n),Ya(`Added pre-processing listener, now ${xp.length} listeners`)},NR=(n,e,t)=>{(Array.isArray(e)?e:[e]).forEach(r=>{if(r)throw new Error(`Problem with log4js configuration: (${Rie.inspect(n,{depth:5})}) - ${t}`)})},Aie=n=>{Ya("New configuration to be validated: ",n),NR(n,OR(MR(n)),"must be an object."),Ya(`Calling pre-processing listeners (${xp.length})`),xp.forEach(e=>e(n)),Ya("Configuration pre-processing finished."),Ya(`Calling configuration listeners (${Cp.length})`),Cp.forEach(e=>e(n)),Ya("Configuration finished.")};BR.exports={configure:Aie,addListener:Iie,addPreProcessingListener:jie,throwExceptionIf:NR,anObject:MR,anInteger:Fie,validIdentifier:Lie,not:OR}});var Sp=m((nke,Wn)=>{"use strict";function HR(n,e){for(var t=n.toString();t.length-1?r:o,a=Za(e.getHours()),l=Za(e.getMinutes()),u=Za(e.getSeconds()),c=HR(e.getMilliseconds(),3),h=Oie(e.getTimezoneOffset()),d=n.replace(/dd/g,t).replace(/MM/g,i).replace(/y{1,4}/g,s).replace(/hh/g,a).replace(/mm/g,l).replace(/ss/g,u).replace(/SSS/g,c).replace(/O/g,h);return d}function Ja(n,e,t,i){n["set"+(i?"":"UTC")+e](t)}function Mie(n,e,t){var i=n.indexOf("O")<0,r=[{pattern:/y{1,4}/,regexp:"\\d{1,4}",fn:function(c,h){Ja(c,"FullYear",h,i)}},{pattern:/MM/,regexp:"\\d{1,2}",fn:function(c,h){Ja(c,"Month",h-1,i)}},{pattern:/dd/,regexp:"\\d{1,2}",fn:function(c,h){Ja(c,"Date",h,i)}},{pattern:/hh/,regexp:"\\d{1,2}",fn:function(c,h){Ja(c,"Hours",h,i)}},{pattern:/mm/,regexp:"\\d\\d",fn:function(c,h){Ja(c,"Minutes",h,i)}},{pattern:/ss/,regexp:"\\d\\d",fn:function(c,h){Ja(c,"Seconds",h,i)}},{pattern:/SSS/,regexp:"\\d\\d\\d",fn:function(c,h){Ja(c,"Milliseconds",h,i)}},{pattern:/O/,regexp:"[+-]\\d{1,2}:?\\d{2}?|Z",fn:function(c,h){h==="Z"?h=0:h=h.replace(":","");var d=Math.abs(h),g=(h>0?-1:1)*(d%100+Math.floor(d/100)*60);c.setUTCMinutes(c.getUTCMinutes()+g)}}],o=r.reduce(function(c,h){return h.pattern.test(c.regexp)?(h.index=c.regexp.match(h.pattern).index,c.regexp=c.regexp.replace(h.pattern,"("+h.regexp+")")):h.index=-1,c},{regexp:n,index:[]}),s=r.filter(function(c){return c.index>-1});s.sort(function(c,h){return c.index-h.index});var a=new RegExp(o.regexp),l=a.exec(e);if(l){var u=t||Wn.exports.now();return s.forEach(function(c,h){c.fn(u,l[h+1])}),u}throw new Error("String '"+e+"' could not be parsed as '"+n+"'")}function Nie(n,e,t){if(!n)throw new Error("pattern must be supplied");return Mie(n,e,t)}function Bie(){return new Date}Wn.exports=qR;Wn.exports.asString=qR;Wn.exports.parse=Nie;Wn.exports.now=Bie;Wn.exports.ISO8601_FORMAT="yyyy-MM-ddThh:mm:ss.SSS";Wn.exports.ISO8601_WITH_TZ_OFFSET_FORMAT="yyyy-MM-ddThh:mm:ss.SSSO";Wn.exports.DATETIME_FORMAT="dd MM yyyy hh:mm:ss.SSS";Wn.exports.ABSOLUTETIME_FORMAT="hh:mm:ss.SSS"});var Fx=m((rke,zR)=>{var Ss=Sp(),YR=require("os"),$h=require("util"),WR=require("path"),ZR={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[90,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[91,39],yellow:[33,39]};function JR(n){return n?`\x1B[${ZR[n][0]}m`:""}function $R(n){return n?`\x1B[${ZR[n][1]}m`:""}function Hie(n,e){return JR(e)+n+$R(e)}function XR(n,e){return Hie($h.format("[%s] [%s] %s - ",Ss.asString(n.startTime),n.level.toString(),n.categoryName),e)}function UR(n){return XR(n)+$h.format(...n.data)}function Tp(n){return XR(n,n.level.colour)+$h.format(...n.data)}function GR(n){return $h.format(...n.data)}function QR(n){return n.data[0]}function KR(n,e){let t="%r %p %c - %m%n",i=/%(-?[0-9]+)?(\.?-?[0-9]+)?([[\]cdhmnprzxXyflos%])(\{([^}]+)\})?|([^%]+)/;n=n||t;function r(I,M){let J=I.categoryName;if(M){let K=parseInt(M,10),ae=J.split(".");KK&&(J=ae.slice(-K).join(WR.sep))}return J}function D(I){return I.lineNumber?`${I.lineNumber}`:""}function S(I){return I.columnNumber?`${I.columnNumber}`:""}function F(I){return I.callStack||""}let L={c:r,d:o,h:s,m:a,n:l,p:u,r:c,"[":h,"]":d,y:p,z:f,"%":g,x:b,X:v,f:w,l:D,o:S,s:F};function j(I,M,J){return L[I](M,J)}function W(I,M){let J;return I?(J=parseInt(I.substr(1),10),J>0?M.slice(0,J):M.slice(J)):M}function B(I,M){let J;if(I)if(I.charAt(0)==="-")for(J=parseInt(I.substr(1),10);M.length{var Yt=Wa(),VR=["white","grey","black","blue","cyan","green","magenta","red","yellow"],zt=class{constructor(e,t,i){this.level=e,this.levelStr=t,this.colour=i}toString(){return this.levelStr}static getLevel(e,t){return e?e instanceof zt?e:(e instanceof Object&&e.levelStr&&(e=e.levelStr),zt[e.toString().toUpperCase()]||t):t}static addLevels(e){e&&(Object.keys(e).forEach(i=>{let r=i.toUpperCase();zt[r]=new zt(e[i].value,r,e[i].colour);let o=zt.levels.findIndex(s=>s.levelStr===r);o>-1?zt.levels[o]=zt[r]:zt.levels.push(zt[r])}),zt.levels.sort((i,r)=>i.level-r.level))}isLessThanOrEqualTo(e){return typeof e=="string"&&(e=zt.getLevel(e)),this.level<=e.level}isGreaterThanOrEqualTo(e){return typeof e=="string"&&(e=zt.getLevel(e)),this.level>=e.level}isEqualTo(e){return typeof e=="string"&&(e=zt.getLevel(e)),this.level===e.level}};zt.levels=[];zt.addLevels({ALL:{value:Number.MIN_VALUE,colour:"grey"},TRACE:{value:5e3,colour:"blue"},DEBUG:{value:1e4,colour:"cyan"},INFO:{value:2e4,colour:"green"},WARN:{value:3e4,colour:"yellow"},ERROR:{value:4e4,colour:"red"},FATAL:{value:5e4,colour:"magenta"},MARK:{value:9007199254740992,colour:"grey"},OFF:{value:Number.MAX_VALUE,colour:"grey"}});Yt.addListener(n=>{let e=n.levels;e&&(Yt.throwExceptionIf(n,Yt.not(Yt.anObject(e)),"levels must be an object"),Object.keys(e).forEach(i=>{Yt.throwExceptionIf(n,Yt.not(Yt.validIdentifier(i)),`level name "${i}" is not a valid identifier (must start with a letter, only contain A-Z,a-z,0-9,_)`),Yt.throwExceptionIf(n,Yt.not(Yt.anObject(e[i])),`level "${i}" must be an object`),Yt.throwExceptionIf(n,Yt.not(e[i].value),`level "${i}" must have a 'value' property`),Yt.throwExceptionIf(n,Yt.not(Yt.anInteger(e[i].value)),`level "${i}".value must have an integer value`),Yt.throwExceptionIf(n,Yt.not(e[i].colour),`level "${i}" must have a 'colour' property`),Yt.throwExceptionIf(n,Yt.not(VR.indexOf(e[i].colour)>-1),`level "${i}".colour must be one of ${VR.join(", ")}`)}))});Yt.addListener(n=>{zt.addLevels(n.levels)});eL.exports=zt});var cL=m(Uh=>{"use strict";var{parse:nL,stringify:rL}=JSON,{keys:qie}=Object,Xh=String,oL="string",tL={},kp="object",sL=(n,e)=>e,Yie=n=>n instanceof Xh?Xh(n):n,Wie=(n,e)=>typeof e===oL?new Xh(e):e,aL=(n,e,t,i)=>{let r=[];for(let o=qie(t),{length:s}=o,a=0;a{let i=Xh(e.push(t)-1);return n.set(t,i),i},lL=(n,e)=>{let t=nL(n,Wie).map(Yie),i=t[0],r=e||sL,o=typeof i===kp&&i?aL(t,new Set,i,r):i;return r.call({"":o},"",o)};Uh.parse=lL;var uL=(n,e,t)=>{let i=e&&typeof e===kp?(c,h)=>c===""||-1nL(uL(n));Uh.toJSON=Zie;var Jie=n=>lL(rL(n));Uh.fromJSON=Jie});var Ix=m((ake,gL)=>{var hL=cL(),dL=$a(),Gh=class{constructor(e,t,i,r,o){this.startTime=new Date,this.categoryName=e,this.data=i,this.level=t,this.context=Object.assign({},r),this.pid=process.pid,o&&(this.functionName=o.functionName,this.fileName=o.fileName,this.lineNumber=o.lineNumber,this.columnNumber=o.columnNumber,this.callStack=o.callStack)}serialise(){let e=this.data.map(t=>(t&&t.message&&t.stack&&(t=Object.assign({message:t.message,stack:t.stack},t)),t));return this.data=e,hL.stringify(this)}static deserialise(e){let t;try{let i=hL.parse(e);i.data=i.data.map(r=>{if(r&&r.message&&r.stack){let o=new Error(r);Object.keys(r).forEach(s=>{o[s]=r[s]}),r=o}return r}),t=new Gh(i.categoryName,dL.getLevel(i.level.levelStr),i.data,i.context),t.startTime=new Date(i.startTime),t.pid=i.pid,t.cluster=i.cluster}catch(i){t=new Gh("log4js",dL.ERROR,["Unable to parse log:",e,"because: ",i])}return t}};gL.exports=Gh});var Pp=m((lke,mL)=>{var Zn=Ot()("log4js:clustering"),$ie=Ix(),Xie=Wa(),vu=!1,$r=null;try{$r=require("cluster")}catch{Zn("cluster module not present"),vu=!0}var Ax=[],Kh=!1,Qh="NODE_APP_INSTANCE",fL=()=>Kh&&process.env[Qh]==="0",jx=()=>vu||$r.isMaster||fL(),pL=n=>{Ax.forEach(e=>e(n))},Ep=(n,e)=>{if(Zn("cluster message received from worker ",n,": ",e),n.topic&&n.data&&(e=n,n=void 0),e&&e.topic&&e.topic==="log4js:message"){Zn("received message: ",e.data);let t=$ie.deserialise(e.data);pL(t)}};vu||Xie.addListener(n=>{Ax.length=0,{pm2:Kh,disableClustering:vu,pm2InstanceVar:Qh="NODE_APP_INSTANCE"}=n,Zn(`clustering disabled ? ${vu}`),Zn(`cluster.isMaster ? ${$r&&$r.isMaster}`),Zn(`pm2 enabled ? ${Kh}`),Zn(`pm2InstanceVar = ${Qh}`),Zn(`process.env[${Qh}] = ${process.env[Qh]}`),Kh&&process.removeListener("message",Ep),$r&&$r.removeListener&&$r.removeListener("message",Ep),vu||n.disableClustering?Zn("Not listening for cluster messages, because clustering disabled."):fL()?(Zn("listening for PM2 broadcast messages"),process.on("message",Ep)):$r.isMaster?(Zn("listening for cluster messages"),$r.on("message",Ep)):Zn("not listening for messages, because we are not a master process")});mL.exports={onlyOnMaster:(n,e)=>jx()?n():e,isMaster:jx,send:n=>{jx()?pL(n):(Kh||(n.cluster={workerId:$r.worker.id,worker:process.pid}),process.send({topic:"log4js:message",data:n.serialise()}))},onMessage:n=>{Ax.push(n)}}});var wL=m((uke,vL)=>{function Uie(n){if(typeof n=="number"&&Number.isInteger(n))return n;let e={K:1024,M:1024*1024,G:1024*1024*1024},t=Object.keys(e),i=n.substr(n.length-1).toLocaleUpperCase(),r=n.substring(0,n.length-1).trim();if(t.indexOf(i)<0||!Number.isInteger(Number(r)))throw Error(`maxLogSize: "${n}" is invalid`);return r*e[i]}function Gie(n,e){let t=Object.assign({},e);return Object.keys(n).forEach(i=>{t[i]&&(t[i]=n[i](e[i]))}),t}function bL(n){return Gie({maxLogSize:Uie},n)}var yL={file:bL,fileSync:bL};vL.exports.modifyConfig=n=>yL[n.type]?yL[n.type](n):n});var xL=m((cke,DL)=>{var Qie=console.log.bind(console);function Kie(n,e){return t=>{Qie(n(t,e))}}function zie(n,e){let t=e.colouredLayout;return n.layout&&(t=e.layout(n.layout.type,n.layout)),Kie(t,n.timezoneOffset)}DL.exports.configure=zie});var SL=m(CL=>{function Vie(n,e){return t=>{process.stdout.write(`${n(t,e)} -`)}}function ene(n,e){let t=e.colouredLayout;return n.layout&&(t=e.layout(n.layout.type,n.layout)),Vie(t,n.timezoneOffset)}CL.configure=ene});var kL=m((dke,TL)=>{function tne(n,e){return t=>{process.stderr.write(`${n(t,e)} -`)}}function ine(n,e){let t=e.colouredLayout;return n.layout&&(t=e.layout(n.layout.type,n.layout)),tne(t,n.timezoneOffset)}TL.exports.configure=ine});var PL=m((gke,EL)=>{function nne(n,e,t,i){let r=i.getLevel(n),o=i.getLevel(e,i.FATAL);return s=>{let a=s.level;a.isGreaterThanOrEqualTo(r)&&a.isLessThanOrEqualTo(o)&&t(s)}}function rne(n,e,t,i){let r=t(n.appender);return nne(n.level,n.maxLevel,r,i)}EL.exports.configure=rne});var LL=m((fke,RL)=>{var _L=Ot()("log4js:categoryFilter");function one(n,e){return typeof n=="string"&&(n=[n]),t=>{_L(`Checking ${t.categoryName} against ${n}`),n.indexOf(t.categoryName)===-1&&(_L("Not excluded, sending to appender"),e(t))}}function sne(n,e,t){let i=t(n.appender);return one(n.exclude,i)}RL.exports.configure=sne});var jL=m((pke,IL)=>{var FL=Ot()("log4js:noLogFilter");function ane(n){return n.filter(t=>t!=null&&t!=="")}function lne(n,e){return t=>{FL(`Checking data: ${t.data} against filters: ${n}`),typeof n=="string"&&(n=[n]),n=ane(n);let i=new RegExp(n.join("|"),"i");(n.length===0||t.data.findIndex(r=>i.test(r))<0)&&(FL("Not excluded, sending to appender"),e(t))}}function une(n,e,t){let i=t(n.appender);return lne(n.exclude,i)}IL.exports.configure=une});var gt=m(Ox=>{"use strict";Ox.fromCallback=function(n){return Object.defineProperty(function(...e){if(typeof e[e.length-1]=="function")n.apply(this,e);else return new Promise((t,i)=>{n.call(this,...e,(r,o)=>r!=null?i(r):t(o))})},"name",{value:n.name})};Ox.fromPromise=function(n){return Object.defineProperty(function(...e){let t=e[e.length-1];if(typeof t!="function")return n.apply(this,e);n.apply(this,e.slice(0,-1)).then(i=>t(null,i),t)},"name",{value:n.name})}});var OL=m((bke,AL)=>{var Ts=require("constants"),cne=process.cwd,_p=null,hne=process.env.GRACEFUL_FS_PLATFORM||process.platform;process.cwd=function(){return _p||(_p=cne.call(process)),_p};try{process.cwd()}catch{}typeof process.chdir=="function"&&(Mx=process.chdir,process.chdir=function(n){_p=null,Mx.call(process,n)},Object.setPrototypeOf&&Object.setPrototypeOf(process.chdir,Mx));var Mx;AL.exports=dne;function dne(n){Ts.hasOwnProperty("O_SYMLINK")&&process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)&&e(n),n.lutimes||t(n),n.chown=o(n.chown),n.fchown=o(n.fchown),n.lchown=o(n.lchown),n.chmod=i(n.chmod),n.fchmod=i(n.fchmod),n.lchmod=i(n.lchmod),n.chownSync=s(n.chownSync),n.fchownSync=s(n.fchownSync),n.lchownSync=s(n.lchownSync),n.chmodSync=r(n.chmodSync),n.fchmodSync=r(n.fchmodSync),n.lchmodSync=r(n.lchmodSync),n.stat=a(n.stat),n.fstat=a(n.fstat),n.lstat=a(n.lstat),n.statSync=l(n.statSync),n.fstatSync=l(n.fstatSync),n.lstatSync=l(n.lstatSync),n.lchmod||(n.lchmod=function(c,h,d){d&&process.nextTick(d)},n.lchmodSync=function(){}),n.lchown||(n.lchown=function(c,h,d,g){g&&process.nextTick(g)},n.lchownSync=function(){}),hne==="win32"&&(n.rename=function(c){return function(h,d,g){var f=Date.now(),p=0;c(h,d,function b(v){if(v&&(v.code==="EACCES"||v.code==="EPERM")&&Date.now()-f<6e4){setTimeout(function(){n.stat(d,function(w,D){w&&w.code==="ENOENT"?c(h,d,b):g(v)})},p),p<100&&(p+=10);return}g&&g(v)})}}(n.rename)),n.read=function(c){function h(d,g,f,p,b,v){var w;if(v&&typeof v=="function"){var D=0;w=function(S,F,L){if(S&&S.code==="EAGAIN"&&D<10)return D++,c.call(n,d,g,f,p,b,w);v.apply(this,arguments)}}return c.call(n,d,g,f,p,b,w)}return Object.setPrototypeOf&&Object.setPrototypeOf(h,c),h}(n.read),n.readSync=function(c){return function(h,d,g,f,p){for(var b=0;;)try{return c.call(n,h,d,g,f,p)}catch(v){if(v.code==="EAGAIN"&&b<10){b++;continue}throw v}}}(n.readSync);function e(c){c.lchmod=function(h,d,g){c.open(h,Ts.O_WRONLY|Ts.O_SYMLINK,d,function(f,p){if(f){g&&g(f);return}c.fchmod(p,d,function(b){c.close(p,function(v){g&&g(b||v)})})})},c.lchmodSync=function(h,d){var g=c.openSync(h,Ts.O_WRONLY|Ts.O_SYMLINK,d),f=!0,p;try{p=c.fchmodSync(g,d),f=!1}finally{if(f)try{c.closeSync(g)}catch{}else c.closeSync(g)}return p}}function t(c){Ts.hasOwnProperty("O_SYMLINK")?(c.lutimes=function(h,d,g,f){c.open(h,Ts.O_SYMLINK,function(p,b){if(p){f&&f(p);return}c.futimes(b,d,g,function(v){c.close(b,function(w){f&&f(v||w)})})})},c.lutimesSync=function(h,d,g){var f=c.openSync(h,Ts.O_SYMLINK),p,b=!0;try{p=c.futimesSync(f,d,g),b=!1}finally{if(b)try{c.closeSync(f)}catch{}else c.closeSync(f)}return p}):(c.lutimes=function(h,d,g,f){f&&process.nextTick(f)},c.lutimesSync=function(){})}function i(c){return c&&function(h,d,g){return c.call(n,h,d,function(f){u(f)&&(f=null),g&&g.apply(this,arguments)})}}function r(c){return c&&function(h,d){try{return c.call(n,h,d)}catch(g){if(!u(g))throw g}}}function o(c){return c&&function(h,d,g,f){return c.call(n,h,d,g,function(p){u(p)&&(p=null),f&&f.apply(this,arguments)})}}function s(c){return c&&function(h,d,g){try{return c.call(n,h,d,g)}catch(f){if(!u(f))throw f}}}function a(c){return c&&function(h,d,g){typeof d=="function"&&(g=d,d=null);function f(p,b){b&&(b.uid<0&&(b.uid+=4294967296),b.gid<0&&(b.gid+=4294967296)),g&&g.apply(this,arguments)}return d?c.call(n,h,d,f):c.call(n,h,f)}}function l(c){return c&&function(h,d){var g=d?c.call(n,h,d):c.call(n,h);return g.uid<0&&(g.uid+=4294967296),g.gid<0&&(g.gid+=4294967296),g}}function u(c){if(!c||c.code==="ENOSYS")return!0;var h=!process.getuid||process.getuid()!==0;return!!(h&&(c.code==="EINVAL"||c.code==="EPERM"))}}});var BL=m((yke,NL)=>{var ML=require("stream").Stream;NL.exports=gne;function gne(n){return{ReadStream:e,WriteStream:t};function e(i,r){if(!(this instanceof e))return new e(i,r);ML.call(this);var o=this;this.path=i,this.fd=null,this.readable=!0,this.paused=!1,this.flags="r",this.mode=438,this.bufferSize=64*1024,r=r||{};for(var s=Object.keys(r),a=0,l=s.length;athis.end)throw new Error("start must be <= end");this.pos=this.start}if(this.fd!==null){process.nextTick(function(){o._read()});return}n.open(this.path,this.flags,this.mode,function(c,h){if(c){o.emit("error",c),o.readable=!1;return}o.fd=h,o.emit("open",h),o._read()})}function t(i,r){if(!(this instanceof t))return new t(i,r);ML.call(this),this.path=i,this.fd=null,this.writable=!0,this.flags="w",this.encoding="binary",this.mode=438,this.bytesWritten=0,r=r||{};for(var o=Object.keys(r),s=0,a=o.length;s= zero");this.pos=this.start}this.busy=!1,this._queue=[],this.fd===null&&(this._open=n.open,this._queue.push([this._open,this.path,this.flags,this.mode,void 0]),this.flush())}}});var qL=m((vke,HL)=>{"use strict";HL.exports=pne;var fne=Object.getPrototypeOf||function(n){return n.__proto__};function pne(n){if(n===null||typeof n!="object")return n;if(n instanceof Object)var e={__proto__:fne(n)};else var e=Object.create(null);return Object.getOwnPropertyNames(n).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}),e}});var Qe=m((wke,Bx)=>{var pi=require("fs"),mne=OL(),bne=BL(),yne=qL(),Rp=require("util"),pr,Lp;typeof Symbol=="function"&&typeof Symbol.for=="function"?(pr=Symbol.for("graceful-fs.queue"),Lp=Symbol.for("graceful-fs.previous")):(pr="___graceful-fs.queue",Lp="___graceful-fs.previous");function vne(){}function WL(n,e){Object.defineProperty(n,pr,{get:function(){return e}})}var zh=vne;Rp.debuglog?zh=Rp.debuglog("gfs4"):/\bgfs4\b/i.test(process.env.NODE_DEBUG||"")&&(zh=function(){var n=Rp.format.apply(Rp,arguments);n="GFS4: "+n.split(/\n/).join(` -GFS4: `),console.error(n)});pi[pr]||(YL=global[pr]||[],WL(pi,YL),pi.close=function(n){function e(t,i){return n.call(pi,t,function(r){r||ks(),typeof i=="function"&&i.apply(this,arguments)})}return Object.defineProperty(e,Lp,{value:n}),e}(pi.close),pi.closeSync=function(n){function e(t){n.apply(pi,arguments),ks()}return Object.defineProperty(e,Lp,{value:n}),e}(pi.closeSync),/\bgfs4\b/i.test(process.env.NODE_DEBUG||"")&&process.on("exit",function(){zh(pi[pr]),require("assert").equal(pi[pr].length,0)}));var YL;global[pr]||WL(global,pi[pr]);Bx.exports=Nx(yne(pi));process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH&&!pi.__patched&&(Bx.exports=Nx(pi),pi.__patched=!0);function Nx(n){mne(n),n.gracefulify=Nx,n.createReadStream=F,n.createWriteStream=L;var e=n.readFile;n.readFile=t;function t(B,N,I){return typeof N=="function"&&(I=N,N=null),M(B,N,I);function M(J,K,ae){return e(J,K,function(je){je&&(je.code==="EMFILE"||je.code==="ENFILE")?wu([M,[J,K,ae]]):(typeof ae=="function"&&ae.apply(this,arguments),ks())})}}var i=n.writeFile;n.writeFile=r;function r(B,N,I,M){return typeof I=="function"&&(M=I,I=null),J(B,N,I,M);function J(K,ae,je,_e){return i(K,ae,je,function(Ve){Ve&&(Ve.code==="EMFILE"||Ve.code==="ENFILE")?wu([J,[K,ae,je,_e]]):(typeof _e=="function"&&_e.apply(this,arguments),ks())})}}var o=n.appendFile;o&&(n.appendFile=s);function s(B,N,I,M){return typeof I=="function"&&(M=I,I=null),J(B,N,I,M);function J(K,ae,je,_e){return o(K,ae,je,function(Ve){Ve&&(Ve.code==="EMFILE"||Ve.code==="ENFILE")?wu([J,[K,ae,je,_e]]):(typeof _e=="function"&&_e.apply(this,arguments),ks())})}}var a=n.copyFile;a&&(n.copyFile=l);function l(B,N,I,M){return typeof I=="function"&&(M=I,I=0),a(B,N,I,function(J){J&&(J.code==="EMFILE"||J.code==="ENFILE")?wu([a,[B,N,I,M]]):(typeof M=="function"&&M.apply(this,arguments),ks())})}var u=n.readdir;n.readdir=c;function c(B,N,I){var M=[B];return typeof N!="function"?M.push(N):I=N,M.push(J),h(M);function J(K,ae){ae&&ae.sort&&ae.sort(),K&&(K.code==="EMFILE"||K.code==="ENFILE")?wu([h,[M]]):(typeof I=="function"&&I.apply(this,arguments),ks())}}function h(B){return u.apply(n,B)}if(process.version.substr(0,4)==="v0.8"){var d=bne(n);v=d.ReadStream,D=d.WriteStream}var g=n.ReadStream;g&&(v.prototype=Object.create(g.prototype),v.prototype.open=w);var f=n.WriteStream;f&&(D.prototype=Object.create(f.prototype),D.prototype.open=S),Object.defineProperty(n,"ReadStream",{get:function(){return v},set:function(B){v=B},enumerable:!0,configurable:!0}),Object.defineProperty(n,"WriteStream",{get:function(){return D},set:function(B){D=B},enumerable:!0,configurable:!0});var p=v;Object.defineProperty(n,"FileReadStream",{get:function(){return p},set:function(B){p=B},enumerable:!0,configurable:!0});var b=D;Object.defineProperty(n,"FileWriteStream",{get:function(){return b},set:function(B){b=B},enumerable:!0,configurable:!0});function v(B,N){return this instanceof v?(g.apply(this,arguments),this):v.apply(Object.create(v.prototype),arguments)}function w(){var B=this;W(B.path,B.flags,B.mode,function(N,I){N?(B.autoClose&&B.destroy(),B.emit("error",N)):(B.fd=I,B.emit("open",I),B.read())})}function D(B,N){return this instanceof D?(f.apply(this,arguments),this):D.apply(Object.create(D.prototype),arguments)}function S(){var B=this;W(B.path,B.flags,B.mode,function(N,I){N?(B.destroy(),B.emit("error",N)):(B.fd=I,B.emit("open",I))})}function F(B,N){return new n.ReadStream(B,N)}function L(B,N){return new n.WriteStream(B,N)}var j=n.open;n.open=W;function W(B,N,I,M){return typeof I=="function"&&(M=I,I=null),J(B,N,I,M);function J(K,ae,je,_e){return j(K,ae,je,function(Ve,Et){Ve&&(Ve.code==="EMFILE"||Ve.code==="ENFILE")?wu([J,[K,ae,je,_e]]):(typeof _e=="function"&&_e.apply(this,arguments),ks())})}}return n}function wu(n){zh("ENQUEUE",n[0].name,n[1]),pi[pr].push(n)}function ks(){var n=pi[pr].shift();n&&(zh("RETRY",n[0].name,n[1]),n[0].apply(null,n[1]))}});var Xa=m(Es=>{"use strict";var ZL=gt().fromCallback,Pn=Qe(),wne=["access","appendFile","chmod","chown","close","copyFile","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","symlink","truncate","unlink","utimes","writeFile"].filter(n=>typeof Pn[n]=="function");Object.assign(Es,Pn);wne.forEach(n=>{Es[n]=ZL(Pn[n])});Es.realpath.native=ZL(Pn.realpath.native);Es.exists=function(n,e){return typeof e=="function"?Pn.exists(n,e):new Promise(t=>Pn.exists(n,t))};Es.read=function(n,e,t,i,r,o){return typeof o=="function"?Pn.read(n,e,t,i,r,o):new Promise((s,a)=>{Pn.read(n,e,t,i,r,(l,u,c)=>{if(l)return a(l);s({bytesRead:u,buffer:c})})})};Es.write=function(n,e,...t){return typeof t[t.length-1]=="function"?Pn.write(n,e,...t):new Promise((i,r)=>{Pn.write(n,e,...t,(o,s,a)=>{if(o)return r(o);i({bytesWritten:s,buffer:a})})})};typeof Pn.writev=="function"&&(Es.writev=function(n,e,...t){return typeof t[t.length-1]=="function"?Pn.writev(n,e,...t):new Promise((i,r)=>{Pn.writev(n,e,...t,(o,s,a)=>{if(o)return r(o);i({bytesWritten:s,buffers:a})})})})});var $L=m((xke,JL)=>{"use strict";var Dne=require("path");JL.exports.checkPath=function(e){if(process.platform==="win32"&&/[<>:"|?*]/.test(e.replace(Dne.parse(e).root,""))){let i=new Error(`Path contains invalid characters: ${e}`);throw i.code="EINVAL",i}}});var QL=m((Cke,Hx)=>{"use strict";var XL=Xa(),{checkPath:UL}=$L(),GL=n=>{let e={mode:511};return typeof n=="number"?n:ge(ge({},e),n).mode};Hx.exports.makeDir=async(n,e)=>(UL(n),XL.mkdir(n,{mode:GL(e),recursive:!0}));Hx.exports.makeDirSync=(n,e)=>(UL(n),XL.mkdirSync(n,{mode:GL(e),recursive:!0}))});var mr=m((Ske,KL)=>{"use strict";var xne=gt().fromPromise,{makeDir:Cne,makeDirSync:qx}=QL(),Yx=xne(Cne);KL.exports={mkdirs:Yx,mkdirsSync:qx,mkdirp:Yx,mkdirpSync:qx,ensureDir:Yx,ensureDirSync:qx}});var Wx=m((Tke,zL)=>{"use strict";var Du=Qe();function Sne(n,e,t,i){Du.open(n,"r+",(r,o)=>{if(r)return i(r);Du.futimes(o,e,t,s=>{Du.close(o,a=>{i&&i(s||a)})})})}function Tne(n,e,t){let i=Du.openSync(n,"r+");return Du.futimesSync(i,e,t),Du.closeSync(i)}zL.exports={utimesMillis:Sne,utimesMillisSync:Tne}});var Ua=m((kke,tF)=>{"use strict";var xu=Xa(),si=require("path"),kne=require("util");function Ene(n,e,t){let i=t.dereference?r=>xu.stat(r,{bigint:!0}):r=>xu.lstat(r,{bigint:!0});return Promise.all([i(n),i(e).catch(r=>{if(r.code==="ENOENT")return null;throw r})]).then(([r,o])=>({srcStat:r,destStat:o}))}function Pne(n,e,t){let i,r=t.dereference?s=>xu.statSync(s,{bigint:!0}):s=>xu.lstatSync(s,{bigint:!0}),o=r(n);try{i=r(e)}catch(s){if(s.code==="ENOENT")return{srcStat:o,destStat:null};throw s}return{srcStat:o,destStat:i}}function _ne(n,e,t,i,r){kne.callbackify(Ene)(n,e,i,(o,s)=>{if(o)return r(o);let{srcStat:a,destStat:l}=s;if(l){if(Vh(a,l)){let u=si.basename(n),c=si.basename(e);return t==="move"&&u!==c&&u.toLowerCase()===c.toLowerCase()?r(null,{srcStat:a,destStat:l,isChangingCase:!0}):r(new Error("Source and destination must not be the same."))}if(a.isDirectory()&&!l.isDirectory())return r(new Error(`Cannot overwrite non-directory '${e}' with directory '${n}'.`));if(!a.isDirectory()&&l.isDirectory())return r(new Error(`Cannot overwrite directory '${e}' with non-directory '${n}'.`))}return a.isDirectory()&&Zx(n,e)?r(new Error(Fp(n,e,t))):r(null,{srcStat:a,destStat:l})})}function Rne(n,e,t,i){let{srcStat:r,destStat:o}=Pne(n,e,i);if(o){if(Vh(r,o)){let s=si.basename(n),a=si.basename(e);if(t==="move"&&s!==a&&s.toLowerCase()===a.toLowerCase())return{srcStat:r,destStat:o,isChangingCase:!0};throw new Error("Source and destination must not be the same.")}if(r.isDirectory()&&!o.isDirectory())throw new Error(`Cannot overwrite non-directory '${e}' with directory '${n}'.`);if(!r.isDirectory()&&o.isDirectory())throw new Error(`Cannot overwrite directory '${e}' with non-directory '${n}'.`)}if(r.isDirectory()&&Zx(n,e))throw new Error(Fp(n,e,t));return{srcStat:r,destStat:o}}function VL(n,e,t,i,r){let o=si.resolve(si.dirname(n)),s=si.resolve(si.dirname(t));if(s===o||s===si.parse(s).root)return r();xu.stat(s,{bigint:!0},(a,l)=>a?a.code==="ENOENT"?r():r(a):Vh(e,l)?r(new Error(Fp(n,t,i))):VL(n,e,s,i,r))}function eF(n,e,t,i){let r=si.resolve(si.dirname(n)),o=si.resolve(si.dirname(t));if(o===r||o===si.parse(o).root)return;let s;try{s=xu.statSync(o,{bigint:!0})}catch(a){if(a.code==="ENOENT")return;throw a}if(Vh(e,s))throw new Error(Fp(n,t,i));return eF(n,e,o,i)}function Vh(n,e){return e.ino&&e.dev&&e.ino===n.ino&&e.dev===n.dev}function Zx(n,e){let t=si.resolve(n).split(si.sep).filter(r=>r),i=si.resolve(e).split(si.sep).filter(r=>r);return t.reduce((r,o,s)=>r&&i[s]===o,!0)}function Fp(n,e,t){return`Cannot ${t} '${n}' to a subdirectory of itself, '${e}'.`}tF.exports={checkPaths:_ne,checkPathsSync:Rne,checkParentPaths:VL,checkParentPathsSync:eF,isSrcSubdir:Zx,areIdentical:Vh}});var sF=m((Eke,oF)=>{"use strict";var Ci=Qe(),ed=require("path"),Lne=mr().mkdirsSync,Fne=Wx().utimesMillisSync,td=Ua();function Ine(n,e,t){typeof t=="function"&&(t={filter:t}),t=t||{},t.clobber="clobber"in t?!!t.clobber:!0,t.overwrite="overwrite"in t?!!t.overwrite:t.clobber,t.preserveTimestamps&&process.arch==="ia32"&&console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended; - - see https://github.com/jprichardson/node-fs-extra/issues/269`);let{srcStat:i,destStat:r}=td.checkPathsSync(n,e,"copy",t);return td.checkParentPathsSync(n,i,e,"copy"),jne(r,n,e,t)}function jne(n,e,t,i){if(i.filter&&!i.filter(e,t))return;let r=ed.dirname(t);return Ci.existsSync(r)||Lne(r),iF(n,e,t,i)}function Ane(n,e,t,i){if(!(i.filter&&!i.filter(e,t)))return iF(n,e,t,i)}function iF(n,e,t,i){let o=(i.dereference?Ci.statSync:Ci.lstatSync)(e);if(o.isDirectory())return Yne(o,n,e,t,i);if(o.isFile()||o.isCharacterDevice()||o.isBlockDevice())return One(o,n,e,t,i);if(o.isSymbolicLink())return Jne(n,e,t,i);throw o.isSocket()?new Error(`Cannot copy a socket file: ${e}`):o.isFIFO()?new Error(`Cannot copy a FIFO pipe: ${e}`):new Error(`Unknown file: ${e}`)}function One(n,e,t,i,r){return e?Mne(n,t,i,r):nF(n,t,i,r)}function Mne(n,e,t,i){if(i.overwrite)return Ci.unlinkSync(t),nF(n,e,t,i);if(i.errorOnExist)throw new Error(`'${t}' already exists`)}function nF(n,e,t,i){return Ci.copyFileSync(e,t),i.preserveTimestamps&&Nne(n.mode,e,t),Jx(t,n.mode)}function Nne(n,e,t){return Bne(n)&&Hne(t,n),qne(e,t)}function Bne(n){return(n&128)===0}function Hne(n,e){return Jx(n,e|128)}function Jx(n,e){return Ci.chmodSync(n,e)}function qne(n,e){let t=Ci.statSync(n);return Fne(e,t.atime,t.mtime)}function Yne(n,e,t,i,r){return e?rF(t,i,r):Wne(n.mode,t,i,r)}function Wne(n,e,t,i){return Ci.mkdirSync(t),rF(e,t,i),Jx(t,n)}function rF(n,e,t){Ci.readdirSync(n).forEach(i=>Zne(i,n,e,t))}function Zne(n,e,t,i){let r=ed.join(e,n),o=ed.join(t,n),{destStat:s}=td.checkPathsSync(r,o,"copy",i);return Ane(s,r,o,i)}function Jne(n,e,t,i){let r=Ci.readlinkSync(e);if(i.dereference&&(r=ed.resolve(process.cwd(),r)),n){let o;try{o=Ci.readlinkSync(t)}catch(s){if(s.code==="EINVAL"||s.code==="UNKNOWN")return Ci.symlinkSync(r,t);throw s}if(i.dereference&&(o=ed.resolve(process.cwd(),o)),td.isSrcSubdir(r,o))throw new Error(`Cannot copy '${r}' to a subdirectory of itself, '${o}'.`);if(Ci.statSync(t).isDirectory()&&td.isSrcSubdir(o,r))throw new Error(`Cannot overwrite '${o}' with '${r}'.`);return $ne(r,t)}else return Ci.symlinkSync(r,t)}function $ne(n,e){return Ci.unlinkSync(e),Ci.symlinkSync(n,e)}oF.exports=Ine});var $x=m((Pke,aF)=>{"use strict";aF.exports={copySync:sF()}});var Ps=m((_ke,uF)=>{"use strict";var Xne=gt().fromPromise,lF=Xa();function Une(n){return lF.access(n).then(()=>!0).catch(()=>!1)}uF.exports={pathExists:Xne(Une),pathExistsSync:lF.existsSync}});var bF=m((Rke,mF)=>{"use strict";var rn=Qe(),id=require("path"),Gne=mr().mkdirs,Qne=Ps().pathExists,Kne=Wx().utimesMillis,nd=Ua();function zne(n,e,t,i){typeof t=="function"&&!i?(i=t,t={}):typeof t=="function"&&(t={filter:t}),i=i||function(){},t=t||{},t.clobber="clobber"in t?!!t.clobber:!0,t.overwrite="overwrite"in t?!!t.overwrite:t.clobber,t.preserveTimestamps&&process.arch==="ia32"&&console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended; - - see https://github.com/jprichardson/node-fs-extra/issues/269`),nd.checkPaths(n,e,"copy",t,(r,o)=>{if(r)return i(r);let{srcStat:s,destStat:a}=o;nd.checkParentPaths(n,s,e,"copy",l=>l?i(l):t.filter?dF(cF,a,n,e,t,i):cF(a,n,e,t,i))})}function cF(n,e,t,i,r){let o=id.dirname(t);Qne(o,(s,a)=>{if(s)return r(s);if(a)return Ip(n,e,t,i,r);Gne(o,l=>l?r(l):Ip(n,e,t,i,r))})}function dF(n,e,t,i,r,o){Promise.resolve(r.filter(t,i)).then(s=>s?n(e,t,i,r,o):o(),s=>o(s))}function Vne(n,e,t,i,r){return i.filter?dF(Ip,n,e,t,i,r):Ip(n,e,t,i,r)}function Ip(n,e,t,i,r){(i.dereference?rn.stat:rn.lstat)(e,(s,a)=>s?r(s):a.isDirectory()?sre(a,n,e,t,i,r):a.isFile()||a.isCharacterDevice()||a.isBlockDevice()?ere(a,n,e,t,i,r):a.isSymbolicLink()?ure(n,e,t,i,r):a.isSocket()?r(new Error(`Cannot copy a socket file: ${e}`)):a.isFIFO()?r(new Error(`Cannot copy a FIFO pipe: ${e}`)):r(new Error(`Unknown file: ${e}`)))}function ere(n,e,t,i,r,o){return e?tre(n,t,i,r,o):gF(n,t,i,r,o)}function tre(n,e,t,i,r){if(i.overwrite)rn.unlink(t,o=>o?r(o):gF(n,e,t,i,r));else return i.errorOnExist?r(new Error(`'${t}' already exists`)):r()}function gF(n,e,t,i,r){rn.copyFile(e,t,o=>o?r(o):i.preserveTimestamps?ire(n.mode,e,t,r):jp(t,n.mode,r))}function ire(n,e,t,i){return nre(n)?rre(t,n,r=>r?i(r):hF(n,e,t,i)):hF(n,e,t,i)}function nre(n){return(n&128)===0}function rre(n,e,t){return jp(n,e|128,t)}function hF(n,e,t,i){ore(e,t,r=>r?i(r):jp(t,n,i))}function jp(n,e,t){return rn.chmod(n,e,t)}function ore(n,e,t){rn.stat(n,(i,r)=>i?t(i):Kne(e,r.atime,r.mtime,t))}function sre(n,e,t,i,r,o){return e?fF(t,i,r,o):are(n.mode,t,i,r,o)}function are(n,e,t,i,r){rn.mkdir(t,o=>{if(o)return r(o);fF(e,t,i,s=>s?r(s):jp(t,n,r))})}function fF(n,e,t,i){rn.readdir(n,(r,o)=>r?i(r):pF(o,n,e,t,i))}function pF(n,e,t,i,r){let o=n.pop();return o?lre(n,o,e,t,i,r):r()}function lre(n,e,t,i,r,o){let s=id.join(t,e),a=id.join(i,e);nd.checkPaths(s,a,"copy",r,(l,u)=>{if(l)return o(l);let{destStat:c}=u;Vne(c,s,a,r,h=>h?o(h):pF(n,t,i,r,o))})}function ure(n,e,t,i,r){rn.readlink(e,(o,s)=>{if(o)return r(o);if(i.dereference&&(s=id.resolve(process.cwd(),s)),n)rn.readlink(t,(a,l)=>a?a.code==="EINVAL"||a.code==="UNKNOWN"?rn.symlink(s,t,r):r(a):(i.dereference&&(l=id.resolve(process.cwd(),l)),nd.isSrcSubdir(s,l)?r(new Error(`Cannot copy '${s}' to a subdirectory of itself, '${l}'.`)):n.isDirectory()&&nd.isSrcSubdir(l,s)?r(new Error(`Cannot overwrite '${l}' with '${s}'.`)):cre(s,t,r)));else return rn.symlink(s,t,r)})}function cre(n,e,t){rn.unlink(e,i=>i?t(i):rn.symlink(n,e,t))}mF.exports=zne});var Xx=m((Lke,yF)=>{"use strict";var hre=gt().fromCallback;yF.exports={copy:hre(bF())}});var EF=m((Fke,kF)=>{"use strict";var vF=Qe(),CF=require("path"),ot=require("assert"),rd=process.platform==="win32";function SF(n){["unlink","chmod","stat","lstat","rmdir","readdir"].forEach(t=>{n[t]=n[t]||vF[t],t=t+"Sync",n[t]=n[t]||vF[t]}),n.maxBusyTries=n.maxBusyTries||3}function Ux(n,e,t){let i=0;typeof e=="function"&&(t=e,e={}),ot(n,"rimraf: missing path"),ot.strictEqual(typeof n,"string","rimraf: path should be a string"),ot.strictEqual(typeof t,"function","rimraf: callback function required"),ot(e,"rimraf: invalid options argument provided"),ot.strictEqual(typeof e,"object","rimraf: options should be object"),SF(e),wF(n,e,function r(o){if(o){if((o.code==="EBUSY"||o.code==="ENOTEMPTY"||o.code==="EPERM")&&iwF(n,e,r),s)}o.code==="ENOENT"&&(o=null)}t(o)})}function wF(n,e,t){ot(n),ot(e),ot(typeof t=="function"),e.lstat(n,(i,r)=>{if(i&&i.code==="ENOENT")return t(null);if(i&&i.code==="EPERM"&&rd)return DF(n,e,i,t);if(r&&r.isDirectory())return Ap(n,e,i,t);e.unlink(n,o=>{if(o){if(o.code==="ENOENT")return t(null);if(o.code==="EPERM")return rd?DF(n,e,o,t):Ap(n,e,o,t);if(o.code==="EISDIR")return Ap(n,e,o,t)}return t(o)})})}function DF(n,e,t,i){ot(n),ot(e),ot(typeof i=="function"),e.chmod(n,438,r=>{r?i(r.code==="ENOENT"?null:t):e.stat(n,(o,s)=>{o?i(o.code==="ENOENT"?null:t):s.isDirectory()?Ap(n,e,t,i):e.unlink(n,i)})})}function xF(n,e,t){let i;ot(n),ot(e);try{e.chmodSync(n,438)}catch(r){if(r.code==="ENOENT")return;throw t}try{i=e.statSync(n)}catch(r){if(r.code==="ENOENT")return;throw t}i.isDirectory()?Op(n,e,t):e.unlinkSync(n)}function Ap(n,e,t,i){ot(n),ot(e),ot(typeof i=="function"),e.rmdir(n,r=>{r&&(r.code==="ENOTEMPTY"||r.code==="EEXIST"||r.code==="EPERM")?dre(n,e,i):r&&r.code==="ENOTDIR"?i(t):i(r)})}function dre(n,e,t){ot(n),ot(e),ot(typeof t=="function"),e.readdir(n,(i,r)=>{if(i)return t(i);let o=r.length,s;if(o===0)return e.rmdir(n,t);r.forEach(a=>{Ux(CF.join(n,a),e,l=>{if(!s){if(l)return t(s=l);--o===0&&e.rmdir(n,t)}})})})}function TF(n,e){let t;e=e||{},SF(e),ot(n,"rimraf: missing path"),ot.strictEqual(typeof n,"string","rimraf: path should be a string"),ot(e,"rimraf: missing options"),ot.strictEqual(typeof e,"object","rimraf: options should be object");try{t=e.lstatSync(n)}catch(i){if(i.code==="ENOENT")return;i.code==="EPERM"&&rd&&xF(n,e,i)}try{t&&t.isDirectory()?Op(n,e,null):e.unlinkSync(n)}catch(i){if(i.code==="ENOENT")return;if(i.code==="EPERM")return rd?xF(n,e,i):Op(n,e,i);if(i.code!=="EISDIR")throw i;Op(n,e,i)}}function Op(n,e,t){ot(n),ot(e);try{e.rmdirSync(n)}catch(i){if(i.code==="ENOTDIR")throw t;if(i.code==="ENOTEMPTY"||i.code==="EEXIST"||i.code==="EPERM")gre(n,e);else if(i.code!=="ENOENT")throw i}}function gre(n,e){if(ot(n),ot(e),e.readdirSync(n).forEach(t=>TF(CF.join(n,t),e)),rd){let t=Date.now();do try{return e.rmdirSync(n,e)}catch{}while(Date.now()-t<500)}else return e.rmdirSync(n,e)}kF.exports=Ux;Ux.sync=TF});var od=m((Ike,_F)=>{"use strict";var Mp=Qe(),fre=gt().fromCallback,PF=EF();function pre(n,e){if(Mp.rm)return Mp.rm(n,{recursive:!0,force:!0},e);PF(n,e)}function mre(n){if(Mp.rmSync)return Mp.rmSync(n,{recursive:!0,force:!0});PF.sync(n)}_F.exports={remove:fre(pre),removeSync:mre}});var MF=m((jke,OF)=>{"use strict";var bre=gt().fromPromise,FF=Xa(),IF=require("path"),jF=mr(),AF=od(),RF=bre(async function(e){let t;try{t=await FF.readdir(e)}catch{return jF.mkdirs(e)}return Promise.all(t.map(i=>AF.remove(IF.join(e,i))))});function LF(n){let e;try{e=FF.readdirSync(n)}catch{return jF.mkdirsSync(n)}e.forEach(t=>{t=IF.join(n,t),AF.removeSync(t)})}OF.exports={emptyDirSync:LF,emptydirSync:LF,emptyDir:RF,emptydir:RF}});var qF=m((Ake,HF)=>{"use strict";var yre=gt().fromCallback,NF=require("path"),_s=Qe(),BF=mr();function vre(n,e){function t(){_s.writeFile(n,"",i=>{if(i)return e(i);e()})}_s.stat(n,(i,r)=>{if(!i&&r.isFile())return e();let o=NF.dirname(n);_s.stat(o,(s,a)=>{if(s)return s.code==="ENOENT"?BF.mkdirs(o,l=>{if(l)return e(l);t()}):e(s);a.isDirectory()?t():_s.readdir(o,l=>{if(l)return e(l)})})})}function wre(n){let e;try{e=_s.statSync(n)}catch{}if(e&&e.isFile())return;let t=NF.dirname(n);try{_s.statSync(t).isDirectory()||_s.readdirSync(t)}catch(i){if(i&&i.code==="ENOENT")BF.mkdirsSync(t);else throw i}_s.writeFileSync(n,"")}HF.exports={createFile:yre(vre),createFileSync:wre}});var $F=m((Oke,JF)=>{"use strict";var Dre=gt().fromCallback,YF=require("path"),Rs=Qe(),WF=mr(),xre=Ps().pathExists,{areIdentical:ZF}=Ua();function Cre(n,e,t){function i(r,o){Rs.link(r,o,s=>{if(s)return t(s);t(null)})}Rs.lstat(e,(r,o)=>{Rs.lstat(n,(s,a)=>{if(s)return s.message=s.message.replace("lstat","ensureLink"),t(s);if(o&&ZF(a,o))return t(null);let l=YF.dirname(e);xre(l,(u,c)=>{if(u)return t(u);if(c)return i(n,e);WF.mkdirs(l,h=>{if(h)return t(h);i(n,e)})})})})}function Sre(n,e){let t;try{t=Rs.lstatSync(e)}catch{}try{let o=Rs.lstatSync(n);if(t&&ZF(o,t))return}catch(o){throw o.message=o.message.replace("lstat","ensureLink"),o}let i=YF.dirname(e);return Rs.existsSync(i)||WF.mkdirsSync(i),Rs.linkSync(n,e)}JF.exports={createLink:Dre(Cre),createLinkSync:Sre}});var UF=m((Mke,XF)=>{"use strict";var Ls=require("path"),sd=Qe(),Tre=Ps().pathExists;function kre(n,e,t){if(Ls.isAbsolute(n))return sd.lstat(n,i=>i?(i.message=i.message.replace("lstat","ensureSymlink"),t(i)):t(null,{toCwd:n,toDst:n}));{let i=Ls.dirname(e),r=Ls.join(i,n);return Tre(r,(o,s)=>o?t(o):s?t(null,{toCwd:r,toDst:n}):sd.lstat(n,a=>a?(a.message=a.message.replace("lstat","ensureSymlink"),t(a)):t(null,{toCwd:n,toDst:Ls.relative(i,n)})))}}function Ere(n,e){let t;if(Ls.isAbsolute(n)){if(t=sd.existsSync(n),!t)throw new Error("absolute srcpath does not exist");return{toCwd:n,toDst:n}}else{let i=Ls.dirname(e),r=Ls.join(i,n);if(t=sd.existsSync(r),t)return{toCwd:r,toDst:n};if(t=sd.existsSync(n),!t)throw new Error("relative srcpath does not exist");return{toCwd:n,toDst:Ls.relative(i,n)}}}XF.exports={symlinkPaths:kre,symlinkPathsSync:Ere}});var KF=m((Nke,QF)=>{"use strict";var GF=Qe();function Pre(n,e,t){if(t=typeof e=="function"?e:t,e=typeof e=="function"?!1:e,e)return t(null,e);GF.lstat(n,(i,r)=>{if(i)return t(null,"file");e=r&&r.isDirectory()?"dir":"file",t(null,e)})}function _re(n,e){let t;if(e)return e;try{t=GF.lstatSync(n)}catch{return"file"}return t&&t.isDirectory()?"dir":"file"}QF.exports={symlinkType:Pre,symlinkTypeSync:_re}});var oI=m((Bke,rI)=>{"use strict";var Rre=gt().fromCallback,VF=require("path"),br=Xa(),eI=mr(),Lre=eI.mkdirs,Fre=eI.mkdirsSync,tI=UF(),Ire=tI.symlinkPaths,jre=tI.symlinkPathsSync,iI=KF(),Are=iI.symlinkType,Ore=iI.symlinkTypeSync,Mre=Ps().pathExists,{areIdentical:nI}=Ua();function Nre(n,e,t,i){i=typeof t=="function"?t:i,t=typeof t=="function"?!1:t,br.lstat(e,(r,o)=>{!r&&o.isSymbolicLink()?Promise.all([br.stat(n),br.stat(e)]).then(([s,a])=>{if(nI(s,a))return i(null);zF(n,e,t,i)}):zF(n,e,t,i)})}function zF(n,e,t,i){Ire(n,e,(r,o)=>{if(r)return i(r);n=o.toDst,Are(o.toCwd,t,(s,a)=>{if(s)return i(s);let l=VF.dirname(e);Mre(l,(u,c)=>{if(u)return i(u);if(c)return br.symlink(n,e,a,i);Lre(l,h=>{if(h)return i(h);br.symlink(n,e,a,i)})})})})}function Bre(n,e,t){let i;try{i=br.lstatSync(e)}catch{}if(i&&i.isSymbolicLink()){let a=br.statSync(n),l=br.statSync(e);if(nI(a,l))return}let r=jre(n,e);n=r.toDst,t=Ore(r.toCwd,t);let o=VF.dirname(e);return br.existsSync(o)||Fre(o),br.symlinkSync(n,e,t)}rI.exports={createSymlink:Rre(Nre),createSymlinkSync:Bre}});var aI=m((Hke,sI)=>{"use strict";var Np=qF(),Bp=$F(),Hp=oI();sI.exports={createFile:Np.createFile,createFileSync:Np.createFileSync,ensureFile:Np.createFile,ensureFileSync:Np.createFileSync,createLink:Bp.createLink,createLinkSync:Bp.createLinkSync,ensureLink:Bp.createLink,ensureLinkSync:Bp.createLinkSync,createSymlink:Hp.createSymlink,createSymlinkSync:Hp.createSymlinkSync,ensureSymlink:Hp.createSymlink,ensureSymlinkSync:Hp.createSymlinkSync}});var Cu=m((qke,lI)=>{function Hre(n,{EOL:e=` -`,finalEOL:t=!0,replacer:i=null,spaces:r}={}){let o=t?e:"";return JSON.stringify(n,i,r).replace(/\n/g,e)+o}function qre(n){return Buffer.isBuffer(n)&&(n=n.toString("utf8")),n.replace(/^\uFEFF/,"")}lI.exports={stringify:Hre,stripBom:qre}});var Gx=m((Yke,hI)=>{var Su;try{Su=Qe()}catch{Su=require("fs")}var qp=gt(),{stringify:uI,stripBom:cI}=Cu();async function Yre(n,e={}){typeof e=="string"&&(e={encoding:e});let t=e.fs||Su,i="throws"in e?e.throws:!0,r=await qp.fromCallback(t.readFile)(n,e);r=cI(r);let o;try{o=JSON.parse(r,e?e.reviver:null)}catch(s){if(i)throw s.message=`${n}: ${s.message}`,s;return null}return o}var Wre=qp.fromPromise(Yre);function Zre(n,e={}){typeof e=="string"&&(e={encoding:e});let t=e.fs||Su,i="throws"in e?e.throws:!0;try{let r=t.readFileSync(n,e);return r=cI(r),JSON.parse(r,e.reviver)}catch(r){if(i)throw r.message=`${n}: ${r.message}`,r;return null}}async function Jre(n,e,t={}){let i=t.fs||Su,r=uI(e,t);await qp.fromCallback(i.writeFile)(n,r,t)}var $re=qp.fromPromise(Jre);function Xre(n,e,t={}){let i=t.fs||Su,r=uI(e,t);return i.writeFileSync(n,r,t)}var Ure={readFile:Wre,readFileSync:Zre,writeFile:$re,writeFileSync:Xre};hI.exports=Ure});var gI=m((Wke,dI)=>{"use strict";var Yp=Gx();dI.exports={readJson:Yp.readFile,readJsonSync:Yp.readFileSync,writeJson:Yp.writeFile,writeJsonSync:Yp.writeFileSync}});var Wp=m((Zke,mI)=>{"use strict";var Gre=gt().fromCallback,ad=Qe(),fI=require("path"),pI=mr(),Qre=Ps().pathExists;function Kre(n,e,t,i){typeof t=="function"&&(i=t,t="utf8");let r=fI.dirname(n);Qre(r,(o,s)=>{if(o)return i(o);if(s)return ad.writeFile(n,e,t,i);pI.mkdirs(r,a=>{if(a)return i(a);ad.writeFile(n,e,t,i)})})}function zre(n,...e){let t=fI.dirname(n);if(ad.existsSync(t))return ad.writeFileSync(n,...e);pI.mkdirsSync(t),ad.writeFileSync(n,...e)}mI.exports={outputFile:Gre(Kre),outputFileSync:zre}});var yI=m((Jke,bI)=>{"use strict";var{stringify:Vre}=Cu(),{outputFile:eoe}=Wp();async function toe(n,e,t={}){let i=Vre(e,t);await eoe(n,i,t)}bI.exports=toe});var wI=m(($ke,vI)=>{"use strict";var{stringify:ioe}=Cu(),{outputFileSync:noe}=Wp();function roe(n,e,t){let i=ioe(e,t);noe(n,i,t)}vI.exports=roe});var xI=m((Xke,DI)=>{"use strict";var ooe=gt().fromPromise,qi=gI();qi.outputJson=ooe(yI());qi.outputJsonSync=wI();qi.outputJSON=qi.outputJson;qi.outputJSONSync=qi.outputJsonSync;qi.writeJSON=qi.writeJson;qi.writeJSONSync=qi.writeJsonSync;qi.readJSON=qi.readJson;qi.readJSONSync=qi.readJsonSync;DI.exports=qi});var EI=m((Uke,kI)=>{"use strict";var SI=Qe(),Kx=require("path"),soe=$x().copySync,TI=od().removeSync,aoe=mr().mkdirpSync,CI=Ua();function loe(n,e,t){t=t||{};let i=t.overwrite||t.clobber||!1,{srcStat:r,isChangingCase:o=!1}=CI.checkPathsSync(n,e,"move",t);return CI.checkParentPathsSync(n,r,e,"move"),uoe(e)||aoe(Kx.dirname(e)),coe(n,e,i,o)}function uoe(n){let e=Kx.dirname(n);return Kx.parse(e).root===e}function coe(n,e,t,i){if(i)return Qx(n,e,t);if(t)return TI(e),Qx(n,e,t);if(SI.existsSync(e))throw new Error("dest already exists.");return Qx(n,e,t)}function Qx(n,e,t){try{SI.renameSync(n,e)}catch(i){if(i.code!=="EXDEV")throw i;return hoe(n,e,t)}}function hoe(n,e,t){return soe(n,e,{overwrite:t,errorOnExist:!0}),TI(n)}kI.exports=loe});var _I=m((Gke,PI)=>{"use strict";PI.exports={moveSync:EI()}});var jI=m((Qke,II)=>{"use strict";var doe=Qe(),Vx=require("path"),goe=Xx().copy,FI=od().remove,foe=mr().mkdirp,poe=Ps().pathExists,RI=Ua();function moe(n,e,t,i){typeof t=="function"&&(i=t,t={});let r=t.overwrite||t.clobber||!1;RI.checkPaths(n,e,"move",t,(o,s)=>{if(o)return i(o);let{srcStat:a,isChangingCase:l=!1}=s;RI.checkParentPaths(n,a,e,"move",u=>{if(u)return i(u);if(boe(e))return LI(n,e,r,l,i);foe(Vx.dirname(e),c=>c?i(c):LI(n,e,r,l,i))})})}function boe(n){let e=Vx.dirname(n);return Vx.parse(e).root===e}function LI(n,e,t,i,r){if(i)return zx(n,e,t,r);if(t)return FI(e,o=>o?r(o):zx(n,e,t,r));poe(e,(o,s)=>o?r(o):s?r(new Error("dest already exists.")):zx(n,e,t,r))}function zx(n,e,t,i){doe.rename(n,e,r=>r?r.code!=="EXDEV"?i(r):yoe(n,e,t,i):i())}function yoe(n,e,t,i){goe(n,e,{overwrite:t,errorOnExist:!0},o=>o?i(o):FI(n,i))}II.exports=moe});var OI=m((Kke,AI)=>{"use strict";var voe=gt().fromCallback;AI.exports={move:voe(jI())}});var eC=m((zke,MI)=>{"use strict";MI.exports=ge(ge(ge(ge(ge(ge(ge(ge(ge(ge(ge(ge({},Xa()),$x()),Xx()),MF()),aI()),xI()),mr()),_I()),OI()),Wp()),Ps()),od())});var BI=m((Vke,NI)=>{NI.exports=()=>new Date});var qI=m((eEe,HI)=>{var woe=Ot()("streamroller:fileNameFormatter"),Doe=require("path"),xoe=".gz",Coe=".";HI.exports=({file:n,keepFileExt:e,needsIndex:t,alwaysIncludeDate:i,compress:r,fileNameSep:o})=>{let s=o||Coe,a=Doe.join(n.dir,n.name),l=g=>g+n.ext,u=(g,f,p)=>(t||!p)&&f?g+s+f:g,c=(g,f,p)=>(f>0||i)&&p?g+s+p:g,h=(g,f)=>f&&r?g+xoe:g,d=e?[c,u,l,h]:[l,c,u,h];return({date:g,index:f})=>(woe(`_formatFileName: date=${g}, index=${f}`),d.reduce((p,b)=>b(p,f,g),a))}});var JI=m((tEe,ZI)=>{var Ga=Ot()("streamroller:fileNameParser"),YI=".gz",WI=Sp(),Soe=".";ZI.exports=({file:n,keepFileExt:e,pattern:t,fileNameSep:i})=>{let r=i||Soe,o=(d,g)=>d.endsWith(YI)?(Ga("it is gzipped"),g.isCompressed=!0,d.slice(0,-1*YI.length)):d,s="__NOT_MATCHING__",h=[o,e?d=>d.startsWith(n.name)&&d.endsWith(n.ext)?(Ga("it starts and ends with the right things"),d.slice(n.name.length+1,-1*n.ext.length)):s:d=>d.startsWith(n.base)?(Ga("it starts with the right things"),d.slice(n.base.length+1)):s,t?(d,g)=>{let f=d.split(r),p=f[f.length-1];Ga("items: ",f,", indexStr: ",p);let b=d;p!==void 0&&p.match(/^\d+$/)?(b=d.slice(0,-1*(p.length+1)),Ga(`dateStr is ${b}`),t&&!b&&(b=p,p="0")):p="0";try{let v=WI.parse(t,b,new Date(0,0));return WI.asString(t,v)!==b?d:(g.index=parseInt(p,10),g.date=b,g.timestamp=v.getTime(),"")}catch(v){return Ga(`Problem parsing ${b} as ${t}, error was: `,v),d}}:(d,g)=>d.match(/^\d+$/)?(Ga("it has an index"),g.index=parseInt(d,10),""):d];return d=>{let g={filename:d,index:0,isCompressed:!1};return h.reduce((p,b)=>b(p,g),d)?null:g}}});var XI=m((iEe,$I)=>{var Is=Ot()("streamroller:moveAndMaybeCompressFile"),Fs=eC(),Toe=require("zlib"),koe=function(n){let e={mode:parseInt("0600",8),compress:!1},t=Object.assign({},e,n);return Is(`_parseOption: moveAndMaybeCompressFile called with option=${JSON.stringify(t)}`),t},Eoe=async(n,e,t)=>{if(t=koe(t),n===e){Is("moveAndMaybeCompressFile: source and target are the same, not doing anything");return}if(await Fs.pathExists(n))if(Is(`moveAndMaybeCompressFile: moving file from ${n} to ${e} ${t.compress?"with":"without"} compress`),t.compress)await new Promise((i,r)=>{Fs.createReadStream(n).pipe(Toe.createGzip()).pipe(Fs.createWriteStream(e,{mode:t.mode})).on("finish",()=>{Is(`moveAndMaybeCompressFile: finished compressing ${e}, deleting ${n}`),Fs.unlink(n).then(i).catch(()=>{Is(`Deleting ${n} failed, truncating instead`),Fs.truncate(n).then(i).catch(r)})})});else{Is(`moveAndMaybeCompressFile: deleting file=${e}, renaming ${n} to ${e}`);try{await Fs.move(n,e,{overwrite:!0})}catch(i){Is(`moveAndMaybeCompressFile: error moving ${n} to ${e}`,i),Is("Trying copy+truncate instead"),await Fs.copy(n,e,{overwrite:!0}),await Fs.truncate(n)}}};$I.exports=Eoe});var Xp=m((nEe,GI)=>{var _n=Ot()("streamroller:RollingFileWriteStream"),ld=eC(),Zp=require("path"),Jp=BI(),$p=Sp(),{Writable:Poe}=require("stream"),_oe=qI(),Roe=JI(),Loe=XI(),UI=class extends Poe{constructor(e,t){_n(`constructor: creating RollingFileWriteStream. path=${e}`);super(t);this.options=this._parseOption(t),this.fileObject=Zp.parse(e),this.fileObject.dir===""&&(this.fileObject=Zp.parse(Zp.join(process.cwd(),e))),this.fileFormatter=_oe({file:this.fileObject,alwaysIncludeDate:this.options.alwaysIncludePattern,needsIndex:this.options.maxSize 0`);if(i.numBackups||i.numBackups===0){if(i.numBackups<0)throw new Error(`options.numBackups (${i.numBackups}) should be >= 0`);if(i.numBackups>=Number.MAX_SAFE_INTEGER)throw new Error(`options.numBackups (${i.numBackups}) should be < Number.MAX_SAFE_INTEGER`);i.numToKeep=i.numBackups+1}else if(i.numToKeep<=0)throw new Error(`options.numToKeep (${i.numToKeep}) should be > 0`);return _n(`_parseOption: creating stream with option=${JSON.stringify(i)}`),i}_final(e){this.currentFileStream.end("",this.options.encoding,e)}_write(e,t,i){this._shouldRoll().then(()=>{_n(`_write: writing chunk. file=${this.currentFileStream.path} state=${JSON.stringify(this.state)} chunk=${e}`),this.currentFileStream.write(e,t,r=>{this.state.currentSize+=e.length,i(r)})})}async _shouldRoll(){(this._dateChanged()||this._tooBig())&&(_n(`_shouldRoll: rolling because dateChanged? ${this._dateChanged()} or tooBig? ${this._tooBig()}`),await this._roll())}_dateChanged(){return this.state.currentDate&&this.state.currentDate!==$p(this.options.pattern,Jp())}_tooBig(){return this.state.currentSize>=this.options.maxSize}_roll(){return _n("_roll: closing the current stream"),new Promise((e,t)=>{this.currentFileStream.end("",this.options.encoding,()=>{this._moveOldFiles().then(e).catch(t)})})}async _moveOldFiles(){let e=await this._getExistingFiles(),t=this.state.currentDate?e.filter(i=>i.date===this.state.currentDate):e;for(let i=t.length;i>=0;i--){_n(`_moveOldFiles: i = ${i}`);let r=this.fileFormatter({date:this.state.currentDate,index:i}),o=this.fileFormatter({date:this.state.currentDate,index:i+1}),s={compress:this.options.compress&&i===0,mode:this.options.mode};await Loe(r,o,s)}this.state.currentSize=0,this.state.currentDate=this.state.currentDate?$p(this.options.pattern,Jp()):null,_n(`_moveOldFiles: finished rolling files. state=${JSON.stringify(this.state)}`),this._renewWriteStream(),await new Promise((i,r)=>{this.currentFileStream.write("","utf8",()=>{this._clean().then(i).catch(r)})})}async _getExistingFiles(){let e=await ld.readdir(this.fileObject.dir).catch(()=>[]);_n(`_getExistingFiles: files=${e}`);let t=e.map(r=>this.fileNameParser(r)).filter(r=>r),i=r=>(r.timestamp?r.timestamp:Jp().getTime())-r.index;return t.sort((r,o)=>i(r)-i(o)),t}_renewWriteStream(){ld.ensureDirSync(this.fileObject.dir);let e=this.fileFormatter({date:this.state.currentDate,index:0}),t={flags:this.options.flags,encoding:this.options.encoding,mode:this.options.mode};this.currentFileStream=ld.createWriteStream(e,t),this.currentFileStream.on("error",i=>{this.emit("error",i)})}async _clean(){let e=await this._getExistingFiles();if(_n(`_clean: numToKeep = ${this.options.numToKeep}, existingFiles = ${e.length}`),_n("_clean: existing files are: ",e),this._tooManyFiles(e.length)){let t=e.slice(0,e.length-this.options.numToKeep).map(i=>Zp.format({dir:this.fileObject.dir,base:i.filename}));await Foe(t)}}_tooManyFiles(e){return this.options.numToKeep>0&&e>this.options.numToKeep}},Foe=n=>(_n(`deleteFiles: files to delete: ${n}`),Promise.all(n.map(e=>ld.unlink(e).catch(t=>{_n(`deleteFiles: error when unlinking ${e}, ignoring. Error was ${t}`)}))));GI.exports=UI});var zI=m((rEe,KI)=>{var Ioe=Xp(),QI=class extends Ioe{constructor(e,t,i,r){r||(r={}),t&&(r.maxSize=t),!r.numBackups&&r.numBackups!==0&&(!i&&i!==0&&(i=1),r.numBackups=i);super(e,r);this.backups=r.numBackups,this.size=this.options.maxSize}get theStream(){return this.currentFileStream}};KI.exports=QI});var tj=m((oEe,ej)=>{var joe=Xp(),VI=class extends joe{constructor(e,t,i){t&&typeof t=="object"&&(i=t,t=null),i||(i={}),t||(t="yyyy-MM-dd"),i.pattern=t,!i.numBackups&&i.numBackups!==0?(!i.daysToKeep&&i.daysToKeep!==0?i.daysToKeep=1:process.emitWarning("options.daysToKeep is deprecated due the confusion it causes when used together with file size rolling. Please use options.numBackups instead.","DeprecationWarning","StreamRoller0001"),i.numBackups=i.daysToKeep):i.daysToKeep=i.numBackups;super(e,i);this.mode=this.options.mode}get theStream(){return this.currentFileStream}};ej.exports=VI});var tC=m((sEe,ij)=>{ij.exports={RollingFileWriteStream:Xp(),RollingFileStream:zI(),DateRollingFileStream:tj()}});var aj=m((aEe,sj)=>{var nj=Ot()("log4js:file"),Aoe=require("path"),Ooe=tC(),Moe=require("os"),Noe=Moe.EOL,Up=!1,Gp=new Set;function rj(){Gp.forEach(n=>{n.sighupHandler()})}function oj(n,e,t,i){let r=new Ooe.RollingFileStream(n,e,t,i);return r.on("error",o=>{console.error("log4js.fileAppender - Writing to file %s, error happened ",n,o)}),r.on("drain",()=>{process.emit("log4js:pause",!1)}),r}function Boe(n,e,t,i,r,o){n=Aoe.normalize(n),i=!i&&i!==0?5:i,nj("Creating file appender (",n,", ",t,", ",i,", ",r,", ",o,")");let s=oj(n,t,i,r),a=function(l){if(!!s.writable){if(r.removeColor===!0){let u=/\x1b[[0-9;]*m/g;l.data=l.data.map(c=>typeof c=="string"?c.replace(u,""):c)}s.write(e(l,o)+Noe,"utf8")||process.emit("log4js:pause",!0)}};return a.reopen=function(){s.end(()=>{s=oj(n,t,i,r)})},a.sighupHandler=function(){nj("SIGHUP handler called."),a.reopen()},a.shutdown=function(l){Gp.delete(a),Gp.size===0&&Up&&(process.removeListener("SIGHUP",rj),Up=!1),s.end("","utf-8",l)},Gp.add(a),Up||(process.on("SIGHUP",rj),Up=!0),a}function Hoe(n,e){let t=e.basicLayout;return n.layout&&(t=e.layout(n.layout.type,n.layout)),n.mode=n.mode||384,Boe(n.filename,t,n.maxLogSize,n.backups,n,n.timezoneOffset)}sj.exports.configure=Hoe});var uj=m((lEe,lj)=>{var qoe=tC(),Yoe=require("os"),Woe=Yoe.EOL;function Zoe(n,e,t){let i=new qoe.DateRollingFileStream(n,e,t);return i.on("error",r=>{console.error("log4js.dateFileAppender - Writing to file %s, error happened ",n,r)}),i.on("drain",()=>{process.emit("log4js:pause",!1)}),i}function Joe(n,e,t,i,r){i.maxSize=i.maxLogSize;let o=Zoe(n,e,i),s=function(a){!o.writable||o.write(t(a,r)+Woe,"utf8")||process.emit("log4js:pause",!0)};return s.shutdown=function(a){o.end("","utf-8",a)},s}function $oe(n,e){let t=e.basicLayout;return n.layout&&(t=e.layout(n.layout.type,n.layout)),n.alwaysIncludePattern||(n.alwaysIncludePattern=!1),n.mode=n.mode||384,Joe(n.filename,n.pattern,t,n,n.timezoneOffset)}lj.exports.configure=$oe});var gj=m((uEe,dj)=>{var _o=Ot()("log4js:fileSync"),Tu=require("path"),Xr=require("fs"),Xoe=require("os"),Uoe=Xoe.EOL||` -`;function cj(n,e){if(Xr.existsSync(n))return;let t=Xr.openSync(n,e.flags,e.mode);Xr.closeSync(t)}var hj=class{constructor(e,t,i,r){_o("In RollingFileStream");function o(){if(!e||!t||t<=0)throw new Error("You must specify a filename and file size")}o(),this.filename=e,this.size=t,this.backups=i,this.options=r,this.currentSize=0;function s(a){let l=0;try{l=Xr.statSync(a).size}catch{cj(a,r)}return l}this.currentSize=s(this.filename)}shouldRoll(){return _o("should roll with current size %d, and max size %d",this.currentSize,this.size),this.currentSize>=this.size}roll(e){let t=this,i=new RegExp(`^${Tu.basename(e)}`);function r(u){return i.test(u)}function o(u){return parseInt(u.substring(`${Tu.basename(e)}.`.length),10)||0}function s(u,c){return o(u)>o(c)?1:o(u) ${e}.${c+1}`),Xr.renameSync(Tu.join(Tu.dirname(e),u),`${e}.${c+1}`)}}function l(){_o("Renaming the old files"),Xr.readdirSync(Tu.dirname(e)).filter(r).sort(s).reverse().forEach(a)}_o("Rolling, rolling, rolling"),l()}write(e,t){let i=this;function r(){_o("writing the chunk to the file"),i.currentSize+=e.length,Xr.appendFileSync(i.filename,e)}_o("in write"),this.shouldRoll()&&(this.currentSize=0,this.roll(this.filename)),r()}};function Goe(n,e,t,i,r,o){_o("fileSync appender created"),n=Tu.normalize(n),i=!i&&i!==0?5:i;function s(l,u,c){let h;return u?h=new hj(l,u,c,o):h=(d=>(cj(d,o),{write(g){Xr.appendFileSync(d,g)}}))(l),h}let a=s(n,t,i);return l=>{a.write(e(l,r)+Uoe)}}function Qoe(n,e){let t=e.basicLayout;n.layout&&(t=e.layout(n.layout.type,n.layout));let i={flags:n.flags||"a",encoding:n.encoding||"utf8",mode:n.mode||384};return Goe(n.filename,t,n.maxLogSize,n.backups,n.timezoneOffset,i)}dj.exports.configure=Qoe});var pj=m((cEe,fj)=>{var Ur=Ot()("log4js:tcp"),Koe=require("net");function zoe(n,e){let t=!1,i=[],r,o=3,s="__LOG4JS__";function a(h){Ur("Writing log event to socket"),t=r.write(`${e(h)}${s}`,"utf8")}function l(){let h;for(Ur("emptying buffer");h=i.shift();)a(h)}function u(){Ur(`appender creating socket to ${n.host||"localhost"}:${n.port||5e3}`),s=`${n.endMsg||"__LOG4JS__"}`,r=Koe.createConnection(n.port||5e3,n.host||"localhost"),r.on("connect",()=>{Ur("socket connected"),l(),t=!0}),r.on("drain",()=>{Ur("drain event received, emptying buffer"),t=!0,l()}),r.on("timeout",r.end.bind(r)),r.on("error",h=>{Ur("connection error",h),t=!1,l()}),r.on("close",u)}u();function c(h){t?a(h):(Ur("buffering log event because it cannot write at the moment"),i.push(h))}return c.shutdown=function(h){Ur("shutdown called"),i.length&&o?(Ur("buffer has items, waiting 100ms to empty"),o-=1,setTimeout(()=>{c.shutdown(h)},100)):(r.removeAllListeners("close"),r.end(h))},c}function Voe(n,e){Ur(`configure with config = ${n}`);let t=function(i){return i.serialise()};return n.layout&&(t=e.layout(n.layout.type,n.layout)),zoe(n,t)}fj.exports.configure=Voe});var rC=m((hEe,nC)=>{var ese=require("path"),Qa=Ot()("log4js:appenders"),Jn=Wa(),mj=Pp(),tse=$a(),ise=Fx(),nse=wL(),yr=new Map;yr.set("console",xL());yr.set("stdout",SL());yr.set("stderr",kL());yr.set("logLevelFilter",PL());yr.set("categoryFilter",LL());yr.set("noLogFilter",jL());yr.set("file",aj());yr.set("dateFile",uj());yr.set("fileSync",gj());yr.set("tcp",pj());var ud=new Map,iC=(n,e)=>{Qa("Loading module from ",n);try{return require(n)}catch(t){Jn.throwExceptionIf(e,t.code!=="MODULE_NOT_FOUND",`appender "${n}" could not be loaded (error was: ${t})`);return}},rse=(n,e)=>yr.get(n)||iC(`./${n}`,e)||iC(n,e)||""||iC(ese.join(process.cwd(),n),e),Qp=new Set,bj=(n,e)=>{if(ud.has(n))return ud.get(n);if(!e.appenders[n])return!1;if(Qp.has(n))throw new Error(`Dependency loop detected for appender ${n}.`);Qp.add(n),Qa(`Creating appender ${n}`);let t=ose(n,e);return Qp.delete(n),ud.set(n,t),t},ose=(n,e)=>{let t=e.appenders[n],i=t.type.configure?t.type:rse(t.type,e);return Jn.throwExceptionIf(e,Jn.not(i),`appender "${n}" is not valid (type "${t.type}" could not be found)`),i.appender&&Qa(`DEPRECATION: Appender ${t.type} exports an appender function.`),i.shutdown&&Qa(`DEPRECATION: Appender ${t.type} exports a shutdown function.`),Qa(`${n}: clustering.isMaster ? ${mj.isMaster()}`),Qa(`${n}: appenderModule is ${require("util").inspect(i)}`),mj.onlyOnMaster(()=>(Qa(`calling appenderModule.configure for ${n} / ${t.type}`),i.configure(nse.modifyConfig(t),ise,r=>bj(r,e),tse)),()=>{})},yj=n=>{ud.clear(),Qp.clear();let e=[];Object.values(n.categories).forEach(t=>{e.push(...t.appenders)}),Object.keys(n.appenders).forEach(t=>{(e.includes(t)||n.appenders[t].type==="tcp-server")&&bj(t,n)})},vj=()=>{yj({appenders:{out:{type:"stdout"}},categories:{default:{appenders:["out"],level:"trace"}}})};vj();Jn.addListener(n=>{Jn.throwExceptionIf(n,Jn.not(Jn.anObject(n.appenders)),'must have a property "appenders" of type object.');let e=Object.keys(n.appenders);Jn.throwExceptionIf(n,Jn.not(e.length),"must define at least one appender."),e.forEach(t=>{Jn.throwExceptionIf(n,Jn.not(n.appenders[t].type),`appender "${t}" is not valid (must be an object with property "type")`)})});Jn.addListener(yj);nC.exports=ud;nC.exports.init=vj});var sC=m((dEe,Kp)=>{var Ka=Ot()("log4js:categories"),Mt=Wa(),oC=$a(),wj=rC(),za=new Map;function Dj(n,e,t){if(e.inherit===!1)return;let i=t.lastIndexOf(".");if(i<0)return;let r=t.substring(0,i),o=n.categories[r];o||(o={inherit:!0,appenders:[]}),Dj(n,o,r),!n.categories[r]&&o.appenders&&o.appenders.length&&o.level&&(n.categories[r]=o),e.appenders=e.appenders||[],e.level=e.level||o.level,o.appenders.forEach(s=>{e.appenders.includes(s)||e.appenders.push(s)}),e.parent=o}function sse(n){if(!n.categories)return;Object.keys(n.categories).forEach(t=>{let i=n.categories[t];Dj(n,i,t)})}Mt.addPreProcessingListener(n=>sse(n));Mt.addListener(n=>{Mt.throwExceptionIf(n,Mt.not(Mt.anObject(n.categories)),'must have a property "categories" of type object.');let e=Object.keys(n.categories);Mt.throwExceptionIf(n,Mt.not(e.length),"must define at least one category."),e.forEach(t=>{let i=n.categories[t];Mt.throwExceptionIf(n,[Mt.not(i.appenders),Mt.not(i.level)],`category "${t}" is not valid (must be an object with properties "appenders" and "level")`),Mt.throwExceptionIf(n,Mt.not(Array.isArray(i.appenders)),`category "${t}" is not valid (appenders must be an array of appender names)`),Mt.throwExceptionIf(n,Mt.not(i.appenders.length),`category "${t}" is not valid (appenders must contain at least one appender name)`),Object.prototype.hasOwnProperty.call(i,"enableCallStack")&&Mt.throwExceptionIf(n,typeof i.enableCallStack!="boolean",`category "${t}" is not valid (enableCallStack must be boolean type)`),i.appenders.forEach(r=>{Mt.throwExceptionIf(n,Mt.not(wj.get(r)),`category "${t}" is not valid (appender "${r}" is not defined)`)}),Mt.throwExceptionIf(n,Mt.not(oC.getLevel(i.level)),`category "${t}" is not valid (level "${i.level}" not recognised; valid levels are ${oC.levels.join(", ")})`)}),Mt.throwExceptionIf(n,Mt.not(n.categories.default),'must define a "default" category.')});var xj=n=>{za.clear(),Object.keys(n.categories).forEach(t=>{let i=n.categories[t],r=[];i.appenders.forEach(o=>{r.push(wj.get(o)),Ka(`Creating category ${t}`),za.set(t,{appenders:r,level:oC.getLevel(i.level),enableCallStack:i.enableCallStack||!1})})})},Cj=()=>{xj({categories:{default:{appenders:["out"],level:"OFF"}}})};Cj();Mt.addListener(xj);var Va=n=>(Ka(`configForCategory: searching for config for ${n}`),za.has(n)?(Ka(`configForCategory: ${n} exists in config, returning it`),za.get(n)):n.indexOf(".")>0?(Ka(`configForCategory: ${n} has hierarchy, searching for parents`),Va(n.substring(0,n.lastIndexOf(".")))):(Ka("configForCategory: returning config for default category"),Va("default"))),ase=n=>Va(n).appenders,lse=n=>Va(n).level,use=(n,e)=>{let t=za.get(n);if(Ka(`setLevelForCategory: found ${t} for ${n}`),!t){let i=Va(n);Ka(`setLevelForCategory: no config found for category, found ${i} for parents of ${n}`),t={appenders:i.appenders}}t.level=e,za.set(n,t)},cse=n=>Va(n).enableCallStack===!0,hse=(n,e)=>{Va(n).enableCallStack=e};Kp.exports=za;Kp.exports=Object.assign(Kp.exports,{appendersForCategory:ase,getLevelForCategory:lse,setLevelForCategory:use,getEnableCallStackForCategory:cse,setEnableCallStackForCategory:hse,init:Cj})});var Ej=m((gEe,kj)=>{var Sj=Ot()("log4js:logger"),dse=Ix(),Ro=$a(),gse=Pp(),zp=sC(),fse=Wa(),pse=/at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;function mse(n,e=4){let t=n.stack.split(` -`).slice(e),i=pse.exec(t[0]);return i&&i.length===6?{functionName:i[1],fileName:i[2],lineNumber:parseInt(i[3],10),columnNumber:parseInt(i[4],10),callStack:t.join(` -`)}:null}var Vp=class{constructor(e){if(!e)throw new Error("No category provided.");this.category=e,this.context={},this.parseCallStack=mse,Sj(`Logger created (${this.category}, ${this.level})`)}get level(){return Ro.getLevel(zp.getLevelForCategory(this.category),Ro.TRACE)}set level(e){zp.setLevelForCategory(this.category,Ro.getLevel(e,this.level))}get useCallStack(){return zp.getEnableCallStackForCategory(this.category)}set useCallStack(e){zp.setEnableCallStackForCategory(this.category,e===!0)}log(e,...t){let i=Ro.getLevel(e);i||(this._log(Ro.WARN,"log4js:logger.log: invalid value for log-level as first parameter given: ",e),i=Ro.INFO),this.isLevelEnabled(i)&&this._log(i,t)}isLevelEnabled(e){return this.level.isLessThanOrEqualTo(e)}_log(e,t){Sj(`sending log data (${e}) to appenders`);let i=new dse(this.category,e,t,this.context,this.useCallStack&&this.parseCallStack(new Error));gse.send(i)}addContext(e,t){this.context[e]=t}removeContext(e){delete this.context[e]}clearContext(){this.context={}}setParseCallStackFunction(e){this.parseCallStack=e}};function Tj(n){let e=Ro.getLevel(n),i=e.toString().toLowerCase().replace(/_([a-z])/g,o=>o[1].toUpperCase()),r=i[0].toUpperCase()+i.slice(1);Vp.prototype[`is${r}Enabled`]=function(){return this.isLevelEnabled(e)},Vp.prototype[i]=function(...o){this.log(e,...o)}}Ro.levels.forEach(Tj);fse.addListener(()=>{Ro.levels.forEach(Tj)});kj.exports=Vp});var Rj=m((fEe,_j)=>{var ku=$a(),bse=':remote-addr - - ":method :url HTTP/:http-version" :status :content-length ":referrer" ":user-agent"';function yse(n){return n.originalUrl||n.url}function vse(n,e,t){let i=o=>{let s=o.concat();for(let a=0;ai.source?i.source:i);e=new RegExp(t.join("|"))}return e}function Dse(n,e,t){let i=e;if(t){let r=t.find(o=>{let s=!1;return o.from&&o.to?s=n>=o.from&&n<=o.to:s=o.codes.indexOf(n)!==-1,s});r&&(i=ku.getLevel(r.level,i))}return i}_j.exports=function(e,t){typeof t=="string"||typeof t=="function"?t={format:t}:t=t||{};let i=e,r=ku.getLevel(t.level,ku.INFO),o=t.format||bse,s=wse(t.nolog);return(a,l,u)=>{if(a._logging||s&&s.test(a.originalUrl))return u();if(i.isLevelEnabled(r)||t.level==="auto"){let c=new Date,{writeHead:h}=l;a._logging=!0,l.writeHead=(d,g)=>{l.writeHead=h,l.writeHead(d,g),l.__statusCode=d,l.__headers=g||{}},l.on("finish",()=>{l.responseTime=new Date-c,l.statusCode&&t.level==="auto"&&(r=ku.INFO,l.statusCode>=300&&(r=ku.WARN),l.statusCode>=400&&(r=ku.ERROR)),r=Dse(l.statusCode,r,t.statusRules);let d=vse(a,l,t.tokens||[]);if(t.context&&i.addContext("res",l),typeof o=="function"){let g=o(a,l,f=>Pj(f,d));g&&i.log(r,g)}else i.log(r,Pj(o,d));t.context&&i.removeContext("res")})}return u()}}});var Aj=m((pEe,jj)=>{var Lj=Ot()("log4js:recording"),em=[];function xse(){return function(n){Lj(`received logEvent, number of events now ${em.length+1}`),Lj("log event was ",n),em.push(n)}}function Fj(){return em.slice()}function Ij(){em.length=0}jj.exports={configure:xse,replay:Fj,playback:Fj,reset:Ij,erase:Ij}});var aC=m((mEe,qj)=>{var js=Ot()("log4js:main"),Cse=require("fs"),Sse=AR()({proto:!0}),Tse=Wa(),kse=Fx(),Ese=$a(),Oj=rC(),Mj=sC(),Pse=Ej(),_se=Pp(),Rse=Rj(),Lse=Aj(),cd=!1;function Fse(n){if(!cd)return;js("Received log event ",n),Mj.appendersForCategory(n.categoryName).forEach(t=>{t(n)})}function Ise(n){js(`Loading configuration from ${n}`);try{return JSON.parse(Cse.readFileSync(n,"utf8"))}catch(e){throw new Error(`Problem reading config from file "${n}". Error was ${e.message}`,e)}}function Nj(n){cd&&Bj();let e=n;return typeof e=="string"&&(e=Ise(n)),js(`Configuration is ${e}`),Tse.configure(Sse(e)),_se.onMessage(Fse),cd=!0,Hj}function jse(){return Lse}function Bj(n){js("Shutdown called. Disabling all log writing."),cd=!1;let e=Array.from(Oj.values());Oj.init(),Mj.init();let t=e.reduceRight((s,a)=>a.shutdown?s+1:s,0);if(t===0)return js("No appenders with shutdown functions found."),n!==void 0&&n();let i=0,r;js(`Found ${t} appenders with shutdown functions.`);function o(s){r=r||s,i+=1,js(`Appender shutdowns complete: ${i} / ${t}`),i>=t&&(js("All shutdown functions completed."),n&&n(r))}return e.filter(s=>s.shutdown).forEach(s=>s.shutdown(o)),null}function Ase(n){return cd||Nj(process.env.LOG4JS_CONFIG||{appenders:{out:{type:"stdout"}},categories:{default:{appenders:["out"],level:"OFF"}}}),new Pse(n||"default")}var Hj={getLogger:Ase,configure:Nj,shutdown:Bj,connectLogger:Rse,levels:Ese,addLayout:kse.addLayout,recording:jse};qj.exports=Hj});var hd=m(As=>{"use strict";var Yj=gt().fromCallback,Yi=Qe(),Ose=["access","appendFile","chmod","chown","close","copyFile","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","symlink","truncate","unlink","utimes","writeFile"].filter(n=>typeof Yi[n]=="function");Object.keys(Yi).forEach(n=>{n!=="promises"&&(As[n]=Yi[n])});Ose.forEach(n=>{As[n]=Yj(Yi[n])});As.exists=function(n,e){return typeof e=="function"?Yi.exists(n,e):new Promise(t=>Yi.exists(n,t))};As.read=function(n,e,t,i,r,o){return typeof o=="function"?Yi.read(n,e,t,i,r,o):new Promise((s,a)=>{Yi.read(n,e,t,i,r,(l,u,c)=>{if(l)return a(l);s({bytesRead:u,buffer:c})})})};As.write=function(n,e,...t){return typeof t[t.length-1]=="function"?Yi.write(n,e,...t):new Promise((i,r)=>{Yi.write(n,e,...t,(o,s,a)=>{if(o)return r(o);i({bytesWritten:s,buffer:a})})})};typeof Yi.writev=="function"&&(As.writev=function(n,e,...t){return typeof t[t.length-1]=="function"?Yi.writev(n,e,...t):new Promise((i,r)=>{Yi.writev(n,e,...t,(o,s,a)=>{if(o)return r(o);i({bytesWritten:s,buffers:a})})})});typeof Yi.realpath.native=="function"&&(As.realpath.native=Yj(Yi.realpath.native))});var lC=m((yEe,Wj)=>{Wj.exports=n=>{let e=process.versions.node.split(".").map(t=>parseInt(t,10));return n=n.split(".").map(t=>parseInt(t,10)),e[0]>n[0]||e[0]===n[0]&&(e[1]>n[1]||e[1]===n[1]&&e[2]>=n[2])}});var Uj=m((vEe,uC)=>{"use strict";var Eu=hd(),Lo=require("path"),Mse=lC(),Zj=Mse("10.12.0"),Jj=n=>{if(process.platform==="win32"&&/[<>:"|?*]/.test(n.replace(Lo.parse(n).root,""))){let t=new Error(`Path contains invalid characters: ${n}`);throw t.code="EINVAL",t}},$j=n=>{let e={mode:511};return typeof n=="number"&&(n={mode:n}),ge(ge({},e),n)},Xj=n=>{let e=new Error(`operation not permitted, mkdir '${n}'`);return e.code="EPERM",e.errno=-4048,e.path=n,e.syscall="mkdir",e};uC.exports.makeDir=async(n,e)=>{if(Jj(n),e=$j(e),Zj){let i=Lo.resolve(n);return Eu.mkdir(i,{mode:e.mode,recursive:!0})}let t=async i=>{try{await Eu.mkdir(i,e.mode)}catch(r){if(r.code==="EPERM")throw r;if(r.code==="ENOENT"){if(Lo.dirname(i)===i)throw Xj(i);if(r.message.includes("null bytes"))throw r;return await t(Lo.dirname(i)),t(i)}try{if(!(await Eu.stat(i)).isDirectory())throw new Error("The path is not a directory")}catch{throw r}}};return t(Lo.resolve(n))};uC.exports.makeDirSync=(n,e)=>{if(Jj(n),e=$j(e),Zj){let i=Lo.resolve(n);return Eu.mkdirSync(i,{mode:e.mode,recursive:!0})}let t=i=>{try{Eu.mkdirSync(i,e.mode)}catch(r){if(r.code==="EPERM")throw r;if(r.code==="ENOENT"){if(Lo.dirname(i)===i)throw Xj(i);if(r.message.includes("null bytes"))throw r;return t(Lo.dirname(i)),t(i)}try{if(!Eu.statSync(i).isDirectory())throw new Error("The path is not a directory")}catch{throw r}}};return t(Lo.resolve(n))}});var vr=m((wEe,Gj)=>{"use strict";var Nse=gt().fromPromise,{makeDir:Bse,makeDirSync:cC}=Uj(),hC=Nse(Bse);Gj.exports={mkdirs:hC,mkdirsSync:cC,mkdirp:hC,mkdirpSync:cC,ensureDir:hC,ensureDirSync:cC}});var dC=m((DEe,Qj)=>{"use strict";var Pu=Qe();function Hse(n,e,t,i){Pu.open(n,"r+",(r,o)=>{if(r)return i(r);Pu.futimes(o,e,t,s=>{Pu.close(o,a=>{i&&i(s||a)})})})}function qse(n,e,t){let i=Pu.openSync(n,"r+");return Pu.futimesSync(i,e,t),Pu.closeSync(i)}Qj.exports={utimesMillis:Hse,utimesMillisSync:qse}});var dd=m((xEe,e1)=>{"use strict";var _u=hd(),on=require("path"),Yse=require("util"),Wse=lC(),tm=Wse("10.5.0"),Kj=n=>tm?_u.stat(n,{bigint:!0}):_u.stat(n),gC=n=>tm?_u.statSync(n,{bigint:!0}):_u.statSync(n);function Zse(n,e){return Promise.all([Kj(n),Kj(e).catch(t=>{if(t.code==="ENOENT")return null;throw t})]).then(([t,i])=>({srcStat:t,destStat:i}))}function Jse(n,e){let t,i=gC(n);try{t=gC(e)}catch(r){if(r.code==="ENOENT")return{srcStat:i,destStat:null};throw r}return{srcStat:i,destStat:t}}function $se(n,e,t,i){Yse.callbackify(Zse)(n,e,(r,o)=>{if(r)return i(r);let{srcStat:s,destStat:a}=o;return a&&im(s,a)?i(new Error("Source and destination must not be the same.")):s.isDirectory()&&fC(n,e)?i(new Error(nm(n,e,t))):i(null,{srcStat:s,destStat:a})})}function Xse(n,e,t){let{srcStat:i,destStat:r}=Jse(n,e);if(r&&im(i,r))throw new Error("Source and destination must not be the same.");if(i.isDirectory()&&fC(n,e))throw new Error(nm(n,e,t));return{srcStat:i,destStat:r}}function zj(n,e,t,i,r){let o=on.resolve(on.dirname(n)),s=on.resolve(on.dirname(t));if(s===o||s===on.parse(s).root)return r();let a=(l,u)=>l?l.code==="ENOENT"?r():r(l):im(e,u)?r(new Error(nm(n,t,i))):zj(n,e,s,i,r);tm?_u.stat(s,{bigint:!0},a):_u.stat(s,a)}function Vj(n,e,t,i){let r=on.resolve(on.dirname(n)),o=on.resolve(on.dirname(t));if(o===r||o===on.parse(o).root)return;let s;try{s=gC(o)}catch(a){if(a.code==="ENOENT")return;throw a}if(im(e,s))throw new Error(nm(n,t,i));return Vj(n,e,o,i)}function im(n,e){return!!(e.ino&&e.dev&&e.ino===n.ino&&e.dev===n.dev&&(tm||e.inor),i=on.resolve(e).split(on.sep).filter(r=>r);return t.reduce((r,o,s)=>r&&i[s]===o,!0)}function nm(n,e,t){return`Cannot ${t} '${n}' to a subdirectory of itself, '${e}'.`}e1.exports={checkPaths:$se,checkPathsSync:Xse,checkParentPaths:zj,checkParentPathsSync:Vj,isSrcSubdir:fC}});var o1=m((CEe,r1)=>{"use strict";var Si=Qe(),gd=require("path"),Use=vr().mkdirsSync,Gse=dC().utimesMillisSync,fd=dd();function Qse(n,e,t){typeof t=="function"&&(t={filter:t}),t=t||{},t.clobber="clobber"in t?!!t.clobber:!0,t.overwrite="overwrite"in t?!!t.overwrite:t.clobber,t.preserveTimestamps&&process.arch==="ia32"&&console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended; - - see https://github.com/jprichardson/node-fs-extra/issues/269`);let{srcStat:i,destStat:r}=fd.checkPathsSync(n,e,"copy");return fd.checkParentPathsSync(n,i,e,"copy"),Kse(r,n,e,t)}function Kse(n,e,t,i){if(i.filter&&!i.filter(e,t))return;let r=gd.dirname(t);return Si.existsSync(r)||Use(r),t1(n,e,t,i)}function t1(n,e,t,i){if(!(i.filter&&!i.filter(e,t)))return zse(n,e,t,i)}function zse(n,e,t,i){let o=(i.dereference?Si.statSync:Si.lstatSync)(e);if(o.isDirectory())return oae(o,n,e,t,i);if(o.isFile()||o.isCharacterDevice()||o.isBlockDevice())return Vse(o,n,e,t,i);if(o.isSymbolicLink())return lae(n,e,t,i)}function Vse(n,e,t,i,r){return e?eae(n,t,i,r):i1(n,t,i,r)}function eae(n,e,t,i){if(i.overwrite)return Si.unlinkSync(t),i1(n,e,t,i);if(i.errorOnExist)throw new Error(`'${t}' already exists`)}function i1(n,e,t,i){return Si.copyFileSync(e,t),i.preserveTimestamps&&tae(n.mode,e,t),pC(t,n.mode)}function tae(n,e,t){return iae(n)&&nae(t,n),rae(e,t)}function iae(n){return(n&128)===0}function nae(n,e){return pC(n,e|128)}function pC(n,e){return Si.chmodSync(n,e)}function rae(n,e){let t=Si.statSync(n);return Gse(e,t.atime,t.mtime)}function oae(n,e,t,i,r){if(!e)return sae(n.mode,t,i,r);if(e&&!e.isDirectory())throw new Error(`Cannot overwrite non-directory '${i}' with directory '${t}'.`);return n1(t,i,r)}function sae(n,e,t,i){return Si.mkdirSync(t),n1(e,t,i),pC(t,n)}function n1(n,e,t){Si.readdirSync(n).forEach(i=>aae(i,n,e,t))}function aae(n,e,t,i){let r=gd.join(e,n),o=gd.join(t,n),{destStat:s}=fd.checkPathsSync(r,o,"copy");return t1(s,r,o,i)}function lae(n,e,t,i){let r=Si.readlinkSync(e);if(i.dereference&&(r=gd.resolve(process.cwd(),r)),n){let o;try{o=Si.readlinkSync(t)}catch(s){if(s.code==="EINVAL"||s.code==="UNKNOWN")return Si.symlinkSync(r,t);throw s}if(i.dereference&&(o=gd.resolve(process.cwd(),o)),fd.isSrcSubdir(r,o))throw new Error(`Cannot copy '${r}' to a subdirectory of itself, '${o}'.`);if(Si.statSync(t).isDirectory()&&fd.isSrcSubdir(o,r))throw new Error(`Cannot overwrite '${o}' with '${r}'.`);return uae(r,t)}else return Si.symlinkSync(r,t)}function uae(n,e){return Si.unlinkSync(e),Si.symlinkSync(n,e)}r1.exports=Qse});var mC=m((SEe,s1)=>{"use strict";s1.exports={copySync:o1()}});var Os=m((TEe,l1)=>{"use strict";var cae=gt().fromPromise,a1=hd();function hae(n){return a1.access(n).then(()=>!0).catch(()=>!1)}l1.exports={pathExists:cae(hae),pathExistsSync:a1.existsSync}});var b1=m((kEe,m1)=>{"use strict";var sn=Qe(),pd=require("path"),dae=vr().mkdirs,gae=Os().pathExists,fae=dC().utimesMillis,md=dd();function pae(n,e,t,i){typeof t=="function"&&!i?(i=t,t={}):typeof t=="function"&&(t={filter:t}),i=i||function(){},t=t||{},t.clobber="clobber"in t?!!t.clobber:!0,t.overwrite="overwrite"in t?!!t.overwrite:t.clobber,t.preserveTimestamps&&process.arch==="ia32"&&console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended; - - see https://github.com/jprichardson/node-fs-extra/issues/269`),md.checkPaths(n,e,"copy",(r,o)=>{if(r)return i(r);let{srcStat:s,destStat:a}=o;md.checkParentPaths(n,s,e,"copy",l=>l?i(l):t.filter?d1(u1,a,n,e,t,i):u1(a,n,e,t,i))})}function u1(n,e,t,i,r){let o=pd.dirname(t);gae(o,(s,a)=>{if(s)return r(s);if(a)return bC(n,e,t,i,r);dae(o,l=>l?r(l):bC(n,e,t,i,r))})}function d1(n,e,t,i,r,o){Promise.resolve(r.filter(t,i)).then(s=>s?n(e,t,i,r,o):o(),s=>o(s))}function bC(n,e,t,i,r){return i.filter?d1(c1,n,e,t,i,r):c1(n,e,t,i,r)}function c1(n,e,t,i,r){(i.dereference?sn.stat:sn.lstat)(e,(s,a)=>{if(s)return r(s);if(a.isDirectory())return xae(a,n,e,t,i,r);if(a.isFile()||a.isCharacterDevice()||a.isBlockDevice())return mae(a,n,e,t,i,r);if(a.isSymbolicLink())return Tae(n,e,t,i,r)})}function mae(n,e,t,i,r,o){return e?bae(n,t,i,r,o):g1(n,t,i,r,o)}function bae(n,e,t,i,r){if(i.overwrite)sn.unlink(t,o=>o?r(o):g1(n,e,t,i,r));else return i.errorOnExist?r(new Error(`'${t}' already exists`)):r()}function g1(n,e,t,i,r){sn.copyFile(e,t,o=>o?r(o):i.preserveTimestamps?yae(n.mode,e,t,r):rm(t,n.mode,r))}function yae(n,e,t,i){return vae(n)?wae(t,n,r=>r?i(r):h1(n,e,t,i)):h1(n,e,t,i)}function vae(n){return(n&128)===0}function wae(n,e,t){return rm(n,e|128,t)}function h1(n,e,t,i){Dae(e,t,r=>r?i(r):rm(t,n,i))}function rm(n,e,t){return sn.chmod(n,e,t)}function Dae(n,e,t){sn.stat(n,(i,r)=>i?t(i):fae(e,r.atime,r.mtime,t))}function xae(n,e,t,i,r,o){return e?e&&!e.isDirectory()?o(new Error(`Cannot overwrite non-directory '${i}' with directory '${t}'.`)):f1(t,i,r,o):Cae(n.mode,t,i,r,o)}function Cae(n,e,t,i,r){sn.mkdir(t,o=>{if(o)return r(o);f1(e,t,i,s=>s?r(s):rm(t,n,r))})}function f1(n,e,t,i){sn.readdir(n,(r,o)=>r?i(r):p1(o,n,e,t,i))}function p1(n,e,t,i,r){let o=n.pop();return o?Sae(n,o,e,t,i,r):r()}function Sae(n,e,t,i,r,o){let s=pd.join(t,e),a=pd.join(i,e);md.checkPaths(s,a,"copy",(l,u)=>{if(l)return o(l);let{destStat:c}=u;bC(c,s,a,r,h=>h?o(h):p1(n,t,i,r,o))})}function Tae(n,e,t,i,r){sn.readlink(e,(o,s)=>{if(o)return r(o);if(i.dereference&&(s=pd.resolve(process.cwd(),s)),n)sn.readlink(t,(a,l)=>a?a.code==="EINVAL"||a.code==="UNKNOWN"?sn.symlink(s,t,r):r(a):(i.dereference&&(l=pd.resolve(process.cwd(),l)),md.isSrcSubdir(s,l)?r(new Error(`Cannot copy '${s}' to a subdirectory of itself, '${l}'.`)):n.isDirectory()&&md.isSrcSubdir(l,s)?r(new Error(`Cannot overwrite '${l}' with '${s}'.`)):kae(s,t,r)));else return sn.symlink(s,t,r)})}function kae(n,e,t){sn.unlink(e,i=>i?t(i):sn.symlink(n,e,t))}m1.exports=pae});var yC=m((EEe,y1)=>{"use strict";var Eae=gt().fromCallback;y1.exports={copy:Eae(b1())}});var E1=m((PEe,k1)=>{"use strict";var v1=Qe(),C1=require("path"),st=require("assert"),bd=process.platform==="win32";function S1(n){["unlink","chmod","stat","lstat","rmdir","readdir"].forEach(t=>{n[t]=n[t]||v1[t],t=t+"Sync",n[t]=n[t]||v1[t]}),n.maxBusyTries=n.maxBusyTries||3}function vC(n,e,t){let i=0;typeof e=="function"&&(t=e,e={}),st(n,"rimraf: missing path"),st.strictEqual(typeof n,"string","rimraf: path should be a string"),st.strictEqual(typeof t,"function","rimraf: callback function required"),st(e,"rimraf: invalid options argument provided"),st.strictEqual(typeof e,"object","rimraf: options should be object"),S1(e),w1(n,e,function r(o){if(o){if((o.code==="EBUSY"||o.code==="ENOTEMPTY"||o.code==="EPERM")&&iw1(n,e,r),s)}o.code==="ENOENT"&&(o=null)}t(o)})}function w1(n,e,t){st(n),st(e),st(typeof t=="function"),e.lstat(n,(i,r)=>{if(i&&i.code==="ENOENT")return t(null);if(i&&i.code==="EPERM"&&bd)return D1(n,e,i,t);if(r&&r.isDirectory())return om(n,e,i,t);e.unlink(n,o=>{if(o){if(o.code==="ENOENT")return t(null);if(o.code==="EPERM")return bd?D1(n,e,o,t):om(n,e,o,t);if(o.code==="EISDIR")return om(n,e,o,t)}return t(o)})})}function D1(n,e,t,i){st(n),st(e),st(typeof i=="function"),e.chmod(n,438,r=>{r?i(r.code==="ENOENT"?null:t):e.stat(n,(o,s)=>{o?i(o.code==="ENOENT"?null:t):s.isDirectory()?om(n,e,t,i):e.unlink(n,i)})})}function x1(n,e,t){let i;st(n),st(e);try{e.chmodSync(n,438)}catch(r){if(r.code==="ENOENT")return;throw t}try{i=e.statSync(n)}catch(r){if(r.code==="ENOENT")return;throw t}i.isDirectory()?sm(n,e,t):e.unlinkSync(n)}function om(n,e,t,i){st(n),st(e),st(typeof i=="function"),e.rmdir(n,r=>{r&&(r.code==="ENOTEMPTY"||r.code==="EEXIST"||r.code==="EPERM")?Pae(n,e,i):r&&r.code==="ENOTDIR"?i(t):i(r)})}function Pae(n,e,t){st(n),st(e),st(typeof t=="function"),e.readdir(n,(i,r)=>{if(i)return t(i);let o=r.length,s;if(o===0)return e.rmdir(n,t);r.forEach(a=>{vC(C1.join(n,a),e,l=>{if(!s){if(l)return t(s=l);--o===0&&e.rmdir(n,t)}})})})}function T1(n,e){let t;e=e||{},S1(e),st(n,"rimraf: missing path"),st.strictEqual(typeof n,"string","rimraf: path should be a string"),st(e,"rimraf: missing options"),st.strictEqual(typeof e,"object","rimraf: options should be object");try{t=e.lstatSync(n)}catch(i){if(i.code==="ENOENT")return;i.code==="EPERM"&&bd&&x1(n,e,i)}try{t&&t.isDirectory()?sm(n,e,null):e.unlinkSync(n)}catch(i){if(i.code==="ENOENT")return;if(i.code==="EPERM")return bd?x1(n,e,i):sm(n,e,i);if(i.code!=="EISDIR")throw i;sm(n,e,i)}}function sm(n,e,t){st(n),st(e);try{e.rmdirSync(n)}catch(i){if(i.code==="ENOTDIR")throw t;if(i.code==="ENOTEMPTY"||i.code==="EEXIST"||i.code==="EPERM")_ae(n,e);else if(i.code!=="ENOENT")throw i}}function _ae(n,e){if(st(n),st(e),e.readdirSync(n).forEach(t=>T1(C1.join(n,t),e)),bd){let t=Date.now();do try{return e.rmdirSync(n,e)}catch{}while(Date.now()-t<500)}else return e.rmdirSync(n,e)}k1.exports=vC;vC.sync=T1});var yd=m((_Ee,_1)=>{"use strict";var Rae=gt().fromCallback,P1=E1();_1.exports={remove:Rae(P1),removeSync:P1.sync}});var M1=m((REe,O1)=>{"use strict";var Lae=gt().fromCallback,F1=Qe(),I1=require("path"),j1=vr(),A1=yd(),R1=Lae(function(e,t){t=t||function(){},F1.readdir(e,(i,r)=>{if(i)return j1.mkdirs(e,t);r=r.map(s=>I1.join(e,s)),o();function o(){let s=r.pop();if(!s)return t();A1.remove(s,a=>{if(a)return t(a);o()})}})});function L1(n){let e;try{e=F1.readdirSync(n)}catch{return j1.mkdirsSync(n)}e.forEach(t=>{t=I1.join(n,t),A1.removeSync(t)})}O1.exports={emptyDirSync:L1,emptydirSync:L1,emptyDir:R1,emptydir:R1}});var q1=m((LEe,H1)=>{"use strict";var Fae=gt().fromCallback,N1=require("path"),Ms=Qe(),B1=vr();function Iae(n,e){function t(){Ms.writeFile(n,"",i=>{if(i)return e(i);e()})}Ms.stat(n,(i,r)=>{if(!i&&r.isFile())return e();let o=N1.dirname(n);Ms.stat(o,(s,a)=>{if(s)return s.code==="ENOENT"?B1.mkdirs(o,l=>{if(l)return e(l);t()}):e(s);a.isDirectory()?t():Ms.readdir(o,l=>{if(l)return e(l)})})})}function jae(n){let e;try{e=Ms.statSync(n)}catch{}if(e&&e.isFile())return;let t=N1.dirname(n);try{Ms.statSync(t).isDirectory()||Ms.readdirSync(t)}catch(i){if(i&&i.code==="ENOENT")B1.mkdirsSync(t);else throw i}Ms.writeFileSync(n,"")}H1.exports={createFile:Fae(Iae),createFileSync:jae}});var $1=m((FEe,J1)=>{"use strict";var Aae=gt().fromCallback,W1=require("path"),el=Qe(),Z1=vr(),Y1=Os().pathExists;function Oae(n,e,t){function i(r,o){el.link(r,o,s=>{if(s)return t(s);t(null)})}Y1(e,(r,o)=>{if(r)return t(r);if(o)return t(null);el.lstat(n,s=>{if(s)return s.message=s.message.replace("lstat","ensureLink"),t(s);let a=W1.dirname(e);Y1(a,(l,u)=>{if(l)return t(l);if(u)return i(n,e);Z1.mkdirs(a,c=>{if(c)return t(c);i(n,e)})})})})}function Mae(n,e){if(el.existsSync(e))return;try{el.lstatSync(n)}catch(o){throw o.message=o.message.replace("lstat","ensureLink"),o}let i=W1.dirname(e);return el.existsSync(i)||Z1.mkdirsSync(i),el.linkSync(n,e)}J1.exports={createLink:Aae(Oae),createLinkSync:Mae}});var U1=m((IEe,X1)=>{"use strict";var Ns=require("path"),vd=Qe(),Nae=Os().pathExists;function Bae(n,e,t){if(Ns.isAbsolute(n))return vd.lstat(n,i=>i?(i.message=i.message.replace("lstat","ensureSymlink"),t(i)):t(null,{toCwd:n,toDst:n}));{let i=Ns.dirname(e),r=Ns.join(i,n);return Nae(r,(o,s)=>o?t(o):s?t(null,{toCwd:r,toDst:n}):vd.lstat(n,a=>a?(a.message=a.message.replace("lstat","ensureSymlink"),t(a)):t(null,{toCwd:n,toDst:Ns.relative(i,n)})))}}function Hae(n,e){let t;if(Ns.isAbsolute(n)){if(t=vd.existsSync(n),!t)throw new Error("absolute srcpath does not exist");return{toCwd:n,toDst:n}}else{let i=Ns.dirname(e),r=Ns.join(i,n);if(t=vd.existsSync(r),t)return{toCwd:r,toDst:n};if(t=vd.existsSync(n),!t)throw new Error("relative srcpath does not exist");return{toCwd:n,toDst:Ns.relative(i,n)}}}X1.exports={symlinkPaths:Bae,symlinkPathsSync:Hae}});var K1=m((jEe,Q1)=>{"use strict";var G1=Qe();function qae(n,e,t){if(t=typeof e=="function"?e:t,e=typeof e=="function"?!1:e,e)return t(null,e);G1.lstat(n,(i,r)=>{if(i)return t(null,"file");e=r&&r.isDirectory()?"dir":"file",t(null,e)})}function Yae(n,e){let t;if(e)return e;try{t=G1.lstatSync(n)}catch{return"file"}return t&&t.isDirectory()?"dir":"file"}Q1.exports={symlinkType:qae,symlinkTypeSync:Yae}});var rA=m((AEe,nA)=>{"use strict";var Wae=gt().fromCallback,V1=require("path"),Ru=Qe(),eA=vr(),Zae=eA.mkdirs,Jae=eA.mkdirsSync,tA=U1(),$ae=tA.symlinkPaths,Xae=tA.symlinkPathsSync,iA=K1(),Uae=iA.symlinkType,Gae=iA.symlinkTypeSync,z1=Os().pathExists;function Qae(n,e,t,i){i=typeof t=="function"?t:i,t=typeof t=="function"?!1:t,z1(e,(r,o)=>{if(r)return i(r);if(o)return i(null);$ae(n,e,(s,a)=>{if(s)return i(s);n=a.toDst,Uae(a.toCwd,t,(l,u)=>{if(l)return i(l);let c=V1.dirname(e);z1(c,(h,d)=>{if(h)return i(h);if(d)return Ru.symlink(n,e,u,i);Zae(c,g=>{if(g)return i(g);Ru.symlink(n,e,u,i)})})})})})}function Kae(n,e,t){if(Ru.existsSync(e))return;let r=Xae(n,e);n=r.toDst,t=Gae(r.toCwd,t);let o=V1.dirname(e);return Ru.existsSync(o)||Jae(o),Ru.symlinkSync(n,e,t)}nA.exports={createSymlink:Wae(Qae),createSymlinkSync:Kae}});var sA=m((OEe,oA)=>{"use strict";var am=q1(),lm=$1(),um=rA();oA.exports={createFile:am.createFile,createFileSync:am.createFileSync,ensureFile:am.createFile,ensureFileSync:am.createFileSync,createLink:lm.createLink,createLinkSync:lm.createLinkSync,ensureLink:lm.createLink,ensureLinkSync:lm.createLinkSync,createSymlink:um.createSymlink,createSymlinkSync:um.createSymlinkSync,ensureSymlink:um.createSymlink,ensureSymlinkSync:um.createSymlinkSync}});var lA=m((MEe,aA)=>{"use strict";var cm=Gx();aA.exports={readJson:cm.readFile,readJsonSync:cm.readFileSync,writeJson:cm.writeFile,writeJsonSync:cm.writeFileSync}});var hm=m((NEe,hA)=>{"use strict";var zae=gt().fromCallback,wd=Qe(),uA=require("path"),cA=vr(),Vae=Os().pathExists;function ele(n,e,t,i){typeof t=="function"&&(i=t,t="utf8");let r=uA.dirname(n);Vae(r,(o,s)=>{if(o)return i(o);if(s)return wd.writeFile(n,e,t,i);cA.mkdirs(r,a=>{if(a)return i(a);wd.writeFile(n,e,t,i)})})}function tle(n,...e){let t=uA.dirname(n);if(wd.existsSync(t))return wd.writeFileSync(n,...e);cA.mkdirsSync(t),wd.writeFileSync(n,...e)}hA.exports={outputFile:zae(ele),outputFileSync:tle}});var gA=m((BEe,dA)=>{"use strict";var{stringify:ile}=Cu(),{outputFile:nle}=hm();async function rle(n,e,t={}){let i=ile(e,t);await nle(n,i,t)}dA.exports=rle});var pA=m((HEe,fA)=>{"use strict";var{stringify:ole}=Cu(),{outputFileSync:sle}=hm();function ale(n,e,t){let i=ole(e,t);sle(n,i,t)}fA.exports=ale});var bA=m((qEe,mA)=>{"use strict";var lle=gt().fromPromise,Wi=lA();Wi.outputJson=lle(gA());Wi.outputJsonSync=pA();Wi.outputJSON=Wi.outputJson;Wi.outputJSONSync=Wi.outputJsonSync;Wi.writeJSON=Wi.writeJson;Wi.writeJSONSync=Wi.writeJsonSync;Wi.readJSON=Wi.readJson;Wi.readJSONSync=Wi.readJsonSync;mA.exports=Wi});var CA=m((YEe,xA)=>{"use strict";var wA=Qe(),ule=require("path"),cle=mC().copySync,DA=yd().removeSync,hle=vr().mkdirpSync,yA=dd();function dle(n,e,t){t=t||{};let i=t.overwrite||t.clobber||!1,{srcStat:r}=yA.checkPathsSync(n,e,"move");return yA.checkParentPathsSync(n,r,e,"move"),hle(ule.dirname(e)),gle(n,e,i)}function gle(n,e,t){if(t)return DA(e),vA(n,e,t);if(wA.existsSync(e))throw new Error("dest already exists.");return vA(n,e,t)}function vA(n,e,t){try{wA.renameSync(n,e)}catch(i){if(i.code!=="EXDEV")throw i;return fle(n,e,t)}}function fle(n,e,t){return cle(n,e,{overwrite:t,errorOnExist:!0}),DA(n)}xA.exports=dle});var TA=m((WEe,SA)=>{"use strict";SA.exports={moveSync:CA()}});var RA=m((ZEe,_A)=>{"use strict";var ple=Qe(),mle=require("path"),ble=yC().copy,PA=yd().remove,yle=vr().mkdirp,vle=Os().pathExists,kA=dd();function wle(n,e,t,i){typeof t=="function"&&(i=t,t={});let r=t.overwrite||t.clobber||!1;kA.checkPaths(n,e,"move",(o,s)=>{if(o)return i(o);let{srcStat:a}=s;kA.checkParentPaths(n,a,e,"move",l=>{if(l)return i(l);yle(mle.dirname(e),u=>u?i(u):Dle(n,e,r,i))})})}function Dle(n,e,t,i){if(t)return PA(e,r=>r?i(r):EA(n,e,t,i));vle(e,(r,o)=>r?i(r):o?i(new Error("dest already exists.")):EA(n,e,t,i))}function EA(n,e,t,i){ple.rename(n,e,r=>r?r.code!=="EXDEV"?i(r):xle(n,e,t,i):i())}function xle(n,e,t,i){ble(n,e,{overwrite:t,errorOnExist:!0},o=>o?i(o):PA(n,i))}_A.exports=wle});var FA=m((JEe,LA)=>{"use strict";var Cle=gt().fromCallback;LA.exports={move:Cle(RA())}});var Rn=m(($Ee,wC)=>{"use strict";wC.exports=ge(ge(ge(ge(ge(ge(ge(ge(ge(ge(ge(ge({},hd()),mC()),yC()),M1()),sA()),bA()),vr()),TA()),FA()),hm()),Os()),yd());var IA=require("fs");Object.getOwnPropertyDescriptor(IA,"promises")&&Object.defineProperty(wC.exports,"promises",{get(){return IA.promises}})});var q=m((OA,MA)=>{"use strict";var tl=C(require("fs")),DC=C(aC()),dm=C(require("path")),jA=C(require("os")),AA=C(Rn());function xC(){let n=process.env.NVIM_COC_LOG_FILE;if(n)return n;let e=process.env.XDG_RUNTIME_DIR;if(e)try{return tl.default.accessSync(e,tl.default.constants.R_OK|tl.default.constants.W_OK),dm.default.join(e,`coc-nvim-${process.pid}.log`)}catch{}let t=jA.default.tmpdir();return e=dm.default.join(t,`coc.nvim-${process.pid}`),tl.default.existsSync(e)||(0,AA.mkdirpSync)(e),dm.default.join(e,"coc-nvim.log")}var Sle=1024*1024,Tle=10,gm=xC(),kle=process.env.NVIM_COC_LOG_LEVEL||"info";if(tl.default.existsSync(gm))try{tl.default.writeFileSync(gm,"",{encoding:"utf8",mode:438})}catch{}OA.getLogFile=xC;DC.default.configure({disableClustering:!0,appenders:{out:{type:"file",mode:438,filename:gm,maxLogSize:Sle,backups:Tle,layout:{type:"pattern",pattern:`%d{ISO8601} %p (pid:${process.pid}) [%c] - %m`}}},categories:{default:{appenders:["out"],level:kle}}});MA.exports=(n="coc-nvim")=>{let e=DC.default.getLogger(n);return Object.assign(e,{getLogFile:xC,logfile:gm})}});var CC=_(()=>{"use strict";Promise.prototype.logError=function(){this.catch(n=>{q()("util-extensions").error(n)})}});var BA=m((TC,NA)=>{NA.exports=SC(typeof Buffer<"u"&&Buffer)||SC(TC.Buffer)||SC(typeof window<"u"&&window.Buffer)||TC.Buffer;function SC(n){return n&&n.isBuffer&&n}});var fm=m((XEe,HA)=>{var Ele={}.toString;HA.exports=Array.isArray||function(n){return Ele.call(n)=="[object Array]"}});var WA=m((Fu,YA)=>{var Lu=Ln(),Fu=YA.exports=qA(0);Fu.alloc=qA;Fu.concat=Lu.concat;Fu.from=Ple;function qA(n){return new Array(n)}function Ple(n){if(!Lu.isBuffer(n)&&Lu.isView(n))n=Lu.Uint8Array.from(n);else if(Lu.isArrayBuffer(n))n=new Uint8Array(n);else{if(typeof n=="string")return Lu.from.call(Fu,n);if(typeof n=="number")throw new TypeError('"value" argument must not be a number')}return Array.prototype.slice.call(n)}});var $A=m((ju,JA)=>{var Fo=Ln(),Iu=Fo.global,ju=JA.exports=Fo.hasBuffer?ZA(0):[];ju.alloc=Fo.hasBuffer&&Iu.alloc||ZA;ju.concat=Fo.concat;ju.from=_le;function ZA(n){return new Iu(n)}function _le(n){if(!Fo.isBuffer(n)&&Fo.isView(n))n=Fo.Uint8Array.from(n);else if(Fo.isArrayBuffer(n))n=new Uint8Array(n);else{if(typeof n=="string")return Fo.from.call(ju,n);if(typeof n=="number")throw new TypeError('"value" argument must not be a number')}return Iu.from&&Iu.from.length!==1?Iu.from(n):new Iu(n)}});var GA=m((Au,UA)=>{var pm=Ln(),Au=UA.exports=pm.hasArrayBuffer?XA(0):[];Au.alloc=XA;Au.concat=pm.concat;Au.from=Rle;function XA(n){return new Uint8Array(n)}function Rle(n){if(pm.isView(n)){var e=n.byteOffset,t=n.byteLength;n=n.buffer,n.byteLength!==t&&(n.slice?n=n.slice(e,e+t):(n=new Uint8Array(n),n.byteLength!==t&&(n=Array.prototype.slice.call(n,e,e+t))))}else{if(typeof n=="string")return pm.from.call(Au,n);if(typeof n=="number")throw new TypeError('"value" argument must not be a number')}return new Uint8Array(n)}});var QA=m(mm=>{mm.copy=Ile;mm.toString=Fle;mm.write=Lle;function Lle(n,e){for(var t=this,i=e||(e|=0),r=n.length,o=0,s=0;s>>6,t[i++]=128|o&63):o<55296||o>57343?(t[i++]=224|o>>>12,t[i++]=128|o>>>6&63,t[i++]=128|o&63):(o=(o-55296<<10|n.charCodeAt(s++)-56320)+65536,t[i++]=240|o>>>18,t[i++]=128|o>>>12&63,t[i++]=128|o>>>6&63,t[i++]=128|o&63);return i-e}function Fle(n,e,t){var i=this,r=e|0;t||(t=i.length);for(var o="",s=0;r=65536?(s-=65536,o+=String.fromCharCode((s>>>10)+55296,(s&1023)+56320)):o+=String.fromCharCode(s)}return o}function Ile(n,e,t,i){var r;t||(t=0),!i&&i!==0&&(i=this.length),e||(e=0);var o=i-t;if(n===this&&t=0;r--)n[r+e]=this[r+t];else for(r=0;r{var kC=QA();Dd.copy=eO;Dd.slice=tO;Dd.toString=jle;Dd.write=Ale("write");var Bs=Ln(),KA=Bs.global,zA=Bs.hasBuffer&&"TYPED_ARRAY_SUPPORT"in KA,VA=zA&&!KA.TYPED_ARRAY_SUPPORT;function eO(n,e,t,i){var r=Bs.isBuffer(this),o=Bs.isBuffer(n);if(r&&o)return this.copy(n,e,t,i);if(!VA&&!r&&!o&&Bs.isView(this)&&Bs.isView(n)){var s=t||i!=null?tO.call(this,t,i):this;return n.set(s,e),s.length}else return kC.copy.call(this,n,e,t,i)}function tO(n,e){var t=this.slice||!VA&&this.subarray;if(t)return t.call(this,n,e);var i=Bs.alloc.call(this,e-n);return eO.call(this,i,0,n,e),i}function jle(n,e,t){var i=!zA&&Bs.isBuffer(this)?this.toString:kC.toString;return i.apply(this,arguments)}function Ale(n){return e;function e(){var t=this[n]||kC[n];return t.apply(this,arguments)}}});var Ln=m(Ti=>{var EC=Ti.global=BA(),oO=Ti.hasBuffer=EC&&!!EC.isBuffer,_C=Ti.hasArrayBuffer=typeof ArrayBuffer<"u",Ole=Ti.isArray=fm();Ti.isArrayBuffer=_C?Yle:LC;var Mle=Ti.isBuffer=oO?EC.isBuffer:LC,Nle=Ti.isView=_C?ArrayBuffer.isView||aO("ArrayBuffer","buffer"):LC;Ti.alloc=RC;Ti.concat=Hle;Ti.from=Ble;var iO=Ti.Array=WA(),nO=Ti.Buffer=$A(),rO=Ti.Uint8Array=GA(),PC=Ti.prototype=bm();function Ble(n){return typeof n=="string"?Wle.call(this,n):sO(this).from(n)}function RC(n){return sO(this).alloc(n)}function Hle(n,e){e||(e=0,Array.prototype.forEach.call(n,o));var t=this!==Ti&&this||n[0],i=RC.call(t,e),r=0;return Array.prototype.forEach.call(n,s),i;function o(a){e+=a.length}function s(a){r+=PC.copy.call(a,i,r)}}var qle=aO("ArrayBuffer");function Yle(n){return n instanceof ArrayBuffer||qle(n)}function Wle(n){var e=n.length*3,t=RC.call(this,e),i=PC.write.call(t,n);return e!==i&&(t=PC.slice.call(t,0,i)),t}function sO(n){return Mle(n)?nO:Nle(n)?rO:Ole(n)?iO:oO?nO:_C?rO:iO}function LC(){return!1}function aO(n,e){return n="[object "+n+"]",function(t){return t!=null&&{}.toString.call(e?t[e]:t)===n}}});var ym=m(lO=>{lO.ExtBuffer=FC;var Zle=Ln();function FC(n,e){if(!(this instanceof FC))return new FC(n,e);this.buffer=Zle.from(n),this.type=e}});var cO=m(uO=>{uO.setExtPackers=Xle;var vm=Ln(),Jle=vm.global,wr=vm.Uint8Array.from,IC,$le={name:1,message:1,stack:1,columnNumber:1,fileName:1,lineNumber:1};function Xle(n){n.addExtPacker(14,Error,[il,$n]),n.addExtPacker(1,EvalError,[il,$n]),n.addExtPacker(2,RangeError,[il,$n]),n.addExtPacker(3,ReferenceError,[il,$n]),n.addExtPacker(4,SyntaxError,[il,$n]),n.addExtPacker(5,TypeError,[il,$n]),n.addExtPacker(6,URIError,[il,$n]),n.addExtPacker(10,RegExp,[Ule,$n]),n.addExtPacker(11,Boolean,[jC,$n]),n.addExtPacker(12,String,[jC,$n]),n.addExtPacker(13,Date,[Number,$n]),n.addExtPacker(15,Number,[jC,$n]),typeof Uint8Array<"u"&&(n.addExtPacker(17,Int8Array,wr),n.addExtPacker(18,Uint8Array,wr),n.addExtPacker(19,Int16Array,wr),n.addExtPacker(20,Uint16Array,wr),n.addExtPacker(21,Int32Array,wr),n.addExtPacker(22,Uint32Array,wr),n.addExtPacker(23,Float32Array,wr),typeof Float64Array<"u"&&n.addExtPacker(24,Float64Array,wr),typeof Uint8ClampedArray<"u"&&n.addExtPacker(25,Uint8ClampedArray,wr),n.addExtPacker(26,ArrayBuffer,wr),n.addExtPacker(29,DataView,wr)),vm.hasBuffer&&n.addExtPacker(27,Jle,vm.from)}function $n(n){return IC||(IC=AC().encode),IC(n)}function jC(n){return n.valueOf()}function Ule(n){n=RegExp.prototype.toString.call(n).split("/"),n.shift();var e=[n.pop()];return e.unshift(n.join("/")),e}function il(n){var e={};for(var t in $le)e[t]=n[t];return e}});var wm=m(xd=>{var Gle,Qle,Kle,zle;(function(n){var e="undefined",t=e!==typeof Buffer&&Buffer,i=e!==typeof Uint8Array&&Uint8Array,r=e!==typeof ArrayBuffer&&ArrayBuffer,o=[0,0,0,0,0,0,0,0],s=Array.isArray||F,a=4294967296,l=16777216,u;Gle=c("Uint64BE",!0,!0),Qle=c("Int64BE",!0,!1),Kle=c("Uint64LE",!1,!0),zle=c("Int64LE",!1,!1);function c(L,j,W){var B=j?0:4,N=j?4:0,I=j?0:3,M=j?1:2,J=j?2:1,K=j?3:0,ae=j?v:D,je=j?w:S,_e=xi.prototype,Ve="is"+L,Et="_"+Ve;return _e.buffer=void 0,_e.offset=0,_e[Et]=!0,_e.toNumber=bp,_e.toString=Tx,_e.toJSON=bp,_e.toArray=h,t&&(_e.toBuffer=d),i&&(_e.toArrayBuffer=g),xi[Ve]=ys,n[L]=xi,xi;function xi(Re,Se,Te,Le){return this instanceof xi?Po(this,Re,Se,Te,Le):new xi(Re,Se,Te,Le)}function ys(Re){return!!(Re&&Re[Et])}function Po(Re,Se,Te,Le,It){if(i&&r&&(Se instanceof r&&(Se=new i(Se)),Le instanceof r&&(Le=new i(Le))),!Se&&!Te&&!Le&&!u){Re.buffer=b(o,0);return}if(!f(Se,Te)){var gr=u||Array;It=Te,Le=Se,Te=0,Se=new gr(8)}Re.buffer=Se,Re.offset=Te|=0,e!==typeof Le&&(typeof Le=="string"?mp(Se,Te,Le,It||10):f(Le,It)?p(Se,Te,Le,It):typeof It=="number"?(du(Se,Te+B,Le),du(Se,Te+N,It)):Le>0?ae(Se,Te,Le):Le<0?je(Se,Te,Le):p(Se,Te,o,0))}function mp(Re,Se,Te,Le){var It=0,gr=Te.length,fr=0,kn=0;Te[0]==="-"&&It++;for(var vs=It;It=0))break;kn=kn*Le+ws,fr=fr*Le+Math.floor(kn/a),kn%=a}vs&&(fr=~fr,kn?kn=a-kn:fr++),du(Re,Se+B,fr),du(Re,Se+N,kn)}function bp(){var Re=this.buffer,Se=this.offset,Te=gu(Re,Se+B),Le=gu(Re,Se+N);return W||(Te|=0),Te?Te*a+Le:Le}function Tx(Re){var Se=this.buffer,Te=this.offset,Le=gu(Se,Te+B),It=gu(Se,Te+N),gr="",fr=!W&&Le&2147483648;for(fr&&(Le=~Le,It=a-It),Re=Re||10;;){var kn=Le%Re*a+It;if(Le=Math.floor(Le/Re),It=Math.floor(kn/Re),gr=(kn%Re).toString(Re)+gr,!Le&&!It)break}return fr&&(gr="-"+gr),gr}function du(Re,Se,Te){Re[Se+K]=Te&255,Te=Te>>8,Re[Se+J]=Te&255,Te=Te>>8,Re[Se+M]=Te&255,Te=Te>>8,Re[Se+I]=Te&255}function gu(Re,Se){return Re[Se+I]*l+(Re[Se+M]<<16)+(Re[Se+J]<<8)+Re[Se+K]}}function h(L){var j=this.buffer,W=this.offset;return u=null,L!==!1&&W===0&&j.length===8&&s(j)?j:b(j,W)}function d(L){var j=this.buffer,W=this.offset;if(u=t,L!==!1&&W===0&&j.length===8&&Buffer.isBuffer(j))return j;var B=new t(8);return p(B,0,j,W),B}function g(L){var j=this.buffer,W=this.offset,B=j.buffer;if(u=i,L!==!1&&W===0&&B instanceof r&&B.byteLength===8)return B;var N=new i(8);return p(N,0,j,W),N.buffer}function f(L,j){var W=L&&L.length;return j|=0,W&&j+8<=W&&typeof L[j]!="string"}function p(L,j,W,B){j|=0,B|=0;for(var N=0;N<8;N++)L[j++]=W[B++]&255}function b(L,j){return Array.prototype.slice.call(L,j,j+8)}function v(L,j,W){for(var B=j+8;B>j;)L[--B]=W&255,W/=256}function w(L,j,W){var B=j+8;for(W++;B>j;)L[--B]=-W&255^255,W/=256}function D(L,j,W){for(var B=j+8;j{OC.read=function(n,e,t,i,r){var o,s,a=r*8-i-1,l=(1<>1,c=-7,h=t?r-1:0,d=t?-1:1,g=n[e+h];for(h+=d,o=g&(1<<-c)-1,g>>=-c,c+=a;c>0;o=o*256+n[e+h],h+=d,c-=8);for(s=o&(1<<-c)-1,o>>=-c,c+=i;c>0;s=s*256+n[e+h],h+=d,c-=8);if(o===0)o=1-u;else{if(o===l)return s?NaN:(g?-1:1)*(1/0);s=s+Math.pow(2,i),o=o-u}return(g?-1:1)*s*Math.pow(2,o-i)};OC.write=function(n,e,t,i,r,o){var s,a,l,u=o*8-r-1,c=(1<>1,d=r===23?Math.pow(2,-24)-Math.pow(2,-77):0,g=i?0:o-1,f=i?1:-1,p=e<0||e===0&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=c):(s=Math.floor(Math.log(e)/Math.LN2),e*(l=Math.pow(2,-s))<1&&(s--,l*=2),s+h>=1?e+=d/l:e+=d*Math.pow(2,1-h),e*l>=2&&(s++,l/=2),s+h>=c?(a=0,s=c):s+h>=1?(a=(e*l-1)*Math.pow(2,r),s=s+h):(a=e*Math.pow(2,h-1)*Math.pow(2,r),s=0));r>=8;n[t+g]=a&255,g+=f,a/=256,r-=8);for(s=s<0;n[t+g]=s&255,g+=f,s/=256,u-=8);n[t+g-f]|=p*128}});var NC=m(hO=>{var Vle=hO.uint8=new Array(256);for(Cd=0;Cd<=255;Cd++)Vle[Cd]=eue(Cd);var Cd;function eue(n){return function(e){var t=e.reserve(1);e.buffer[t]=n}}});var xO=m(DO=>{var gO=MC(),fO=wm(),tue=fO.Uint64BE,iue=fO.Int64BE,pO=NC().uint8,Dm=Ln(),Dt=Dm.global,nue=Dm.hasBuffer&&"TYPED_ARRAY_SUPPORT"in Dt,rue=nue&&!Dt.TYPED_ARRAY_SUPPORT,dO=Dm.hasBuffer&&Dt.prototype||{};DO.getWriteToken=oue;function oue(n){return n&&n.uint8array?sue():rue||Dm.hasBuffer&&n&&n.safe?aue():mO()}function sue(){var n=mO();return n[202]=Ke(202,4,vO),n[203]=Ke(203,8,wO),n}function mO(){var n=pO.slice();return n[196]=Sd(196),n[197]=nl(197),n[198]=rl(198),n[199]=Sd(199),n[200]=nl(200),n[201]=rl(201),n[202]=Ke(202,4,dO.writeFloatBE||vO,!0),n[203]=Ke(203,8,dO.writeDoubleBE||wO,!0),n[204]=Sd(204),n[205]=nl(205),n[206]=rl(206),n[207]=Ke(207,8,bO),n[208]=Sd(208),n[209]=nl(209),n[210]=rl(210),n[211]=Ke(211,8,yO),n[217]=Sd(217),n[218]=nl(218),n[219]=rl(219),n[220]=nl(220),n[221]=rl(221),n[222]=nl(222),n[223]=rl(223),n}function aue(){var n=pO.slice();return n[196]=Ke(196,1,Dt.prototype.writeUInt8),n[197]=Ke(197,2,Dt.prototype.writeUInt16BE),n[198]=Ke(198,4,Dt.prototype.writeUInt32BE),n[199]=Ke(199,1,Dt.prototype.writeUInt8),n[200]=Ke(200,2,Dt.prototype.writeUInt16BE),n[201]=Ke(201,4,Dt.prototype.writeUInt32BE),n[202]=Ke(202,4,Dt.prototype.writeFloatBE),n[203]=Ke(203,8,Dt.prototype.writeDoubleBE),n[204]=Ke(204,1,Dt.prototype.writeUInt8),n[205]=Ke(205,2,Dt.prototype.writeUInt16BE),n[206]=Ke(206,4,Dt.prototype.writeUInt32BE),n[207]=Ke(207,8,bO),n[208]=Ke(208,1,Dt.prototype.writeInt8),n[209]=Ke(209,2,Dt.prototype.writeInt16BE),n[210]=Ke(210,4,Dt.prototype.writeInt32BE),n[211]=Ke(211,8,yO),n[217]=Ke(217,1,Dt.prototype.writeUInt8),n[218]=Ke(218,2,Dt.prototype.writeUInt16BE),n[219]=Ke(219,4,Dt.prototype.writeUInt32BE),n[220]=Ke(220,2,Dt.prototype.writeUInt16BE),n[221]=Ke(221,4,Dt.prototype.writeUInt32BE),n[222]=Ke(222,2,Dt.prototype.writeUInt16BE),n[223]=Ke(223,4,Dt.prototype.writeUInt32BE),n}function Sd(n){return function(e,t){var i=e.reserve(2),r=e.buffer;r[i++]=n,r[i]=t}}function nl(n){return function(e,t){var i=e.reserve(3),r=e.buffer;r[i++]=n,r[i++]=t>>>8,r[i]=t}}function rl(n){return function(e,t){var i=e.reserve(5),r=e.buffer;r[i++]=n,r[i++]=t>>>24,r[i++]=t>>>16,r[i++]=t>>>8,r[i]=t}}function Ke(n,e,t,i){return function(r,o){var s=r.reserve(e+1);r.buffer[s++]=n,t.call(r.buffer,o,s,i)}}function bO(n,e){new tue(this,e,n)}function yO(n,e){new iue(this,e,n)}function vO(n,e){gO.write(this,n,e,!1,23,4)}function wO(n,e){gO.write(this,n,e,!1,52,8)}});var EO=m(kO=>{var lue=fm(),TO=wm(),uue=TO.Uint64BE,cue=TO.Int64BE,CO=Ln(),SO=bm(),hue=xO(),due=NC().uint8,gue=ym().ExtBuffer,fue=typeof Uint8Array<"u",pue=typeof Map<"u",Ou=[];Ou[1]=212;Ou[2]=213;Ou[4]=214;Ou[8]=215;Ou[16]=216;kO.getWriteType=mue;function mue(n){var e=hue.getWriteToken(n),t=n&&n.useraw,i=fue&&n&&n.binarraybuffer,r=i?CO.isArrayBuffer:CO.isBuffer,o=i?F:S,s=pue&&n&&n.usemap,a=s?W:j,l={boolean:u,function:w,number:c,object:t?v:b,string:p(t?f:g),symbol:w,undefined:w};return l;function u(N,I){var M=I?195:194;e[M](N,I)}function c(N,I){var M=I|0,J;if(I!==M){J=203,e[J](N,I);return}else-32<=M&&M<=127?J=M&255:0<=M?J=M<=255?204:M<=65535?205:206:J=-128<=M?208:-32768<=M?209:210;e[J](N,M)}function h(N,I){var M=207;e[M](N,I.toArray())}function d(N,I){var M=211;e[M](N,I.toArray())}function g(N){return N<32?1:N<=255?2:N<=65535?3:5}function f(N){return N<32?1:N<=65535?3:5}function p(N){return I;function I(M,J){var K=J.length,ae=5+K*3;M.offset=M.reserve(ae);var je=M.buffer,_e=N(K),Ve=M.offset+_e;K=SO.write.call(je,J,Ve);var Et=N(K);if(_e!==Et){var xi=Ve+Et-_e,ys=Ve+K;SO.copy.call(je,je,xi,Ve,ys)}var Po=Et===1?160+K:Et<=3?215+Et:219;e[Po](M,K),M.offset+=K}}function b(N,I){if(I===null)return w(N,I);if(r(I))return o(N,I);if(lue(I))return D(N,I);if(uue.isUint64BE(I))return h(N,I);if(cue.isInt64BE(I))return d(N,I);var M=N.codec.getExtPacker(I);if(M&&(I=M(I)),I instanceof gue)return L(N,I);a(N,I)}function v(N,I){if(r(I))return B(N,I);b(N,I)}function w(N,I){var M=192;e[M](N,I)}function D(N,I){var M=I.length,J=M<16?144+M:M<=65535?220:221;e[J](N,M);for(var K=N.codec.encode,ae=0;ae{var bue=fm();Td.createCodec=PO;Td.install=vue;Td.filter=xue;var yue=Ln();function Mu(n){if(!(this instanceof Mu))return new Mu(n);this.options=n,this.init()}Mu.prototype.init=function(){var n=this.options;return n&&n.uint8array&&(this.bufferish=yue.Uint8Array),this};function vue(n){for(var e in n)Mu.prototype[e]=wue(Mu.prototype[e],n[e])}function wue(n,e){return n&&e?t:n||e;function t(){return n.apply(this,arguments),e.apply(this,arguments)}}function Due(n){return n=n.slice(),function(t){return n.reduce(e,t)};function e(t,i){return i(t)}}function xue(n){return bue(n)?Due(n):n}function PO(n){return new Mu(n)}Td.preset=PO({preset:!0})});var xm=m(RO=>{var Cue=ym().ExtBuffer,Sue=cO(),Tue=EO(),BC=kd();BC.install({addExtPacker:Eue,getExtPacker:Pue,init:_O});RO.preset=_O.call(BC.preset);function kue(n){var e=Tue.getWriteType(n);return t;function t(i,r){var o=e[typeof r];if(!o)throw new Error('Unsupported type "'+typeof r+'": '+r);o(i,r)}}function _O(){var n=this.options;return this.encode=kue(n),n&&n.preset&&Sue.setExtPackers(this),this}function Eue(n,e,t){t=BC.filter(t);var i=e.name;if(i&&i!=="Object"){var r=this.extPackers||(this.extPackers={});r[i]=s}else{var o=this.extEncoderList||(this.extEncoderList=[]);o.unshift([e,s])}function s(a){return t&&(a=t(a)),new Cue(a,n)}}function Pue(n){var e=this.extPackers||(this.extPackers={}),t=n.constructor,i=t&&t.name&&e[t.name];if(i)return i;for(var r=this.extEncoderList||(this.extEncoderList=[]),o=r.length,s=0;s{HC.FlexDecoder=Nu;HC.FlexEncoder=Bu;var Ed=Ln(),_ue=2048,Rue=65536,LO="BUFFER_SHORTAGE";function Nu(){if(!(this instanceof Nu))return new Nu}function Bu(){if(!(this instanceof Bu))return new Bu}Nu.mixin=jO(Lue());Nu.mixin(Nu.prototype);Bu.mixin=jO(Fue());Bu.mixin(Bu.prototype);function Lue(){return{bufferish:Ed,write:n,fetch:jue,flush:e,push:IO,pull:Aue,read:FO,reserve:t,offset:0};function n(i){var r=this.offset?Ed.prototype.slice.call(this.buffer,this.offset):this.buffer;this.buffer=r?i?this.bufferish.concat([r,i]):r:i,this.offset=0}function e(){for(;this.offsetthis.buffer.length)throw new Error(LO);return this.offset=o,r}}function Fue(){return{bufferish:Ed,write:Iue,fetch:n,flush:e,push:IO,pull:t,read:FO,reserve:i,send:r,maxBufferSize:Rue,minBufferSize:_ue,offset:0,start:0};function n(){var o=this.start;if(o1?this.bufferish.concat(o):o[0];return o.length=0,s}function i(o){var s=o|0;if(this.buffer){var a=this.buffer.length,l=this.offset|0,u=l+s;if(uthis.minBufferSize)this.flush(),this.push(o);else{var a=this.reserve(s);Ed.prototype.copy.call(o,this.buffer,a)}}}function Iue(){throw new Error("method not implemented: write()")}function jue(){throw new Error("method not implemented: fetch()")}function FO(){var n=this.buffers&&this.buffers.length;return n?(this.flush(),this.pull()):this.fetch()}function IO(n){var e=this.buffers||(this.buffers=[]);e.push(n)}function Aue(){var n=this.buffers||(this.buffers=[]);return n.shift()}function jO(n){return e;function e(t){for(var i in n)t[i]=n[i];return t}}});var Cm=m(AO=>{AO.EncodeBuffer=Hu;var Oue=xm().preset,Mue=qC().FlexEncoder;Mue.mixin(Hu.prototype);function Hu(n){if(!(this instanceof Hu))return new Hu(n);if(n&&(this.options=n,n.codec)){var e=this.codec=n.codec;e.bufferish&&(this.bufferish=e.bufferish)}}Hu.prototype.codec=Oue;Hu.prototype.write=function(n){this.codec.encode(this,n)}});var AC=m(OO=>{OO.encode=Bue;var Nue=Cm().EncodeBuffer;function Bue(n,e){var t=new Nue(e);return t.write(n),t.read()}});var BO=m(NO=>{NO.setExtUnpackers=Yue;var MO=Ln(),Hue=MO.global,YC,que={name:1,message:1,stack:1,columnNumber:1,fileName:1,lineNumber:1};function Yue(n){n.addExtUnpacker(14,[Xn,ol(Error)]),n.addExtUnpacker(1,[Xn,ol(EvalError)]),n.addExtUnpacker(2,[Xn,ol(RangeError)]),n.addExtUnpacker(3,[Xn,ol(ReferenceError)]),n.addExtUnpacker(4,[Xn,ol(SyntaxError)]),n.addExtUnpacker(5,[Xn,ol(TypeError)]),n.addExtUnpacker(6,[Xn,ol(URIError)]),n.addExtUnpacker(10,[Xn,Wue]),n.addExtUnpacker(11,[Xn,Zi(Boolean)]),n.addExtUnpacker(12,[Xn,Zi(String)]),n.addExtUnpacker(13,[Xn,Zi(Date)]),n.addExtUnpacker(15,[Xn,Zi(Number)]),typeof Uint8Array<"u"&&(n.addExtUnpacker(17,Zi(Int8Array)),n.addExtUnpacker(18,Zi(Uint8Array)),n.addExtUnpacker(19,[Hs,Zi(Int16Array)]),n.addExtUnpacker(20,[Hs,Zi(Uint16Array)]),n.addExtUnpacker(21,[Hs,Zi(Int32Array)]),n.addExtUnpacker(22,[Hs,Zi(Uint32Array)]),n.addExtUnpacker(23,[Hs,Zi(Float32Array)]),typeof Float64Array<"u"&&n.addExtUnpacker(24,[Hs,Zi(Float64Array)]),typeof Uint8ClampedArray<"u"&&n.addExtUnpacker(25,Zi(Uint8ClampedArray)),n.addExtUnpacker(26,Hs),n.addExtUnpacker(29,[Hs,Zi(DataView)])),MO.hasBuffer&&n.addExtUnpacker(27,Zi(Hue))}function Xn(n){return YC||(YC=WC().decode),YC(n)}function Wue(n){return RegExp.apply(null,n)}function ol(n){return function(e){var t=new n;for(var i in que)t[i]=e[i];return t}}function Zi(n){return function(e){return new n(e)}}function Hs(n){return new Uint8Array(n).buffer}});var $C=m(JC=>{var HO=MC(),qO=wm(),YO=qO.Uint64BE,WO=qO.Int64BE;JC.getReadFormat=$ue;JC.readUint8=ZO;var ZC=Ln(),Tm=bm(),Zue=typeof Map<"u",Jue=!0;function $ue(n){var e=ZC.hasArrayBuffer&&n&&n.binarraybuffer,t=n&&n.int64,i=Zue&&n&&n.usemap,r={map:i?Uue:Xue,array:Gue,str:Que,bin:e?zue:Kue,ext:Vue,uint8:ZO,uint16:tce,uint32:nce,uint64:Sm(8,t?ace:oce),int8:ece,int16:ice,int32:rce,int64:Sm(8,t?lce:sce),float32:Sm(4,uce),float64:Sm(8,cce)};return r}function Xue(n,e){var t={},i,r=new Array(e),o=new Array(e),s=n.codec.decode;for(i=0;i{var hce=$C();$O.getReadToken=dce;function dce(n){var e=hce.getReadFormat(n);return n&&n.useraw?gce(e):JO(e)}function JO(n){var e,t=new Array(256);for(e=0;e<=127;e++)t[e]=Pd(e);for(e=128;e<=143;e++)t[e]=Io(e-128,n.map);for(e=144;e<=159;e++)t[e]=Io(e-144,n.array);for(e=160;e<=191;e++)t[e]=Io(e-160,n.str);for(t[192]=Pd(null),t[193]=null,t[194]=Pd(!1),t[195]=Pd(!0),t[196]=Fn(n.uint8,n.bin),t[197]=Fn(n.uint16,n.bin),t[198]=Fn(n.uint32,n.bin),t[199]=Fn(n.uint8,n.ext),t[200]=Fn(n.uint16,n.ext),t[201]=Fn(n.uint32,n.ext),t[202]=n.float32,t[203]=n.float64,t[204]=n.uint8,t[205]=n.uint16,t[206]=n.uint32,t[207]=n.uint64,t[208]=n.int8,t[209]=n.int16,t[210]=n.int32,t[211]=n.int64,t[212]=Io(1,n.ext),t[213]=Io(2,n.ext),t[214]=Io(4,n.ext),t[215]=Io(8,n.ext),t[216]=Io(16,n.ext),t[217]=Fn(n.uint8,n.str),t[218]=Fn(n.uint16,n.str),t[219]=Fn(n.uint32,n.str),t[220]=Fn(n.uint16,n.array),t[221]=Fn(n.uint32,n.array),t[222]=Fn(n.uint16,n.map),t[223]=Fn(n.uint32,n.map),e=224;e<=255;e++)t[e]=Pd(e-256);return t}function gce(n){var e,t=JO(n).slice();for(t[217]=t[196],t[218]=t[197],t[219]=t[198],e=160;e<=191;e++)t[e]=Io(e-160,n.bin);return t}function Pd(n){return function(){return n}}function Fn(n,e){return function(t){var i=n(t);return e(t,i)}}function Io(n,e){return function(t){return e(t,n)}}});var km=m(GO=>{var fce=ym().ExtBuffer,pce=BO(),mce=$C().readUint8,bce=XO(),XC=kd();XC.install({addExtUnpacker:vce,getExtUnpacker:wce,init:UO});GO.preset=UO.call(XC.preset);function yce(n){var e=bce.getReadToken(n);return t;function t(i){var r=mce(i),o=e[r];if(!o)throw new Error("Invalid type: "+(r&&"0x"+r.toString(16)));return o(i)}}function UO(){var n=this.options;return this.decode=yce(n),n&&n.preset&&pce.setExtUnpackers(this),this}function vce(n,e){var t=this.extUnpackers||(this.extUnpackers=[]);t[n]=XC.filter(e)}function wce(n){var e=this.extUnpackers||(this.extUnpackers=[]);return e[n]||t;function t(i){return new fce(i,n)}}});var Em=m(QO=>{QO.DecodeBuffer=qu;var Dce=km().preset,xce=qC().FlexDecoder;xce.mixin(qu.prototype);function qu(n){if(!(this instanceof qu))return new qu(n);if(n&&(this.options=n,n.codec)){var e=this.codec=n.codec;e.bufferish&&(this.bufferish=e.bufferish)}}qu.prototype.codec=Dce;qu.prototype.fetch=function(){return this.codec.decode(this)}});var WC=m(KO=>{KO.decode=Sce;var Cce=Em().DecodeBuffer;function Sce(n,e){var t=new Cce(e);return t.write(n),t.read()}});var QC=m((pPe,GC)=>{function UC(){if(!(this instanceof UC))return new UC}(function(n){typeof GC<"u"&&(GC.exports=n);var e="listeners",t={on:r,once:o,off:s,emit:a};i(n.prototype),n.mixin=i;function i(u){for(var c in t)u[c]=t[c];return u}function r(u,c){return l(this,u).push(c),this}function o(u,c){var h=this;return d.originalListener=c,l(h,u).push(d),h;function d(){s.call(h,u,d),c.apply(this,arguments)}}function s(u,c){var h=this,d;if(!arguments.length)delete h[e];else if(c){if(d=l(h,u,!0),d){if(d=d.filter(g),!d.length)return s.call(h,u);h[e][u]=d}}else if(d=h[e],d&&(delete d[u],!Object.keys(d).length))return s.call(h);return h;function g(f){return f!==c&&f.originalListener!==c}}function a(u,c){var h=this,d=l(h,u,!0);if(!d)return!1;var g=arguments.length;if(g===1)d.forEach(p);else if(g===2)d.forEach(b);else{var f=Array.prototype.slice.call(arguments,1);d.forEach(v)}return!!d.length;function p(w){w.call(h)}function b(w){w.call(h,c)}function v(w){w.apply(h,f)}}function l(u,c,h){if(!(h&&!u[e])){var d=u[e]||(u[e]={});return d[c]||(d[c]=[])}}})(UC)});var eM=m(VO=>{VO.Encoder=sl;var Tce=QC(),zO=Cm().EncodeBuffer;function sl(n){if(!(this instanceof sl))return new sl(n);zO.call(this,n)}sl.prototype=new zO;Tce.mixin(sl.prototype);sl.prototype.encode=function(n){this.write(n),this.emit("data",this.read())};sl.prototype.end=function(n){arguments.length&&this.encode(n),this.flush(),this.emit("end")}});var nM=m(iM=>{iM.Decoder=qs;var kce=QC(),tM=Em().DecodeBuffer;function qs(n){if(!(this instanceof qs))return new qs(n);tM.call(this,n)}qs.prototype=new tM;kce.mixin(qs.prototype);qs.prototype.decode=function(n){arguments.length&&this.write(n),this.flush()};qs.prototype.push=function(n){this.emit("data",n)};qs.prototype.end=function(n){this.decode(n),this.emit("end")}});var sM=m(oM=>{oM.createEncodeStream=Yu;var Ece=require("util"),rM=require("stream").Transform,Pce=Cm().EncodeBuffer;Ece.inherits(Yu,rM);var _ce={objectMode:!0};function Yu(n){if(!(this instanceof Yu))return new Yu(n);n?n.objectMode=!0:n=_ce,rM.call(this,n);var e=this,t=this.encoder=new Pce(n);t.push=function(i){e.push(i)}}Yu.prototype._transform=function(n,e,t){this.encoder.write(n),t&&t()};Yu.prototype._flush=function(n){this.encoder.flush(),n&&n()}});var uM=m(lM=>{lM.createDecodeStream=_d;var Rce=require("util"),aM=require("stream").Transform,Lce=Em().DecodeBuffer;Rce.inherits(_d,aM);var Fce={objectMode:!0};function _d(n){if(!(this instanceof _d))return new _d(n);n?n.objectMode=!0:n=Fce,aM.call(this,n);var e=this,t=this.decoder=new Lce(n);t.push=function(i){e.push(i)}}_d.prototype._transform=function(n,e,t){this.decoder.write(n),this.decoder.flush(),t&&t()}});var hM=m(cM=>{km();xm();cM.createCodec=kd().createCodec});var gM=m(dM=>{km();xm();dM.codec={preset:kd().preset}});var fM=m(jo=>{jo.encode=AC().encode;jo.decode=WC().decode;jo.Encoder=eM().Encoder;jo.Decoder=nM().Decoder;jo.createEncodeStream=sM().createEncodeStream;jo.createDecodeStream=uM().createDecodeStream;jo.createCodec=hM().createCodec;jo.codec=gM().codec});var mM=m(KC=>{"use strict";Object.defineProperty(KC,"__esModule",{value:!0});var Ice=require("stream"),pM=class extends Ice.Transform{constructor(){super({readableHighWaterMark:10*1024*1024,writableHighWaterMark:10*1024*1024});this.chunks=null,this.timer=null}sendData(){let{chunks:e}=this;if(e){this.chunks=null;let t=Buffer.concat(e);this.push(t)}}_transform(e,t,i){let{chunks:r,timer:o}=this,s=Buffer.poolSize;if(o&&clearTimeout(o),e.length{"use strict";Object.defineProperty(Pm,"__esModule",{value:!0});Pm.BaseApi=void 0;var jce=require("events"),Ace=process.env.VIM_NODE_RPC=="1",bM=class extends jce.EventEmitter{constructor({transport:e,data:t,client:i}){super();this.setTransport(e),this.data=t,this.client=i}setTransport(e){this.transport=e}equals(e){try{return String(this.data)===String(e.data)}catch{return!1}}async request(e,t=[]){let i=Error().stack;return new Promise((r,o)=>{this.transport.request(e,this.getArgsByPrefix(t),(s,a)=>{if(s){let l=new Error(`${s[1].split(/\r?\n/)[0]}`);l.stack=`Error: request error on ${e} - ${s[1]} -`+i.split(/\r?\n/).slice(3).join(` -`),e.endsWith("get_var")||this.client.logError(`request error on "${e}"`,t,s[1],i),o(l)}else r(a)})})}getArgsByPrefix(e){return this.prefix!=="nvim_"&&e[0]!=this?[Ace?this.data:this,...e]:e}getVar(e){return this.request(`${this.prefix}get_var`,[e]).then(t=>t,t=>null)}setVar(e,t,i=!1){if(i){this.notify(`${this.prefix}set_var`,[e,t]);return}return this.request(`${this.prefix}set_var`,[e,t])}deleteVar(e){this.notify(`${this.prefix}del_var`,[e])}getOption(e){return this.request(`${this.prefix}get_option`,[e])}setOption(e,t,i){if(i){this.notify(`${this.prefix}set_option`,[e,t]);return}return this.request(`${this.prefix}set_option`,[e,t])}notify(e,t=[]){this.transport.notify(e,this.getArgsByPrefix(t))}};Pm.BaseApi=bM});var Ld=m(_m=>{"use strict";Object.defineProperty(_m,"__esModule",{value:!0});_m.Buffer=void 0;var Oce=Rd(),yM=class extends Oce.BaseApi{constructor(){super(...arguments);this.prefix="nvim_buf_"}async attach(e=!1,t={}){return await this.request(`${this.prefix}attach`,[e,t])}async detach(){return await this.request(`${this.prefix}detach`,[])}get id(){return this.data}get length(){return this.request(`${this.prefix}line_count`,[])}get lines(){return this.getLines()}get changedtick(){return this.request(`${this.prefix}get_changedtick`,[])}get commands(){return this.getCommands()}getCommands(e={}){return this.request(`${this.prefix}get_commands`,[e])}getLines({start:e,end:t,strictIndexing:i}={start:0,end:-1,strictIndexing:!0}){let r=typeof i>"u"?!0:i;return this.request(`${this.prefix}get_lines`,[e,t,r])}setLines(e,t,i=!1){let{start:r,end:o,strictIndexing:s}=t!=null?t:{};r=r!=null?r:0,o=o!=null?o:r+1;let a=s!=null?s:!0;return this[i?"notify":"request"](`${this.prefix}set_lines`,[r,o,a,typeof e=="string"?[e]:e])}setVirtualText(e,t,i,r={}){return this.client.isVim?Promise.resolve(-1):(this.notify(`${this.prefix}set_virtual_text`,[e,t,i,r]),Promise.resolve(e))}deleteExtMark(e,t){this.client.isVim||this.notify(`${this.prefix}del_extmark`,[e,t])}async getExtMarkById(e,t,i={}){return this.client.isVim?Promise.resolve([]):this.request(`${this.prefix}get_extmark_by_id`,[e,t,i])}async getExtMarks(e,t,i,r={}){return this.client.isVim?Promise.resolve([]):this.request(`${this.prefix}get_extmarks`,[e,t,i,r])}setExtMark(e,t,i,r={}){this.client.isVim||this.notify(`${this.prefix}set_extmark`,[e,t,i,r])}insert(e,t){return this.setLines(e,{start:t,end:t,strictIndexing:!0})}replace(e,t){let i=typeof e=="string"?[e]:e;return this.setLines(i,{start:t,end:t+i.length,strictIndexing:!1})}remove(e,t,i=!1){return this.setLines([],{start:e,end:t,strictIndexing:i})}append(e){return this.setLines(e,{start:-1,end:-1,strictIndexing:!1})}get name(){return this.request(`${this.prefix}get_name`,[])}setName(e){return this.request(`${this.prefix}set_name`,[e])}get valid(){return this.request(`${this.prefix}is_valid`,[])}mark(e){return this.request(`${this.prefix}get_mark`,[e])}getKeymap(e){return this.request(`${this.prefix}get_keymap`,[e])}setKeymap(e,t,i,r={}){this.client.call("coc#compat#buf_add_keymap",[this.id,e,t,i,r],!0)}get loaded(){return this.request(`${this.prefix}is_loaded`,[])}getOffset(e){return this.request(`${this.prefix}get_offset`,[e])}addHighlight({hlGroup:e,line:t,colStart:i,colEnd:r,srcId:o}){if(!e)throw new Error("hlGroup should not empty");let s=typeof r<"u"?r:-1,a=typeof i<"u"?i:-0,l=typeof o<"u"?o:-1,u=l==0?"request":"notify",c=this[u](`${this.prefix}add_highlight`,[l,e,t,a,s]);return u==="request"?c:Promise.resolve(null)}clearHighlight(e={}){let t={srcId:-1,lineStart:0,lineEnd:-1},{srcId:i,lineStart:r,lineEnd:o}=Object.assign({},t,e);return this.notify(`${this.prefix}clear_highlight`,[i,r,o])}highlightRanges(e,t,i){this.client.call("coc#highlight#ranges",[this.id,e,t,i],!0)}clearNamespace(e,t=0,i=-1){this.client.call("coc#highlight#clear_highlight",[this.id,e,t,i],!0)}placeSign(e){let t={lnum:e.lnum};typeof e.priority=="number"&&(t.priority=e.priority),this.client.call("sign_place",[e.id||0,e.group||"",e.name,this.id,t],!0)}unplaceSign(e){let t={buffer:this.id};e.id!=null&&(t.id=e.id),this.client.call("sign_unplace",[e.group||"",t],!0)}async getSigns(e){return(await this.client.call("sign_getplaced",[this.id,e||{}]))[0].signs}async getHighlights(e,t=0,i=-1){let r=[],o=await this.client.call("coc#highlight#get_highlights",[this.id,e,t,i]);for(let s of o)r.push({hlGroup:s[0],lnum:s[1],colStart:s[2],colEnd:s[3],id:s[4]});return r}updateHighlights(e,t,i={}){if(typeof i=="number"){this.client.logError("Bad option for buffer.updateHighlights()",new Error().stack);return}let r=typeof i.start=="number"?i.start:0,o=typeof i.end=="number"?i.end:-1,s=typeof i.changedtick=="number"?i.changedtick:null,a=typeof i.priority=="number"?i.priority:null;if(r==0&&o==-1){let l=t.map(u=>[u.hlGroup,u.lnum,u.colStart,u.colEnd,u.combine===!1?0:1,u.start_incl?1:0,u.end_incl?1:0]);this.client.call("coc#highlight#buffer_update",[this.id,e,l,a,s],!0);return}this.client.call("coc#highlight#update_highlights",[this.id,e,t,r,o,a,s],!0)}listen(e,t,i){this.client.attachBufferEvent(this,e,t),i&&i.push({dispose:()=>{this.client.detachBufferEvent(this,e,t)}})}};_m.Buffer=yM});var Fd=m(Rm=>{"use strict";Object.defineProperty(Rm,"__esModule",{value:!0});Rm.Window=void 0;var Mce=Rd(),zC=require("timers"),vM=class extends Mce.BaseApi{constructor(){super(...arguments);this.prefix="nvim_win_"}get id(){return this.data}get buffer(){return this.request(`${this.prefix}get_buf`,[])}get tabpage(){return this.request(`${this.prefix}get_tabpage`,[])}get cursor(){return this.request(`${this.prefix}get_cursor`,[])}setCursor(e,t=!1){return this[t?"notify":"request"](`${this.prefix}set_cursor`,[e])}get height(){return this.request(`${this.prefix}get_height`,[])}setHeight(e,t=!1){return this[t?"notify":"request"](`${this.prefix}set_height`,[e])}get width(){return this.request(`${this.prefix}get_width`,[])}setWidth(e,t=!1){return this[t?"notify":"request"](`${this.prefix}set_height`,[e])}get position(){return this.request(`${this.prefix}get_position`,[])}get row(){return this.request(`${this.prefix}get_position`,[]).then(e=>e[0])}get col(){return this.request(`${this.prefix}get_position`,[]).then(e=>e[1])}get valid(){return this.request(`${this.prefix}is_valid`,[])}get number(){return this.request(`${this.prefix}get_number`,[])}setConfig(e,t){return this[t?"notify":"request"](`${this.prefix}set_config`,[e])}getConfig(){return this.request(`${this.prefix}get_config`,[])}close(e,t){if(t){this.notify(`${this.prefix}close`,[e]);let i=0,r=setInterval(()=>{if(i==5)return(0,zC.clearInterval)(r);this.request(`${this.prefix}is_valid`,[]).then(o=>{o?this.notify(`${this.prefix}close`,[e]):(0,zC.clearInterval)(r)},()=>{(0,zC.clearInterval)(r)}),i++},50);return null}return this.request(`${this.prefix}close`,[e])}highlightRanges(e,t,i=10,r){if(r){this.client.call("coc#highlight#match_ranges",[this.id,0,t,e,i],!0);return}return this.client.call("coc#highlight#match_ranges",[this.id,0,t,e,i])}clearMatchGroup(e){this.client.call("coc#highlight#clear_match_group",[this.id,e],!0)}clearMatches(e){this.client.call("coc#highlight#clear_matches",[this.id,e],!0)}};Rm.Window=vM});var Id=m(Lm=>{"use strict";Object.defineProperty(Lm,"__esModule",{value:!0});Lm.Tabpage=void 0;var Nce=Rd(),wM=class extends Nce.BaseApi{constructor(){super(...arguments);this.prefix="nvim_tabpage_"}get windows(){return this.request(`${this.prefix}list_wins`,[])}get window(){return this.request(`${this.prefix}get_win`,[])}get valid(){return this.request(`${this.prefix}is_valid`,[])}get number(){return this.request(`${this.prefix}get_number`,[])}getOption(){throw new Error("Tabpage does not have `getOption`")}setOption(){throw new Error("Tabpage does not have `setOption`")}};Lm.Tabpage=wM});var DM=m(al=>{"use strict";Object.defineProperty(al,"__esModule",{value:!0});al.Metadata=al.ExtType=void 0;var Bce=Ld(),Hce=Fd(),qce=Id(),Yce;(function(n){n[n.Buffer=0]="Buffer",n[n.Window=1]="Window",n[n.Tabpage=2]="Tabpage"})(Yce=al.ExtType||(al.ExtType={}));al.Metadata=[{constructor:Bce.Buffer,name:"Buffer",prefix:"nvim_buf_"},{constructor:Hce.Window,name:"Window",prefix:"nvim_win_"},{constructor:qce.Tabpage,name:"Tabpage",prefix:"nvim_tabpage_"}]});var Wu=m(Ys=>{"use strict";var nS=Ys&&Ys.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Ys,"__esModule",{value:!0});Ys.createLogger=Ys.nullLogger=void 0;var VC=nS(require("fs")),Wce=nS(require("os")),eS=nS(require("path"));Ys.nullLogger={debug:()=>{},info:()=>{},warn:()=>{},error:()=>{},trace:()=>{}};function Zce(){let n=process.env.NODE_CLIENT_LOG_FILE;if(n)return n;let e=process.env.XDG_RUNTIME_DIR;return e?eS.default.join(e,"node-client.log"):eS.default.join(Wce.default.tmpdir(),`node-client-${process.pid}.log`)}var tS=Zce(),xM=process.env.NODE_CLIENT_LOG_LEVEL||"info",iS=process.getuid&&process.getuid()==0;if(!iS)try{VC.default.mkdirSync(eS.default.dirname(tS),{recursive:!0}),VC.default.writeFileSync(tS,"",{encoding:"utf8",mode:438})}catch{iS=!0}function CM(n){return n==null?n:Array.isArray(n)?n.map(e=>CM(e)):typeof n=="object"&&typeof n.prefix=="string"&&typeof n.data=="number"?"["+n.prefix+n.data+"]":n}function Jce(n){return n==null?String(n):typeof n=="object"?JSON.stringify(n,null,2):String(n)}function $ce(n){return`${n.getHours()}:${n.getMinutes()}:${n.getSeconds()}.${n.getMilliseconds()}`}var SM=class{constructor(e){this.name=e}get stream(){return iS?null:this._stream?this._stream:(this._stream=VC.default.createWriteStream(tS,{encoding:"utf8"}),this._stream)}getText(e,t,i){let r="";if(i.length){let o=CM(i);r=" "+o.map(s=>Jce(s))}return`${$ce(new Date)} ${e.toUpperCase()} [${this.name}] - ${t}${r} -`}debug(e,...t){xM!="debug"||this.stream==null||this.stream.write(this.getText("debug",e,t))}info(e,...t){this.stream!=null&&this.stream.write(this.getText("info",e,t))}warn(e,...t){this.stream!=null&&this.stream.write(this.getText("warn",e,t))}error(e,...t){this.stream!=null&&this.stream.write(this.getText("error",e,t))}trace(e,...t){xM!="trace"||this.stream==null||this.stream.write(this.getText("trace",e,t))}};function Xce(n){return new SM(n)}Ys.createLogger=Xce});var oS=m(rS=>{"use strict";Object.defineProperty(rS,"__esModule",{value:!0});var Uce=require("events"),Gce=Wu(),TM=process.env.NODE_CLIENT_LOG_LEVEL=="debug",jd=(0,Gce.createLogger)("transport"),kM=class extends Uce.EventEmitter{constructor(e){super();this.logger=e,this.pauseLevel=0,this.paused=new Map}debug(e,...t){!TM||jd.debug(e,...t)}info(e,...t){jd.info(e,...t)}debugMessage(e){if(!TM)return;let t=e[0];t==0?jd.debug("receive request:",e.slice(1)):t==1||(t==2?jd.debug("receive notification:",e.slice(1)):jd.debug("unknown message:",e))}pauseNotification(){this.pauseLevel=this.pauseLevel+1,this.paused.set(this.pauseLevel,[])}cancelNotification(){let{pauseLevel:e}=this;e>0&&(this.paused.delete(e),this.pauseLevel=e-1)}resumeNotification(e=!1){let{pauseLevel:t}=this;if(t==0)return e?null:Promise.resolve([[],null]);let i=Error().stack;this.pauseLevel=t-1;let r=this.paused.get(t);return this.paused.delete(t),r&&r.length?new Promise((o,s)=>{if(!e)return this.request("nvim_call_atomic",[r],(a,l)=>{if(a){let u=new Error(`call_atomic error: ${a[1]}`);return u.stack=i,s(u)}if(Array.isArray(l)&&l[1]!=null){let[u,c,h]=l[1],[d,g]=r[u],f=new Error(`call_atomic request error on "${d}": ${h}`);return f.stack=i,this.logger.error(`call_atomic request error ${c} on "${d}"`,g,h,i),s(f)}o(l)});this.notify("nvim_call_atomic",[r]),o(void 0)}):e?null:Promise.resolve([[],void 0])}};rS.default=kM});var _M=m(Un=>{"use strict";var Qce=Un&&Un.__createBinding||(Object.create?function(n,e,t,i){i===void 0&&(i=t);var r=Object.getOwnPropertyDescriptor(e,t);(!r||("get"in r?!e.__esModule:r.writable||r.configurable))&&(r={enumerable:!0,get:function(){return e[t]}}),Object.defineProperty(n,i,r)}:function(n,e,t,i){i===void 0&&(i=t),n[i]=e[t]}),Kce=Un&&Un.__setModuleDefault||(Object.create?function(n,e){Object.defineProperty(n,"default",{enumerable:!0,value:e})}:function(n,e){n.default=e}),zce=Un&&Un.__importStar||function(n){if(n&&n.__esModule)return n;var e={};if(n!=null)for(var t in n)t!=="default"&&Object.prototype.hasOwnProperty.call(n,t)&&Qce(e,n,t);return Kce(e,n),e},EM=Un&&Un.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Un,"__esModule",{value:!0});Un.NvimTransport=void 0;var Ao=zce(fM()),Vce=EM(mM()),ehe=DM(),the=EM(oS()),PM=class extends the.default{constructor(e){super(e);this.pending=new Map,this.nextRequestId=1,this.attached=!1;let t=this.setupCodec();this.encodeStream=Ao.createEncodeStream({codec:t}),this.decodeStream=Ao.createDecodeStream({codec:t}),this.decodeStream.on("data",i=>{this.parseMessage(i)}),this.decodeStream.on("end",()=>{this.detach(),this.emit("detach")})}parseMessage(e){let t=e[0];if(this.debugMessage(e),t===0)this.emit("request",e[2].toString(),e[3],this.createResponse(e[1]));else if(t===1){let i=e[1],r=this.pending.get(i);if(r){this.pending.delete(i);let o=e[2];o&&o.length!=2&&(o=[0,o instanceof Error?o.message:o]),r(o,e[3])}}else t===2?this.emit("notification",e[1].toString(),e[2]):console.error(`Invalid message type ${t}`)}setupCodec(){let e=Ao.createCodec();return ehe.Metadata.forEach(({constructor:t},i)=>{e.addExtPacker(i,t,r=>Ao.encode(r.data)),e.addExtUnpacker(i,r=>new t({transport:this,client:this.client,data:Ao.decode(r)}))}),this.codec=e,this.codec}attach(e,t,i){this.encodeStream=this.encodeStream.pipe(e);let r=new Vce.default;t.pipe(r).pipe(this.decodeStream),this.writer=e,this.reader=t,this.client=i,this.attached=!0}detach(){!this.attached||(this.attached=!1,this.encodeStream.unpipe(this.writer),this.reader.unpipe(this.decodeStream))}request(e,t,i){if(!this.attached)return;let r=this.nextRequestId;this.nextRequestId=this.nextRequestId+1;let o=Date.now();this.debug("request to nvim:",r,e,t),this.encodeStream.write(Ao.encode([0,r,e,t],{codec:this.codec}));let s=Error().stack,a=setTimeout(()=>{this.debug(`request to vim blocked more than 1s: ${e}`,t,s)},1e3);this.pending.set(r,(l,u)=>{clearTimeout(a),this.debug("response of nvim:",r,`${Date.now()-o}ms`,u,l),i(l,u)})}notify(e,t){if(!!this.attached){if(this.pauseLevel!=0){let i=this.paused.get(this.pauseLevel);if(i){i.push([e,t]);return}}this.debug("nvim notification:",e,t),this.encodeStream.write(Ao.encode([2,e,t],{codec:this.codec}))}}send(e){this.encodeStream.write(Ao.encode(e,{codec:this.codec}))}createResponse(e){let{encodeStream:t}=this,i=Date.now(),r=!1,o=setTimeout(()=>{this.debug("request to client cost more than 1s",e)},1e3);return{send:(s,a)=>{clearTimeout(o),!(r||!this.attached)&&(this.debug("response of client:",e,`${Date.now()-i}ms`,s,a==!0),r=!0,t.write(Ao.encode([1,e,a?s:null,a?null:s])))}}}};Un.NvimTransport=PM});var FM=m(Ad=>{"use strict";var RM=Ad&&Ad.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Ad,"__esModule",{value:!0});var ihe=RM(require("events")),nhe=RM(require("readline")),rhe=Wu(),Zu=(0,rhe.createLogger)("connection"),LM=class extends ihe.default{constructor(e,t){super();this.readable=e,this.writeable=t;let i=nhe.default.createInterface(this.readable);i.on("line",r=>{this.parseData(r)}),i.on("close",()=>{Zu.error("connection closed"),process.exit(0)})}parseData(e){if(e.length==0)return;let t;try{t=JSON.parse(e)}catch{console.error(`Invalid data from vim: ${e}`);return}let[i,r]=t;i>0?(Zu.debug("received request:",i,r),this.emit("request",i,r)):i==0?(Zu.debug("received notification:",r),this.emit("notification",r)):(Zu.debug("received response:",i,r),this.emit("response",i,r))}response(e,t){this.send([e,t||null])}notify(e,t){this.send([0,[e,t||null]])}send(e){Zu.debug("send to vim:",e);try{this.writeable.write(JSON.stringify(e)+` -`)}catch{Zu.error("Send error:",e)}}redraw(e){this.send(["redraw",e?"force":""])}command(e){this.send(["ex",e])}expr(e){this.send(["expr",e])}call(e,t,i){if(!i){this.send(["call",e,t]);return}this.send(["call",e,t,i])}dispose(){this.removeAllListeners()}};Ad.default=LM});var jM=m(sS=>{"use strict";Object.defineProperty(sS,"__esModule",{value:!0});var ohe=Wu(),IPe=(0,ohe.createLogger)("request"),she=process.env.COC_NVIM=="1"?"coc#api#call":"nvim#api#call",IM=class{constructor(e,t,i){this.connection=e,this.cb=t,this.id=i}request(e,t=[]){this.method=e,this.connection.call(she,[e.slice(5),t],this.id)}callback(e,t,i){let{method:r,cb:o}=this;if(t)return o([0,t.toString()]);switch(r){case"nvim_list_wins":case"nvim_tabpage_list_wins":return o(null,i.map(s=>e.createWindow(s)));case"nvim_tabpage_get_win":case"nvim_get_current_win":case"nvim_open_win":return o(null,e.createWindow(i));case"nvim_list_bufs":return o(null,i.map(s=>e.createBuffer(s)));case"nvim_win_get_buf":case"nvim_create_buf":case"nvim_get_current_buf":return o(null,e.createBuffer(i));case"nvim_list_tabpages":return o(null,i.map(s=>e.createTabpage(s)));case"nvim_get_current_tabpage":return o(null,e.createTabpage(i));default:return o(null,i)}}};sS.default=IM});var OM=m(Ju=>{"use strict";var aS=Ju&&Ju.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Ju,"__esModule",{value:!0});Ju.VimTransport=void 0;var ahe=aS(oS()),lhe=aS(FM()),uhe=aS(jM()),AM=class extends ahe.default{constructor(e){super(e);this.pending=new Map,this.nextRequestId=-1,this.attached=!1,this.errText="",this.outText="",this.notifyMethod=process.env.COC_NVIM=="1"?"coc#api#notify":"nvim#api#notify"}attach(e,t,i){let r=this.connection=new lhe.default(t,e);this.attached=!0,this.client=i,r.on("request",(o,s)=>{let[a,l]=s;this.emit("request",a,l,this.createResponse(o))}),r.on("notification",o=>{let[s,a]=o;this.emit("notification",s.toString(),a)}),r.on("response",(o,s)=>{let a=this.pending.get(o);if(a){this.pending.delete(o);let l=null,u=null;Array.isArray(s)?(l=s[0],u=s[1]):l=s,a.callback(this.client,l,u)}})}send(e){this.connection.send(e)}detach(){!this.attached||(this.attached=!1,this.connection.dispose())}request(e,t,i){if(!this.attached)return i([0,"transport disconnected"]);let r=this.nextRequestId;this.nextRequestId=this.nextRequestId-1;let o=Date.now();this.debug("request to vim:",r,e,t);let s=setTimeout(()=>{this.debug("request to vim cost more than 1s",e,t)},1e3),a=new uhe.default(this.connection,(l,u)=>{clearTimeout(s),this.debug("response from vim cost:",r,`${Date.now()-o}ms`),i(l,u)},r);this.pending.set(r,a),a.request(e,t)}notify(e,t){if(!this.attached)return;if(this.pauseLevel!=0){let r=this.paused.get(this.pauseLevel);if(r){r.push([e,t]);return}}let i=e.slice(5);if(i=="err_write"){this.errText=this.errText+t[0].toString();return}if(i=="out_write"){let r=t[0].toString()||"";if(!r.includes(` -`))this.outText=this.outText+r;else{let o=this.outText+t[0].toString();this.outText="",this.connection.call(this.notifyMethod,[i,[o]])}return}if(i=="err_writeln"){let r=this.errText+t[0].toString();this.errText="",this.connection.call(this.notifyMethod,[i,[r]]);return}this.connection.call(this.notifyMethod,[i,t])}createResponse(e){let t=!1,{connection:i}=this,r=Date.now(),o=setTimeout(()=>{this.debug("request to client cost more than 1s",e)},1e3);return{send:(s,a)=>{if(clearTimeout(o),t||!this.attached)return;t=!0;let l=null;a&&(l=typeof s=="string"?s:s.toString()),this.debug("response of client cost:",e,`${Date.now()-r}ms`),i.response(e,[l,a?null:s])}}}};Ju.VimTransport=AM});var NM=m(Fm=>{"use strict";Object.defineProperty(Fm,"__esModule",{value:!0});Fm.Neovim=void 0;var che=Rd(),hhe=Ld(),dhe=Id(),ghe=Fd(),fhe=process.env.VIM_NODE_RPC=="1",MM=class extends che.BaseApi{constructor(){super(...arguments);this.prefix="nvim_",this.Buffer=hhe.Buffer,this.Window=ghe.Window,this.Tabpage=dhe.Tabpage}getArgs(e){return e?Array.isArray(e)?e:[e]:[]}get apiInfo(){return this.request(`${this.prefix}get_api_info`)}get buffers(){return this.request(`${this.prefix}list_bufs`)}get buffer(){return this.request(`${this.prefix}get_current_buf`)}async setBuffer(e){await this.request(`${this.prefix}set_current_buf`,[e])}get chans(){return this.request(`${this.prefix}list_chans`)}getChanInfo(e){return this.request(`${this.prefix}get_chan_info`,[e])}createNamespace(e=""){return process.env.COC_NVIM=="1"?(e=e.startsWith("coc-")?e.slice(4):e,this.request(`${this.prefix}call_function`,["coc#highlight#create_namespace",[e]])):this.request(`${this.prefix}create_namespace`,[e])}get namespaces(){return this.request(`${this.prefix}get_namespaces`,[])}get commands(){return this.getCommands()}getCommands(e={}){return this.request(`${this.prefix}get_commands`,[e])}get tabpages(){return this.request(`${this.prefix}list_tabpages`)}get tabpage(){return this.request(`${this.prefix}get_current_tabpage`)}async setTabpage(e){await this.request(`${this.prefix}set_current_tabpage`,[e])}get windows(){return this.getWindows()}get window(){return this.request(`${this.prefix}get_current_win`)}getWindows(){return this.request(`${this.prefix}list_wins`)}async setWindow(e){await this.request(`${this.prefix}set_current_win`,[e])}get runtimePaths(){return this.request(`${this.prefix}list_runtime_paths`)}setDirectory(e){return this.request(`${this.prefix}set_current_dir`,[e])}get line(){return this.getLine()}createNewBuffer(e=!1,t=!1){return this.request(`${this.prefix}create_buf`,[e,t])}openFloatWindow(e,t,i){return this.request(`${this.prefix}open_win`,[e,t,i])}getLine(){return this.request(`${this.prefix}get_current_line`)}setLine(e){return this.request(`${this.prefix}set_current_line`,[e])}getKeymap(e){return this.request(`${this.prefix}get_keymap`,[e])}get mode(){return this.request(`${this.prefix}get_mode`)}get colorMap(){return this.request(`${this.prefix}get_color_map`)}getColorByName(e){return this.request(`${this.prefix}get_color_by_name`,[e])}getHighlight(e,t=!0){let i=typeof e=="string"?"by_name":"by_id";return this.request(`${this.prefix}get_hl_${i}`,[e,t])}getHighlightByName(e,t=!0){return this.request(`${this.prefix}get_hl_by_name`,[e,t])}getHighlightById(e,t=!0){return this.request(`${this.prefix}get_hl_by_id`,[e,t])}deleteCurrentLine(){return this.request(`${this.prefix}del_current_line`)}eval(e){return this.request(`${this.prefix}eval`,[e])}lua(e,t=[]){return this.request(`${this.prefix}exec_lua`,[e,t])}executeLua(e,t=[]){let i=this.getArgs(t);return this.lua(e,i)}callDictFunction(e,t,i=[]){let r=this.getArgs(i);return this.request(`${this.prefix}call_dict_function`,[e,t,r])}call(e,t=[],i){let r=this.getArgs(t);return i?(this.notify(`${this.prefix}call_function`,[e,r]),null):this.request(`${this.prefix}call_function`,[e,r])}callTimer(e,t=[],i){let r=this.getArgs(t);return i?(this.notify(`${this.prefix}call_function`,["coc#util#timer",[e,r]]),null):fhe?(this.notify(`${this.prefix}call_function`,["coc#util#timer",[e,r]]),new Promise(o=>{setTimeout(()=>{o(null)},20)})):this.request(`${this.prefix}call_function`,["coc#util#timer",[e,r]])}callAsync(e,t=[]){let i=this.getArgs(t);return this.client.sendAsyncRequest(e,i)}callFunction(e,t=[]){return this.call(e,t)}callAtomic(e){return this.request(`${this.prefix}call_atomic`,[e])}command(e,t){return t?(this.notify(`${this.prefix}command`,[e]),null):this.request(`${this.prefix}command`,[e])}commandOutput(e){return this.request(`${this.prefix}command_output`,[e])}exec(e,t=!1){return this.request(`${this.prefix}exec`,[e,t])}getVvar(e){return this.request(`${this.prefix}get_vvar`,[e])}feedKeys(e,t,i){return this.request(`${this.prefix}feedkeys`,[e,t,i])}input(e){return this.request(`${this.prefix}input`,[e])}parseExpression(e,t,i){return this.request(`${this.prefix}parse_expression`,[e,t,i])}getProc(e){return this.request(`${this.prefix}get_proc`,[e])}getProcChildren(e){return this.request(`${this.prefix}get_proc_children`,[e])}replaceTermcodes(e,t,i,r){return this.request(`${this.prefix}replace_termcodes`,[e,t,i,r])}strWidth(e){return this.request(`${this.prefix}strwidth`,[e])}outWrite(e){this.notify(`${this.prefix}out_write`,[e])}outWriteLine(e){this.outWrite(`${e} -`)}errWrite(e){this.notify(`${this.prefix}err_write`,[e])}errWriteLine(e){this.notify(`${this.prefix}err_writeln`,[e])}get uis(){return this.request(`${this.prefix}list_uis`)}uiAttach(e,t,i){return this.request(`${this.prefix}ui_attach`,[e,t,i])}uiDetach(){return this.request(`${this.prefix}ui_detach`,[])}uiTryResize(e,t){return this.request(`${this.prefix}ui_try_resize`,[e,t])}uiSetOption(e,t){return this.request(`${this.prefix}ui_set_option`,[e,t])}subscribe(e){return this.request(`${this.prefix}subscribe`,[e])}unsubscribe(e){return this.request(`${this.prefix}unsubscribe`,[e])}setClientInfo(e,t,i,r,o){this.notify(`${this.prefix}set_client_info`,[e,t,i,r,o])}async quit(){this.command("qa!",!0),this.transport&&this.transport.detach()}};Fm.Neovim=MM});var jm=m($u=>{"use strict";Object.defineProperty($u,"__esModule",{value:!0});$u.NeovimClient=$u.AsyncResponse=void 0;var phe=_M(),mhe=OM(),bhe=NM(),yhe=Ld(),vhe=Fd(),whe=Id(),Dhe=Wu(),BM=(0,Dhe.createLogger)("client"),Im=process.env.VIM_NODE_RPC=="1",lS=class{constructor(e,t){this.requestId=e,this.cb=t,this.finished=!1}finish(e,t){if(!this.finished){if(this.finished=!0,e){this.cb(new Error(e));return}this.cb(null,t)}}};$u.AsyncResponse=lS;var HM=class extends bhe.Neovim{constructor(e){super({});this.logger=e,this.requestId=1,this.responses=new Map,this.attachedBuffers=new Map,this.isVim=Im,Object.defineProperty(this,"client",{value:this});let t=Im?new mhe.VimTransport(e):new phe.NvimTransport(e);this.setTransport(t),this.transportAttached=!1,this.handleRequest=this.handleRequest.bind(this),this.handleNotification=this.handleNotification.bind(this)}echoError(e){let t=process.env.COC_NVIM=="1"?"[coc.nvim] ":"";e instanceof Error?(this.errWriteLine(t+e.message+" use :CocOpenLog for details"),this.logError(e.message||"Unknown error",e.stack)):(this.errWriteLine(t+e),this.logError(e.toString(),Error().stack))}logError(e,...t){!this.logger||this.logger.error(e,...t)}createBuffer(e){return new yhe.Buffer({transport:this.transport,data:e,client:this})}createWindow(e){return new vhe.Window({transport:this.transport,data:e,client:this})}createTabpage(e){return new whe.Tabpage({transport:this.transport,data:e,client:this})}send(e){this.transport.send(e)}redrawVim(e){!Im||this.transport.notify("nvim_command",["redraw"+(e?"!":"")])}attach({reader:e,writer:t},i=!0){this.transport.attach(t,e,this),this.transportAttached=!0,this.setupTransport(i)}detach(){this.transport.detach(),this.transportAttached=!1}get isApiReady(){return this.transportAttached&&typeof this._channelId<"u"}get channelId(){return this._isReady.then(()=>this._channelId)}isAttached(e){return this.attachedBuffers.has(e)}handleRequest(e,t,i){this.emit("request",e,t,i)}sendAsyncRequest(e,t){let i=this.requestId;return this.requestId=i+1,this.notify("nvim_call_function",["coc#rpc#async_request",[i,e,t||[]]]),new Promise((r,o)=>{let s=new lS(i,(a,l)=>{if(a)return o(a);r(l)});this.responses.set(i,s)})}emitNotification(e,t){if(e.endsWith("_event")){if(e.startsWith("nvim_buf_")){let i=e.replace(/nvim_buf_(.*)_event/,"$1"),{id:r}=t[0];if(!this.attachedBuffers.has(r))return;(this.attachedBuffers.get(r).get(i)||[]).forEach(a=>a(...t)),i==="detach"&&this.attachedBuffers.delete(r);return}if(e.startsWith("nvim_async_request")){let[i,r,o]=t;this.handleRequest(r,o,{send:(s,a)=>{this.notify("nvim_call_function",["coc#rpc#async_response",[i,s,a]])}});return}if(e.startsWith("nvim_async_response")){let[i,r,o]=t,s=this.responses.get(i);if(!s){console.error(`Response not found for request ${i}`);return}this.responses.delete(i),s.finish(r,o);return}if(e==="nvim_error_event"){this.logger.error("Error event from nvim:",t[0],t[1]);return}this.logger.debug(`Unhandled event: ${e}`,t)}else this.emit("notification",e,t)}handleNotification(e,t){this.emitNotification(e,t)}setupTransport(e=!0){if(!this.transportAttached)throw new Error("Not attached to input/output");this.transport.on("request",this.handleRequest),this.transport.on("notification",this.handleNotification),this.transport.on("detach",()=>{this.emit("disconnect"),this.transport.removeAllListeners("request"),this.transport.removeAllListeners("notification"),this.transport.removeAllListeners("detach")}),e?this._isReady=this.generateApi():(this._channelId=0,this._isReady=Promise.resolve(!0))}requestApi(){return new Promise((e,t)=>{this.transport.request("nvim_get_api_info",[],(i,r)=>{i?t(new Error(Array.isArray(i)?i[1]:i.message||i.toString())):e(r)})})}async generateApi(){let e;try{e=await this.requestApi()}catch(t){console.error("Could not get vim api results"),BM.error(t)}if(e)try{let[t,i]=e;return this.functions=i.functions.map(r=>r.name),this._channelId=t,!0}catch(t){return BM.error(t.stack),null}return null}attachBufferEvent(e,t,i){let r=this.attachedBuffers.get(e.id)||new Map,o=r.get(t)||[];o.includes(i)||(o.push(i),r.set(t,o),this.attachedBuffers.set(e.id,r))}detachBufferEvent(e,t,i){let r=this.attachedBuffers.get(e.id);if(!r||!r.has(t))return;let o=r.get(t).filter(s=>s!==i);r.set(t,o)}pauseNotification(){let e=Error().stack;this.transport.pauseLevel!=0&&this.logError("Nested nvim.pauseNotification() detected, please avoid it:",e),this.transport.pauseNotification(),process.nextTick(()=>{this.transport.pauseLevel>0&&this.logError("resumeNotification not called within same tick:",e)})}resumeNotification(e,t){return Im&&e&&this.transport.notify("nvim_command",["redraw"]),t?(this.transport.resumeNotification(!0),Promise.resolve(null)):this.transport.resumeNotification()}hasFunction(e){return this.functions?this.functions.includes(e):!0}};$u.NeovimClient=HM});var qM=m(Am=>{"use strict";Object.defineProperty(Am,"__esModule",{value:!0});Am.attach=void 0;var xhe=require("net"),Che=jm(),She=Wu();function The({reader:n,writer:e,proc:t,socket:i},r=null,o=!0){let s,a,l;if(r||(r=She.nullLogger),i){let u=(0,xhe.createConnection)(i);s=u,a=u,u.once("close",()=>{l.detach()})}else n&&e?(s=e,a=n):t&&(s=t.stdin,a=t.stdout,t.once("disconnect",()=>{l.detach()}));if(s.on("error",u=>{u.code=="EPIPE"&&l.detach()}),s&&a)return l=new Che.NeovimClient(r),l.attach({writer:s,reader:a},o),l;throw new Error("Invalid arguments, could not attach")}Am.attach=The});var YM=m(Gn=>{"use strict";Object.defineProperty(Gn,"__esModule",{value:!0});Gn.Tabpage=Gn.Window=Gn.Buffer=Gn.NeovimClient=Gn.Neovim=void 0;var khe=jm();Object.defineProperty(Gn,"Neovim",{enumerable:!0,get:function(){return khe.NeovimClient}});var Ehe=jm();Object.defineProperty(Gn,"NeovimClient",{enumerable:!0,get:function(){return Ehe.NeovimClient}});var Phe=Ld();Object.defineProperty(Gn,"Buffer",{enumerable:!0,get:function(){return Phe.Buffer}});var _he=Fd();Object.defineProperty(Gn,"Window",{enumerable:!0,get:function(){return _he.Window}});var Rhe=Id();Object.defineProperty(Gn,"Tabpage",{enumerable:!0,get:function(){return Rhe.Tabpage}})});var WM=m(an=>{"use strict";Object.defineProperty(an,"__esModule",{value:!0});an.Window=an.Tabpage=an.Buffer=an.NeovimClient=an.Neovim=an.attach=void 0;var Lhe=qM();Object.defineProperty(an,"attach",{enumerable:!0,get:function(){return Lhe.attach}});var Od=YM();Object.defineProperty(an,"Neovim",{enumerable:!0,get:function(){return Od.Neovim}});Object.defineProperty(an,"NeovimClient",{enumerable:!0,get:function(){return Od.NeovimClient}});Object.defineProperty(an,"Buffer",{enumerable:!0,get:function(){return Od.Buffer}});Object.defineProperty(an,"Tabpage",{enumerable:!0,get:function(){return Od.Tabpage}});Object.defineProperty(an,"Window",{enumerable:!0,get:function(){return Od.Window}})});var Oo=m(hS=>{"use strict";Object.defineProperty(hS,"__esModule",{value:!0});var uS;function cS(){if(uS===void 0)throw new Error("No runtime abstraction layer installed");return uS}(function(n){function e(t){if(t===void 0)throw new Error("No runtime abstraction layer provided");uS=t}n.install=e})(cS||(cS={}));hS.default=cS});var dS=m(Md=>{"use strict";Object.defineProperty(Md,"__esModule",{value:!0});Md.Disposable=void 0;var Fhe;(function(n){function e(t){return{dispose:t}}n.create=e})(Fhe=Md.Disposable||(Md.Disposable={}))});var JM=m(Om=>{"use strict";Object.defineProperty(Om,"__esModule",{value:!0});Om.AbstractMessageBuffer=void 0;var Ihe=13,jhe=10,Ahe=`\r -`,ZM=class{constructor(e="utf-8"){this._encoding=e,this._chunks=[],this._totalLength=0}get encoding(){return this._encoding}append(e){let t=typeof e=="string"?this.fromString(e,this._encoding):e;this._chunks.push(t),this._totalLength+=t.byteLength}tryReadHeaders(){if(this._chunks.length===0)return;let e=0,t=0,i=0,r=0;e:for(;tthis._totalLength)throw new Error("Cannot read so many bytes!");if(this._chunks[0].byteLength===e){let o=this._chunks[0];return this._chunks.shift(),this._totalLength-=e,this.asNative(o)}if(this._chunks[0].byteLength>e){let o=this._chunks[0],s=this.asNative(o,e);return this._chunks[0]=o.slice(e),this._totalLength-=e,s}let t=this.allocNative(e),i=0,r=0;for(;e>0;){let o=this._chunks[r];if(o.byteLength>e){let s=o.slice(0,e);t.set(s,i),i+=e,this._chunks[r]=o.slice(e),this._totalLength-=e,e-=e}else t.set(o,i),i+=o.byteLength,this._chunks.shift(),this._totalLength-=o.byteLength,e-=o.byteLength}return t}};Om.AbstractMessageBuffer=ZM});var QM=m(fS=>{"use strict";Object.defineProperty(fS,"__esModule",{value:!0});var Ohe=Oo(),$M=require("util"),ll=dS(),Mhe=JM(),Nd=class extends Mhe.AbstractMessageBuffer{constructor(e="utf-8"){super(e)}emptyBuffer(){return Nd.emptyBuffer}fromString(e,t){return Buffer.from(e,t)}toString(e,t){return e instanceof Buffer?e.toString(t):new $M.TextDecoder(t).decode(e)}asNative(e,t){return t===void 0?e instanceof Buffer?e:Buffer.from(e):e instanceof Buffer?e.slice(0,t):Buffer.from(e,0,t)}allocNative(e){return Buffer.allocUnsafe(e)}};Nd.emptyBuffer=Buffer.allocUnsafe(0);var XM=class{constructor(e){this.stream=e}onClose(e){return this.stream.on("close",e),ll.Disposable.create(()=>this.stream.off("close",e))}onError(e){return this.stream.on("error",e),ll.Disposable.create(()=>this.stream.off("error",e))}onEnd(e){return this.stream.on("end",e),ll.Disposable.create(()=>this.stream.off("end",e))}onData(e){return this.stream.on("data",e),ll.Disposable.create(()=>this.stream.off("data",e))}},UM=class{constructor(e){this.stream=e}onClose(e){return this.stream.on("close",e),ll.Disposable.create(()=>this.stream.off("close",e))}onError(e){return this.stream.on("error",e),ll.Disposable.create(()=>this.stream.off("error",e))}onEnd(e){return this.stream.on("end",e),ll.Disposable.create(()=>this.stream.off("end",e))}write(e,t){return new Promise((i,r)=>{let o=s=>{s==null?i():r(s)};typeof e=="string"?this.stream.write(e,t,o):this.stream.write(e,o)})}end(){this.stream.end()}},GM=Object.freeze({messageBuffer:Object.freeze({create:n=>new Nd(n)}),applicationJson:Object.freeze({encoder:Object.freeze({name:"application/json",encode:(n,e)=>{try{return Promise.resolve(Buffer.from(JSON.stringify(n,void 0,0),e.charset))}catch(t){return Promise.reject(t)}}}),decoder:Object.freeze({name:"application/json",decode:(n,e)=>{try{return n instanceof Buffer?Promise.resolve(JSON.parse(n.toString(e.charset))):Promise.resolve(JSON.parse(new $M.TextDecoder(e.charset).decode(n)))}catch(t){return Promise.reject(t)}}})}),stream:Object.freeze({asReadableStream:n=>new XM(n),asWritableStream:n=>new UM(n)}),console,timer:Object.freeze({setTimeout(n,e,...t){return setTimeout(n,e,...t)},clearTimeout(n){clearTimeout(n)},setImmediate(n,...e){return setImmediate(n,...e)},clearImmediate(n){clearImmediate(n)}})});function gS(){return GM}(function(n){function e(){Ohe.default.install(GM)}n.install=e})(gS||(gS={}));fS.default=gS});var Xu=m(ki=>{"use strict";Object.defineProperty(ki,"__esModule",{value:!0});ki.stringArray=ki.array=ki.func=ki.error=ki.number=ki.string=ki.boolean=void 0;function Nhe(n){return n===!0||n===!1}ki.boolean=Nhe;function KM(n){return typeof n=="string"||n instanceof String}ki.string=KM;function Bhe(n){return typeof n=="number"||n instanceof Number}ki.number=Bhe;function Hhe(n){return n instanceof Error}ki.error=Hhe;function qhe(n){return typeof n=="function"}ki.func=qhe;function zM(n){return Array.isArray(n)}ki.array=zM;function Yhe(n){return zM(n)&&n.every(e=>KM(e))}ki.stringArray=Yhe});var pS=m(ne=>{"use strict";Object.defineProperty(ne,"__esModule",{value:!0});ne.isResponseMessage=ne.isNotificationMessage=ne.isRequestMessage=ne.NotificationType9=ne.NotificationType8=ne.NotificationType7=ne.NotificationType6=ne.NotificationType5=ne.NotificationType4=ne.NotificationType3=ne.NotificationType2=ne.NotificationType1=ne.NotificationType0=ne.NotificationType=ne.RequestType9=ne.RequestType8=ne.RequestType7=ne.RequestType6=ne.RequestType5=ne.RequestType4=ne.RequestType3=ne.RequestType2=ne.RequestType1=ne.RequestType=ne.RequestType0=ne.AbstractMessageSignature=ne.ParameterStructures=ne.ResponseError=ne.ErrorCodes=void 0;var ul=Xu(),VM;(function(n){n.ParseError=-32700,n.InvalidRequest=-32600,n.MethodNotFound=-32601,n.InvalidParams=-32602,n.InternalError=-32603,n.jsonrpcReservedErrorRangeStart=-32099,n.serverErrorStart=n.jsonrpcReservedErrorRangeStart,n.MessageWriteError=-32099,n.MessageReadError=-32098,n.ServerNotInitialized=-32002,n.UnknownErrorCode=-32001,n.jsonrpcReservedErrorRangeEnd=-32e3,n.serverErrorEnd=n.jsonrpcReservedErrorRangeEnd})(VM=ne.ErrorCodes||(ne.ErrorCodes={}));var Mm=class extends Error{constructor(e,t,i){super(t);this.code=ul.number(e)?e:VM.UnknownErrorCode,this.data=i,Object.setPrototypeOf(this,Mm.prototype)}toJson(){return{code:this.code,message:this.message,data:this.data}}};ne.ResponseError=Mm;var mi=class{constructor(e){this.kind=e}static is(e){return e===mi.auto||e===mi.byName||e===mi.byPosition}toString(){return this.kind}};ne.ParameterStructures=mi;mi.auto=new mi("auto");mi.byPosition=new mi("byPosition");mi.byName=new mi("byName");var xt=class{constructor(e,t){this.method=e,this.numberOfParams=t}get parameterStructures(){return mi.auto}};ne.AbstractMessageSignature=xt;var eN=class extends xt{constructor(e){super(e,0)}};ne.RequestType0=eN;var tN=class extends xt{constructor(e,t=mi.auto){super(e,1);this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}};ne.RequestType=tN;var iN=class extends xt{constructor(e,t=mi.auto){super(e,1);this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}};ne.RequestType1=iN;var nN=class extends xt{constructor(e){super(e,2)}};ne.RequestType2=nN;var rN=class extends xt{constructor(e){super(e,3)}};ne.RequestType3=rN;var oN=class extends xt{constructor(e){super(e,4)}};ne.RequestType4=oN;var sN=class extends xt{constructor(e){super(e,5)}};ne.RequestType5=sN;var aN=class extends xt{constructor(e){super(e,6)}};ne.RequestType6=aN;var lN=class extends xt{constructor(e){super(e,7)}};ne.RequestType7=lN;var uN=class extends xt{constructor(e){super(e,8)}};ne.RequestType8=uN;var cN=class extends xt{constructor(e){super(e,9)}};ne.RequestType9=cN;var hN=class extends xt{constructor(e,t=mi.auto){super(e,1);this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}};ne.NotificationType=hN;var dN=class extends xt{constructor(e){super(e,0)}};ne.NotificationType0=dN;var gN=class extends xt{constructor(e,t=mi.auto){super(e,1);this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}};ne.NotificationType1=gN;var fN=class extends xt{constructor(e){super(e,2)}};ne.NotificationType2=fN;var pN=class extends xt{constructor(e){super(e,3)}};ne.NotificationType3=pN;var mN=class extends xt{constructor(e){super(e,4)}};ne.NotificationType4=mN;var bN=class extends xt{constructor(e){super(e,5)}};ne.NotificationType5=bN;var yN=class extends xt{constructor(e){super(e,6)}};ne.NotificationType6=yN;var vN=class extends xt{constructor(e){super(e,7)}};ne.NotificationType7=vN;var wN=class extends xt{constructor(e){super(e,8)}};ne.NotificationType8=wN;var DN=class extends xt{constructor(e){super(e,9)}};ne.NotificationType9=DN;function Whe(n){let e=n;return e&&ul.string(e.method)&&(ul.string(e.id)||ul.number(e.id))}ne.isRequestMessage=Whe;function Zhe(n){let e=n;return e&&ul.string(e.method)&&n.id===void 0}ne.isNotificationMessage=Zhe;function Jhe(n){let e=n;return e&&(e.result!==void 0||!!e.error)&&(ul.string(e.id)||ul.number(e.id)||e.id===null)}ne.isResponseMessage=Jhe});var Uu=m(cl=>{"use strict";Object.defineProperty(cl,"__esModule",{value:!0});cl.Emitter=cl.Event=void 0;var $he=Oo(),Xhe;(function(n){let e={dispose(){}};n.None=function(){return e}})(Xhe=cl.Event||(cl.Event={}));var xN=class{add(e,t=null,i){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(e),this._contexts.push(t),Array.isArray(i)&&i.push({dispose:()=>this.remove(e,t)})}remove(e,t=null){if(!this._callbacks)return;let i=!1;for(let r=0,o=this._callbacks.length;r{this._callbacks||(this._callbacks=new xN),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(e,t);let r={dispose:()=>{!this._callbacks||(this._callbacks.remove(e,t),r.dispose=Bd._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))}};return Array.isArray(i)&&i.push(r),r}),this._event}fire(e){this._callbacks&&this._callbacks.invoke.call(this._callbacks,e)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}};cl.Emitter=Bd;Bd._noop=function(){}});var vS=m(hl=>{"use strict";Object.defineProperty(hl,"__esModule",{value:!0});hl.CancellationTokenSource=hl.CancellationToken=void 0;var CN=Oo(),Uhe=Xu(),mS=Uu(),bS;(function(n){n.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:mS.Event.None}),n.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:mS.Event.None});function e(t){let i=t;return i&&(i===n.None||i===n.Cancelled||Uhe.boolean(i.isCancellationRequested)&&!!i.onCancellationRequested)}n.is=e})(bS=hl.CancellationToken||(hl.CancellationToken={}));var Ghe=Object.freeze(function(n,e){let t=CN.default().timer.setTimeout(n.bind(e),0);return{dispose(){CN.default().timer.clearTimeout(t)}}}),yS=class{constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?Ghe:(this._emitter||(this._emitter=new mS.Emitter),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)}},SN=class{get token(){return this._token||(this._token=new yS),this._token}cancel(){this._token?this._token.cancel():this._token=bS.Cancelled}dispose(){this._token?this._token instanceof yS&&this._token.dispose():this._token=bS.None}};hl.CancellationTokenSource=SN});var kN=m(Mo=>{"use strict";Object.defineProperty(Mo,"__esModule",{value:!0});Mo.ReadableStreamMessageReader=Mo.AbstractMessageReader=Mo.MessageReader=void 0;var Nm=Oo(),Gu=Xu(),wS=Uu(),Qhe;(function(n){function e(t){let i=t;return i&&Gu.func(i.listen)&&Gu.func(i.dispose)&&Gu.func(i.onError)&&Gu.func(i.onClose)&&Gu.func(i.onPartialMessage)}n.is=e})(Qhe=Mo.MessageReader||(Mo.MessageReader={}));var xS=class{constructor(){this.errorEmitter=new wS.Emitter,this.closeEmitter=new wS.Emitter,this.partialMessageEmitter=new wS.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(e){this.errorEmitter.fire(this.asError(e))}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}get onPartialMessage(){return this.partialMessageEmitter.event}firePartialMessage(e){this.partialMessageEmitter.fire(e)}asError(e){return e instanceof Error?e:new Error(`Reader received error. Reason: ${Gu.string(e.message)?e.message:"unknown"}`)}};Mo.AbstractMessageReader=xS;var DS;(function(n){function e(t){var i;let r,o,s,a=new Map,l,u=new Map;if(t===void 0||typeof t=="string")r=t!=null?t:"utf-8";else{if(r=(i=t.charset)!==null&&i!==void 0?i:"utf-8",t.contentDecoder!==void 0&&(s=t.contentDecoder,a.set(s.name,s)),t.contentDecoders!==void 0)for(let c of t.contentDecoders)a.set(c.name,c);if(t.contentTypeDecoder!==void 0&&(l=t.contentTypeDecoder,u.set(l.name,l)),t.contentTypeDecoders!==void 0)for(let c of t.contentTypeDecoders)u.set(c.name,c)}return l===void 0&&(l=Nm.default().applicationJson.decoder,u.set(l.name,l)),{charset:r,contentDecoder:s,contentDecoders:a,contentTypeDecoder:l,contentTypeDecoders:u}}n.fromOptions=e})(DS||(DS={}));var TN=class extends xS{constructor(e,t){super();this.readable=e,this.options=DS.fromOptions(t),this.buffer=Nm.default().messageBuffer.create(this.options.charset),this._partialMessageTimeout=1e4,this.nextMessageLength=-1,this.messageToken=0}set partialMessageTimeout(e){this._partialMessageTimeout=e}get partialMessageTimeout(){return this._partialMessageTimeout}listen(e){this.nextMessageLength=-1,this.messageToken=0,this.partialMessageTimer=void 0,this.callback=e;let t=this.readable.onData(i=>{this.onData(i)});return this.readable.onError(i=>this.fireError(i)),this.readable.onClose(()=>this.fireClose()),t}onData(e){for(this.buffer.append(e);;){if(this.nextMessageLength===-1){let r=this.buffer.tryReadHeaders();if(!r)return;let o=r.get("Content-Length");if(!o)throw new Error("Header must provide a Content-Length property.");let s=parseInt(o);if(isNaN(s))throw new Error("Content-Length value must be a number.");this.nextMessageLength=s}let t=this.buffer.tryReadBody(this.nextMessageLength);if(t===void 0){this.setPartialMessageTimer();return}this.clearPartialMessageTimer(),this.nextMessageLength=-1;let i;this.options.contentDecoder!==void 0?i=this.options.contentDecoder.decode(t):i=Promise.resolve(t),i.then(r=>{this.options.contentTypeDecoder.decode(r,this.options).then(o=>{this.callback(o)},o=>{this.fireError(o)})},r=>{this.fireError(r)})}}clearPartialMessageTimer(){this.partialMessageTimer&&(Nm.default().timer.clearTimeout(this.partialMessageTimer),this.partialMessageTimer=void 0)}setPartialMessageTimer(){this.clearPartialMessageTimer(),!(this._partialMessageTimeout<=0)&&(this.partialMessageTimer=Nm.default().timer.setTimeout((e,t)=>{this.partialMessageTimer=void 0,e===this.messageToken&&(this.firePartialMessage({messageToken:e,waitingTime:t}),this.setPartialMessageTimer())},this._partialMessageTimeout,this.messageToken,this._partialMessageTimeout))}};Mo.ReadableStreamMessageReader=TN});var PN=m(Bm=>{"use strict";Object.defineProperty(Bm,"__esModule",{value:!0});Bm.Semaphore=void 0;var Khe=Oo(),EN=class{constructor(e=1){if(e<=0)throw new Error("Capacity must be greater than 0");this._capacity=e,this._active=0,this._waiting=[]}lock(e){return new Promise((t,i)=>{this._waiting.push({thunk:e,resolve:t,reject:i}),this.runNext()})}get active(){return this._active}runNext(){this._waiting.length===0||this._active===this._capacity||Khe.default().timer.setImmediate(()=>this.doRunNext())}doRunNext(){if(this._waiting.length===0||this._active===this._capacity)return;let e=this._waiting.shift();if(this._active++,this._active>this._capacity)throw new Error("To many thunks active");try{let t=e.thunk();t instanceof Promise?t.then(i=>{this._active--,e.resolve(i),this.runNext()},i=>{this._active--,e.reject(i),this.runNext()}):(this._active--,e.resolve(t),this.runNext())}catch(t){this._active--,e.reject(t),this.runNext()}}};Bm.Semaphore=EN});var IN=m(No=>{"use strict";Object.defineProperty(No,"__esModule",{value:!0});No.WriteableStreamMessageWriter=No.AbstractMessageWriter=No.MessageWriter=void 0;var _N=Oo(),Hd=Xu(),zhe=PN(),RN=Uu(),Vhe="Content-Length: ",LN=`\r -`,ede;(function(n){function e(t){let i=t;return i&&Hd.func(i.dispose)&&Hd.func(i.onClose)&&Hd.func(i.onError)&&Hd.func(i.write)}n.is=e})(ede=No.MessageWriter||(No.MessageWriter={}));var SS=class{constructor(){this.errorEmitter=new RN.Emitter,this.closeEmitter=new RN.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(e,t,i){this.errorEmitter.fire([this.asError(e),t,i])}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}asError(e){return e instanceof Error?e:new Error(`Writer received error. Reason: ${Hd.string(e.message)?e.message:"unknown"}`)}};No.AbstractMessageWriter=SS;var CS;(function(n){function e(t){var i,r;return t===void 0||typeof t=="string"?{charset:t!=null?t:"utf-8",contentTypeEncoder:_N.default().applicationJson.encoder}:{charset:(i=t.charset)!==null&&i!==void 0?i:"utf-8",contentEncoder:t.contentEncoder,contentTypeEncoder:(r=t.contentTypeEncoder)!==null&&r!==void 0?r:_N.default().applicationJson.encoder}}n.fromOptions=e})(CS||(CS={}));var FN=class extends SS{constructor(e,t){super();this.writable=e,this.options=CS.fromOptions(t),this.errorCount=0,this.writeSemaphore=new zhe.Semaphore(1),this.writable.onError(i=>this.fireError(i)),this.writable.onClose(()=>this.fireClose())}async write(e){return this.writeSemaphore.lock(async()=>this.options.contentTypeEncoder.encode(e,this.options).then(i=>this.options.contentEncoder!==void 0?this.options.contentEncoder.encode(i):i).then(i=>{let r=[];return r.push(Vhe,i.byteLength.toString(),LN),r.push(LN),this.doWrite(e,r,i)},i=>{throw this.fireError(i),i}))}async doWrite(e,t,i){try{return await this.writable.write(t.join(""),"ascii"),this.writable.write(i)}catch(r){return this.handleError(r,e),Promise.reject(r)}}handleError(e,t){this.errorCount++,this.fireError(e,t,this.errorCount)}end(){this.writable.end()}};No.WriteableStreamMessageWriter=FN});var AN=m(Bo=>{"use strict";Object.defineProperty(Bo,"__esModule",{value:!0});Bo.LRUCache=Bo.LinkedMap=Bo.Touch=void 0;var Ji;(function(n){n.None=0,n.First=1,n.AsOld=n.First,n.Last=2,n.AsNew=n.Last})(Ji=Bo.Touch||(Bo.Touch={}));var TS=class{constructor(){this[Symbol.toStringTag]="LinkedMap",this._map=new Map,this._head=void 0,this._tail=void 0,this._size=0,this._state=0}clear(){this._map.clear(),this._head=void 0,this._tail=void 0,this._size=0,this._state++}isEmpty(){return!this._head&&!this._tail}get size(){return this._size}get first(){var e;return(e=this._head)===null||e===void 0?void 0:e.value}get last(){var e;return(e=this._tail)===null||e===void 0?void 0:e.value}has(e){return this._map.has(e)}get(e,t=Ji.None){let i=this._map.get(e);if(!!i)return t!==Ji.None&&this.touch(i,t),i.value}set(e,t,i=Ji.None){let r=this._map.get(e);if(r)r.value=t,i!==Ji.None&&this.touch(r,i);else{switch(r={key:e,value:t,next:void 0,previous:void 0},i){case Ji.None:this.addItemLast(r);break;case Ji.First:this.addItemFirst(r);break;case Ji.Last:this.addItemLast(r);break;default:this.addItemLast(r);break}this._map.set(e,r),this._size++}return this}delete(e){return!!this.remove(e)}remove(e){let t=this._map.get(e);if(!!t)return this._map.delete(e),this.removeItem(t),this._size--,t.value}shift(){if(!this._head&&!this._tail)return;if(!this._head||!this._tail)throw new Error("Invalid list");let e=this._head;return this._map.delete(e.key),this.removeItem(e),this._size--,e.value}forEach(e,t){let i=this._state,r=this._head;for(;r;){if(t?e.bind(t)(r.value,r.key,this):e(r.value,r.key,this),this._state!==i)throw new Error("LinkedMap got modified during iteration.");r=r.next}}keys(){let e=this,t=this._state,i=this._head,r={[Symbol.iterator](){return r},next(){if(e._state!==t)throw new Error("LinkedMap got modified during iteration.");if(i){let o={value:i.key,done:!1};return i=i.next,o}else return{value:void 0,done:!0}}};return r}values(){let e=this,t=this._state,i=this._head,r={[Symbol.iterator](){return r},next(){if(e._state!==t)throw new Error("LinkedMap got modified during iteration.");if(i){let o={value:i.value,done:!1};return i=i.next,o}else return{value:void 0,done:!0}}};return r}entries(){let e=this,t=this._state,i=this._head,r={[Symbol.iterator](){return r},next(){if(e._state!==t)throw new Error("LinkedMap got modified during iteration.");if(i){let o={value:[i.key,i.value],done:!1};return i=i.next,o}else return{value:void 0,done:!0}}};return r}[Symbol.iterator](){return this.entries()}trimOld(e){if(e>=this.size)return;if(e===0){this.clear();return}let t=this._head,i=this.size;for(;t&&i>e;)this._map.delete(t.key),t=t.next,i--;this._head=t,this._size=i,t&&(t.previous=void 0),this._state++}addItemFirst(e){if(!this._head&&!this._tail)this._tail=e;else if(this._head)e.next=this._head,this._head.previous=e;else throw new Error("Invalid list");this._head=e,this._state++}addItemLast(e){if(!this._head&&!this._tail)this._head=e;else if(this._tail)e.previous=this._tail,this._tail.next=e;else throw new Error("Invalid list");this._tail=e,this._state++}removeItem(e){if(e===this._head&&e===this._tail)this._head=void 0,this._tail=void 0;else if(e===this._head){if(!e.next)throw new Error("Invalid list");e.next.previous=void 0,this._head=e.next}else if(e===this._tail){if(!e.previous)throw new Error("Invalid list");e.previous.next=void 0,this._tail=e.previous}else{let t=e.next,i=e.previous;if(!t||!i)throw new Error("Invalid list");t.previous=i,i.next=t}e.next=void 0,e.previous=void 0,this._state++}touch(e,t){if(!this._head||!this._tail)throw new Error("Invalid list");if(!(t!==Ji.First&&t!==Ji.Last)){if(t===Ji.First){if(e===this._head)return;let i=e.next,r=e.previous;e===this._tail?(r.next=void 0,this._tail=r):(i.previous=r,r.next=i),e.previous=void 0,e.next=this._head,this._head.previous=e,this._head=e,this._state++}else if(t===Ji.Last){if(e===this._tail)return;let i=e.next,r=e.previous;e===this._head?(i.previous=void 0,this._head=i):(i.previous=r,r.next=i),e.next=void 0,e.previous=this._tail,this._tail.next=e,this._tail=e,this._state++}}}toJSON(){let e=[];return this.forEach((t,i)=>{e.push([i,t])}),e}fromJSON(e){this.clear();for(let[t,i]of e)this.set(t,i)}};Bo.LinkedMap=TS;var jN=class extends TS{constructor(e,t=1){super();this._limit=e,this._ratio=Math.min(Math.max(0,t),1)}get limit(){return this._limit}set limit(e){this._limit=e,this.checkTrim()}get ratio(){return this._ratio}set ratio(e){this._ratio=Math.min(Math.max(0,e),1),this.checkTrim()}get(e,t=Ji.AsNew){return super.get(e,t)}peek(e){return super.get(e,Ji.None)}set(e,t){return super.set(e,t,Ji.Last),this.checkTrim(),this}checkTrim(){this.size>this._limit&&this.trimOld(Math.round(this._limit*this._ratio))}};Bo.LRUCache=jN});var qN=m(be=>{"use strict";Object.defineProperty(be,"__esModule",{value:!0});be.createMessageConnection=be.ConnectionOptions=be.CancellationStrategy=be.CancellationSenderStrategy=be.CancellationReceiverStrategy=be.ConnectionStrategy=be.ConnectionError=be.ConnectionErrors=be.LogTraceNotification=be.SetTraceNotification=be.TraceFormat=be.Trace=be.NullLogger=be.ProgressType=void 0;var ON=Oo(),ai=Xu(),me=pS(),MN=AN(),qd=Uu(),kS=vS(),Yd;(function(n){n.type=new me.NotificationType("$/cancelRequest")})(Yd||(Yd={}));var qm;(function(n){n.type=new me.NotificationType("$/progress")})(qm||(qm={}));var NN=class{constructor(){}};be.ProgressType=NN;var ES;(function(n){function e(t){return ai.func(t)}n.is=e})(ES||(ES={}));be.NullLogger=Object.freeze({error:()=>{},warn:()=>{},info:()=>{},log:()=>{}});var Wt;(function(n){n[n.Off=0]="Off",n[n.Messages=1]="Messages",n[n.Verbose=2]="Verbose"})(Wt=be.Trace||(be.Trace={}));(function(n){function e(i){if(!ai.string(i))return n.Off;switch(i=i.toLowerCase(),i){case"off":return n.Off;case"messages":return n.Messages;case"verbose":return n.Verbose;default:return n.Off}}n.fromString=e;function t(i){switch(i){case n.Off:return"off";case n.Messages:return"messages";case n.Verbose:return"verbose";default:return"off"}}n.toString=t})(Wt=be.Trace||(be.Trace={}));var Dr;(function(n){n.Text="text",n.JSON="json"})(Dr=be.TraceFormat||(be.TraceFormat={}));(function(n){function e(t){return t=t.toLowerCase(),t==="json"?n.JSON:n.Text}n.fromString=e})(Dr=be.TraceFormat||(be.TraceFormat={}));var BN;(function(n){n.type=new me.NotificationType("$/setTrace")})(BN=be.SetTraceNotification||(be.SetTraceNotification={}));var PS;(function(n){n.type=new me.NotificationType("$/logTrace")})(PS=be.LogTraceNotification||(be.LogTraceNotification={}));var Hm;(function(n){n[n.Closed=1]="Closed",n[n.Disposed=2]="Disposed",n[n.AlreadyListening=3]="AlreadyListening"})(Hm=be.ConnectionErrors||(be.ConnectionErrors={}));var dl=class extends Error{constructor(e,t){super(t);this.code=e,Object.setPrototypeOf(this,dl.prototype)}};be.ConnectionError=dl;var HN;(function(n){function e(t){let i=t;return i&&ai.func(i.cancelUndispatched)}n.is=e})(HN=be.ConnectionStrategy||(be.ConnectionStrategy={}));var _S;(function(n){n.Message=Object.freeze({createCancellationTokenSource(t){return new kS.CancellationTokenSource}});function e(t){let i=t;return i&&ai.func(i.createCancellationTokenSource)}n.is=e})(_S=be.CancellationReceiverStrategy||(be.CancellationReceiverStrategy={}));var RS;(function(n){n.Message=Object.freeze({sendCancellation(t,i){t.sendNotification(Yd.type,{id:i})},cleanup(t){}});function e(t){let i=t;return i&&ai.func(i.sendCancellation)&&ai.func(i.cleanup)}n.is=e})(RS=be.CancellationSenderStrategy||(be.CancellationSenderStrategy={}));var LS;(function(n){n.Message=Object.freeze({receiver:_S.Message,sender:RS.Message});function e(t){let i=t;return i&&_S.is(i.receiver)&&RS.is(i.sender)}n.is=e})(LS=be.CancellationStrategy||(be.CancellationStrategy={}));var tde;(function(n){function e(t){let i=t;return i&&(LS.is(i.cancellationStrategy)||HN.is(i.connectionStrategy))}n.is=e})(tde=be.ConnectionOptions||(be.ConnectionOptions={}));var xr;(function(n){n[n.New=1]="New",n[n.Listening=2]="Listening",n[n.Closed=3]="Closed",n[n.Disposed=4]="Disposed"})(xr||(xr={}));function ide(n,e,t,i){let r=t!==void 0?t:be.NullLogger,o=0,s=0,a=0,l="2.0",u,c=Object.create(null),h,d=Object.create(null),g=new Map,f,p=new MN.LinkedMap,b=Object.create(null),v=Object.create(null),w=Wt.Off,D=Dr.Text,S,F=xr.New,L=new qd.Emitter,j=new qd.Emitter,W=new qd.Emitter,B=new qd.Emitter,N=new qd.Emitter,I=i&&i.cancellationStrategy?i.cancellationStrategy:LS.Message;function M(P){if(P===null)throw new Error("Can't send requests with id null since the response can't be correlated.");return"req-"+P.toString()}function J(P){return P===null?"res-unknown-"+(++a).toString():"res-"+P.toString()}function K(){return"not-"+(++s).toString()}function ae(P,$){me.isRequestMessage($)?P.set(M($.id),$):me.isResponseMessage($)?P.set(J($.id),$):P.set(K(),$)}function je(P){}function _e(){return F===xr.Listening}function Ve(){return F===xr.Closed}function Et(){return F===xr.Disposed}function xi(){(F===xr.New||F===xr.Listening)&&(F=xr.Closed,j.fire(void 0))}function ys(P){L.fire([P,void 0,void 0])}function Po(P){L.fire(P)}n.onClose(xi),n.onError(ys),e.onClose(xi),e.onError(Po);function mp(){f||p.size===0||(f=ON.default().timer.setImmediate(()=>{f=void 0,bp()}))}function bp(){if(p.size===0)return;let P=p.shift();try{me.isRequestMessage(P)?du(P):me.isNotificationMessage(P)?Re(P):me.isResponseMessage(P)?gu(P):Se(P)}finally{mp()}}let Tx=P=>{try{if(me.isNotificationMessage(P)&&P.method===Yd.type.method){let $=M(P.params.id),G=p.get($);if(me.isRequestMessage(G)){let ce=i==null?void 0:i.connectionStrategy,Ye=ce&&ce.cancelUndispatched?ce.cancelUndispatched(G,je):void 0;if(Ye&&(Ye.error!==void 0||Ye.result!==void 0)){p.delete($),Ye.id=G.id,It(Ye,P.method,Date.now()),e.write(Ye);return}}}ae(p,P)}finally{mp()}};function du(P){if(Et())return;function $($e,At,Xe){let Kt={jsonrpc:l,id:P.id};$e instanceof me.ResponseError?Kt.error=$e.toJson():Kt.result=$e===void 0?null:$e,It(Kt,At,Xe),e.write(Kt)}function G($e,At,Xe){let Kt={jsonrpc:l,id:P.id,error:$e.toJson()};It(Kt,At,Xe),e.write(Kt)}function ce($e,At,Xe){$e===void 0&&($e=null);let Kt={jsonrpc:l,id:P.id,result:$e};It(Kt,At,Xe),e.write(Kt)}gr(P);let Ye=c[P.method],jt,Qt;Ye&&(jt=Ye.type,Qt=Ye.handler);let ri=Date.now();if(Qt||u){let $e=String(P.id),At=I.receiver.createCancellationTokenSource($e);v[$e]=At;try{let Xe;if(Qt)if(P.params===void 0){if(jt!==void 0&&jt.numberOfParams!==0){G(new me.ResponseError(me.ErrorCodes.InvalidParams,`Request ${P.method} defines ${jt.numberOfParams} params but recevied none.`),P.method,ri);return}Xe=Qt(At.token)}else if(Array.isArray(P.params)){if(jt!==void 0&&jt.parameterStructures===me.ParameterStructures.byName){G(new me.ResponseError(me.ErrorCodes.InvalidParams,`Request ${P.method} defines parameters by name but received parameters by position`),P.method,ri);return}Xe=Qt(...P.params,At.token)}else{if(jt!==void 0&&jt.parameterStructures===me.ParameterStructures.byPosition){G(new me.ResponseError(me.ErrorCodes.InvalidParams,`Request ${P.method} defines parameters by position but received parameters by name`),P.method,ri);return}Xe=Qt(P.params,At.token)}else u&&(Xe=u(P.method,P.params,At.token));let Kt=Xe;Xe?Kt.then?Kt.then(nn=>{delete v[$e],$(nn,P.method,ri)},nn=>{delete v[$e],nn instanceof me.ResponseError?G(nn,P.method,ri):nn&&ai.string(nn.message)?G(new me.ResponseError(me.ErrorCodes.InternalError,`Request ${P.method} failed with message: ${nn.message}`),P.method,ri):G(new me.ResponseError(me.ErrorCodes.InternalError,`Request ${P.method} failed unexpectedly without providing any details.`),P.method,ri)}):(delete v[$e],$(Xe,P.method,ri)):(delete v[$e],ce(Xe,P.method,ri))}catch(Xe){delete v[$e],Xe instanceof me.ResponseError?$(Xe,P.method,ri):Xe&&ai.string(Xe.message)?G(new me.ResponseError(me.ErrorCodes.InternalError,`Request ${P.method} failed with message: ${Xe.message}`),P.method,ri):G(new me.ResponseError(me.ErrorCodes.InternalError,`Request ${P.method} failed unexpectedly without providing any details.`),P.method,ri)}}else G(new me.ResponseError(me.ErrorCodes.MethodNotFound,`Unhandled method ${P.method}`),P.method,ri)}function gu(P){if(!Et())if(P.id===null)P.error?r.error(`Received response message without id: Error is: -${JSON.stringify(P.error,void 0,4)}`):r.error("Received response message without id. No further error information provided.");else{let $=String(P.id),G=b[$];if(kn(P,G),G){delete b[$];try{if(P.error){let ce=P.error;G.reject(new me.ResponseError(ce.code,ce.message,ce.data))}else if(P.result!==void 0)G.resolve(P.result);else throw new Error("Should never happen.")}catch(ce){ce.message?r.error(`Response handler '${G.method}' failed with message: ${ce.message}`):r.error(`Response handler '${G.method}' failed unexpectedly.`)}}}}function Re(P){if(Et())return;let $,G;if(P.method===Yd.type.method)G=ce=>{let Ye=ce.id,jt=v[String(Ye)];jt&&jt.cancel()};else{let ce=d[P.method];ce&&(G=ce.handler,$=ce.type)}if(G||h)try{fr(P),G?P.params===void 0?($!==void 0&&$.numberOfParams!==0&&$.parameterStructures!==me.ParameterStructures.byName&&r.error(`Notification ${P.method} defines ${$.numberOfParams} params but recevied none.`),G()):Array.isArray(P.params)?($!==void 0&&($.parameterStructures===me.ParameterStructures.byName&&r.error(`Notification ${P.method} defines parameters by name but received parameters by position`),$.numberOfParams!==P.params.length&&r.error(`Notification ${P.method} defines ${$.numberOfParams} params but received ${P.params.length} argumennts`)),G(...P.params)):($!==void 0&&$.parameterStructures===me.ParameterStructures.byPosition&&r.error(`Notification ${P.method} defines parameters by position but received parameters by name`),G(P.params)):h&&h(P.method,P.params)}catch(ce){ce.message?r.error(`Notification handler '${P.method}' failed with message: ${ce.message}`):r.error(`Notification handler '${P.method}' failed unexpectedly.`)}else W.fire(P)}function Se(P){if(!P){r.error("Received empty message.");return}r.error(`Received message which is neither a response nor a notification message: -${JSON.stringify(P,null,4)}`);let $=P;if(ai.string($.id)||ai.number($.id)){let G=String($.id),ce=b[G];ce&&ce.reject(new Error("The received response has neither a result nor an error property."))}}function Te(P){if(!(w===Wt.Off||!S))if(D===Dr.Text){let $;w===Wt.Verbose&&P.params&&($=`Params: ${JSON.stringify(P.params,null,4)} - -`),S.log(`Sending request '${P.method} - (${P.id})'.`,$)}else vs("send-request",P)}function Le(P){if(!(w===Wt.Off||!S))if(D===Dr.Text){let $;w===Wt.Verbose&&(P.params?$=`Params: ${JSON.stringify(P.params,null,4)} - -`:$=`No parameters provided. - -`),S.log(`Sending notification '${P.method}'.`,$)}else vs("send-notification",P)}function It(P,$,G){if(!(w===Wt.Off||!S))if(D===Dr.Text){let ce;w===Wt.Verbose&&(P.error&&P.error.data?ce=`Error data: ${JSON.stringify(P.error.data,null,4)} - -`:P.result?ce=`Result: ${JSON.stringify(P.result,null,4)} - -`:P.error===void 0&&(ce=`No result returned. - -`)),S.log(`Sending response '${$} - (${P.id})'. Processing request took ${Date.now()-G}ms`,ce)}else vs("send-response",P)}function gr(P){if(!(w===Wt.Off||!S))if(D===Dr.Text){let $;w===Wt.Verbose&&P.params&&($=`Params: ${JSON.stringify(P.params,null,4)} - -`),S.log(`Received request '${P.method} - (${P.id})'.`,$)}else vs("receive-request",P)}function fr(P){if(!(w===Wt.Off||!S||P.method===PS.type.method))if(D===Dr.Text){let $;w===Wt.Verbose&&(P.params?$=`Params: ${JSON.stringify(P.params,null,4)} - -`:$=`No parameters provided. - -`),S.log(`Received notification '${P.method}'.`,$)}else vs("receive-notification",P)}function kn(P,$){if(!(w===Wt.Off||!S))if(D===Dr.Text){let G;if(w===Wt.Verbose&&(P.error&&P.error.data?G=`Error data: ${JSON.stringify(P.error.data,null,4)} - -`:P.result?G=`Result: ${JSON.stringify(P.result,null,4)} - -`:P.error===void 0&&(G=`No result returned. - -`)),$){let ce=P.error?` Request failed: ${P.error.message} (${P.error.code}).`:"";S.log(`Received response '${$.method} - (${P.id})' in ${Date.now()-$.timerStart}ms.${ce}`,G)}else S.log(`Received response ${P.id} without active response promise.`,G)}else vs("receive-response",P)}function vs(P,$){if(!S||w===Wt.Off)return;let G={isLSPMessage:!0,type:P,message:$,timestamp:Date.now()};S.log(G)}function ws(){if(Ve())throw new dl(Hm.Closed,"Connection is closed.");if(Et())throw new dl(Hm.Disposed,"Connection is disposed.")}function Kte(){if(_e())throw new dl(Hm.AlreadyListening,"Connection is already listening")}function zte(){if(!_e())throw new Error("Call listen() first.")}function Zh(P){return P===void 0?null:P}function pR(P){if(P!==null)return P}function mR(P){return P!=null&&!Array.isArray(P)&&typeof P=="object"}function kx(P,$){switch(P){case me.ParameterStructures.auto:return mR($)?pR($):[Zh($)];case me.ParameterStructures.byName:if(!mR($))throw new Error("Recevied parameters by name but param is not an object literal.");return pR($);case me.ParameterStructures.byPosition:return[Zh($)];default:throw new Error(`Unknown parameter structure ${P.toString()}`)}}function bR(P,$){let G,ce=P.numberOfParams;switch(ce){case 0:G=void 0;break;case 1:G=kx(P.parameterStructures,$[0]);break;default:G=[];for(let Ye=0;Ye<$.length&&Ye{ws();let G,ce;if(ai.string(P)){G=P;let jt=$[0],Qt=0,ri=me.ParameterStructures.auto;me.ParameterStructures.is(jt)&&(Qt=1,ri=jt);let $e=$.length,At=$e-Qt;switch(At){case 0:ce=void 0;break;case 1:ce=kx(ri,$[Qt]);break;default:if(ri===me.ParameterStructures.byName)throw new Error(`Recevied ${At} parameters for 'by Name' notification parameter structure.`);ce=$.slice(Qt,$e).map(Xe=>Zh(Xe));break}}else{let jt=$;G=P.method,ce=bR(P,jt)}let Ye={jsonrpc:l,method:G,params:ce};Le(Ye),e.write(Ye)},onNotification:(P,$)=>{ws();let G;return ai.func(P)?h=P:$&&(ai.string(P)?(G=P,d[P]={type:void 0,handler:$}):(G=P.method,d[P.method]={type:P,handler:$})),{dispose:()=>{G!==void 0?delete d[G]:h=void 0}}},onProgress:(P,$,G)=>{if(g.has($))throw new Error(`Progress handler for token ${$} already registered`);return g.set($,G),{dispose:()=>{g.delete($)}}},sendProgress:(P,$,G)=>{fu.sendNotification(qm.type,{token:$,value:G})},onUnhandledProgress:B.event,sendRequest:(P,...$)=>{ws(),zte();let G,ce,Ye;if(ai.string(P)){G=P;let $e=$[0],At=$[$.length-1],Xe=0,Kt=me.ParameterStructures.auto;me.ParameterStructures.is($e)&&(Xe=1,Kt=$e);let nn=$.length;kS.CancellationToken.is(At)&&(nn=nn-1,Ye=At);let Na=nn-Xe;switch(Na){case 0:ce=void 0;break;case 1:ce=kx(Kt,$[Xe]);break;default:if(Kt===me.ParameterStructures.byName)throw new Error(`Recevied ${Na} parameters for 'by Name' request parameter structure.`);ce=$.slice(Xe,nn).map(Ds=>Zh(Ds));break}}else{let $e=$;G=P.method,ce=bR(P,$e);let At=P.numberOfParams;Ye=kS.CancellationToken.is($e[At])?$e[At]:void 0}let jt=o++,Qt;return Ye&&(Qt=Ye.onCancellationRequested(()=>{I.sender.sendCancellation(fu,jt)})),new Promise(($e,At)=>{let Xe={jsonrpc:l,id:jt,method:G,params:ce},Kt=Ds=>{$e(Ds),I.sender.cleanup(jt),Qt==null||Qt.dispose()},nn=Ds=>{At(Ds),I.sender.cleanup(jt),Qt==null||Qt.dispose()},Na={method:G,timerStart:Date.now(),resolve:Kt,reject:nn};Te(Xe);try{e.write(Xe)}catch(Ds){Na.reject(new me.ResponseError(me.ErrorCodes.MessageWriteError,Ds.message?Ds.message:"Unknown reason")),Na=null}Na&&(b[String(jt)]=Na)})},onRequest:(P,$)=>{ws();let G=null;return ES.is(P)?(G=void 0,u=P):ai.string(P)?(G=null,$!==void 0&&(G=P,c[P]={handler:$,type:void 0})):$!==void 0&&(G=P.method,c[P.method]={type:P,handler:$}),{dispose:()=>{G!==null&&(G!==void 0?delete c[G]:u=void 0)}}},trace:(P,$,G)=>{let ce=!1,Ye=Dr.Text;G!==void 0&&(ai.boolean(G)?ce=G:(ce=G.sendNotification||!1,Ye=G.traceFormat||Dr.Text)),w=P,D=Ye,w===Wt.Off?S=void 0:S=$,ce&&!Ve()&&!Et()&&fu.sendNotification(BN.type,{value:Wt.toString(P)})},onError:L.event,onClose:j.event,onUnhandledNotification:W.event,onDispose:N.event,end:()=>{e.end()},dispose:()=>{if(Et())return;F=xr.Disposed,N.fire(void 0);let P=new Error("Connection got disposed.");Object.keys(b).forEach($=>{b[$].reject(P)}),b=Object.create(null),v=Object.create(null),p=new MN.LinkedMap,ai.func(e.dispose)&&e.dispose(),ai.func(n.dispose)&&n.dispose()},listen:()=>{ws(),Kte(),F=xr.Listening,n.listen(Tx)},inspect:()=>{ON.default().console.log("inspect")}};return fu.onNotification(PS.type,P=>{w===Wt.Off||!S||S.log(P.message,w===Wt.Verbose?P.verbose:void 0)}),fu.onNotification(qm.type,P=>{let $=g.get(P.token);$?$(P.value):B.fire(P)}),fu}be.createMessageConnection=ide});var jS=m(X=>{"use strict";Object.defineProperty(X,"__esModule",{value:!0});X.CancellationSenderStrategy=X.CancellationReceiverStrategy=X.ConnectionError=X.ConnectionErrors=X.LogTraceNotification=X.SetTraceNotification=X.TraceFormat=X.Trace=X.ProgressType=X.createMessageConnection=X.NullLogger=X.ConnectionOptions=X.ConnectionStrategy=X.WriteableStreamMessageWriter=X.AbstractMessageWriter=X.MessageWriter=X.ReadableStreamMessageReader=X.AbstractMessageReader=X.MessageReader=X.CancellationToken=X.CancellationTokenSource=X.Emitter=X.Event=X.Disposable=X.ParameterStructures=X.NotificationType9=X.NotificationType8=X.NotificationType7=X.NotificationType6=X.NotificationType5=X.NotificationType4=X.NotificationType3=X.NotificationType2=X.NotificationType1=X.NotificationType0=X.NotificationType=X.ErrorCodes=X.ResponseError=X.RequestType9=X.RequestType8=X.RequestType7=X.RequestType6=X.RequestType5=X.RequestType4=X.RequestType3=X.RequestType2=X.RequestType1=X.RequestType0=X.RequestType=X.RAL=void 0;X.CancellationStrategy=void 0;var mt=pS();Object.defineProperty(X,"RequestType",{enumerable:!0,get:function(){return mt.RequestType}});Object.defineProperty(X,"RequestType0",{enumerable:!0,get:function(){return mt.RequestType0}});Object.defineProperty(X,"RequestType1",{enumerable:!0,get:function(){return mt.RequestType1}});Object.defineProperty(X,"RequestType2",{enumerable:!0,get:function(){return mt.RequestType2}});Object.defineProperty(X,"RequestType3",{enumerable:!0,get:function(){return mt.RequestType3}});Object.defineProperty(X,"RequestType4",{enumerable:!0,get:function(){return mt.RequestType4}});Object.defineProperty(X,"RequestType5",{enumerable:!0,get:function(){return mt.RequestType5}});Object.defineProperty(X,"RequestType6",{enumerable:!0,get:function(){return mt.RequestType6}});Object.defineProperty(X,"RequestType7",{enumerable:!0,get:function(){return mt.RequestType7}});Object.defineProperty(X,"RequestType8",{enumerable:!0,get:function(){return mt.RequestType8}});Object.defineProperty(X,"RequestType9",{enumerable:!0,get:function(){return mt.RequestType9}});Object.defineProperty(X,"ResponseError",{enumerable:!0,get:function(){return mt.ResponseError}});Object.defineProperty(X,"ErrorCodes",{enumerable:!0,get:function(){return mt.ErrorCodes}});Object.defineProperty(X,"NotificationType",{enumerable:!0,get:function(){return mt.NotificationType}});Object.defineProperty(X,"NotificationType0",{enumerable:!0,get:function(){return mt.NotificationType0}});Object.defineProperty(X,"NotificationType1",{enumerable:!0,get:function(){return mt.NotificationType1}});Object.defineProperty(X,"NotificationType2",{enumerable:!0,get:function(){return mt.NotificationType2}});Object.defineProperty(X,"NotificationType3",{enumerable:!0,get:function(){return mt.NotificationType3}});Object.defineProperty(X,"NotificationType4",{enumerable:!0,get:function(){return mt.NotificationType4}});Object.defineProperty(X,"NotificationType5",{enumerable:!0,get:function(){return mt.NotificationType5}});Object.defineProperty(X,"NotificationType6",{enumerable:!0,get:function(){return mt.NotificationType6}});Object.defineProperty(X,"NotificationType7",{enumerable:!0,get:function(){return mt.NotificationType7}});Object.defineProperty(X,"NotificationType8",{enumerable:!0,get:function(){return mt.NotificationType8}});Object.defineProperty(X,"NotificationType9",{enumerable:!0,get:function(){return mt.NotificationType9}});Object.defineProperty(X,"ParameterStructures",{enumerable:!0,get:function(){return mt.ParameterStructures}});var nde=dS();Object.defineProperty(X,"Disposable",{enumerable:!0,get:function(){return nde.Disposable}});var YN=Uu();Object.defineProperty(X,"Event",{enumerable:!0,get:function(){return YN.Event}});Object.defineProperty(X,"Emitter",{enumerable:!0,get:function(){return YN.Emitter}});var WN=vS();Object.defineProperty(X,"CancellationTokenSource",{enumerable:!0,get:function(){return WN.CancellationTokenSource}});Object.defineProperty(X,"CancellationToken",{enumerable:!0,get:function(){return WN.CancellationToken}});var FS=kN();Object.defineProperty(X,"MessageReader",{enumerable:!0,get:function(){return FS.MessageReader}});Object.defineProperty(X,"AbstractMessageReader",{enumerable:!0,get:function(){return FS.AbstractMessageReader}});Object.defineProperty(X,"ReadableStreamMessageReader",{enumerable:!0,get:function(){return FS.ReadableStreamMessageReader}});var IS=IN();Object.defineProperty(X,"MessageWriter",{enumerable:!0,get:function(){return IS.MessageWriter}});Object.defineProperty(X,"AbstractMessageWriter",{enumerable:!0,get:function(){return IS.AbstractMessageWriter}});Object.defineProperty(X,"WriteableStreamMessageWriter",{enumerable:!0,get:function(){return IS.WriteableStreamMessageWriter}});var ln=qN();Object.defineProperty(X,"ConnectionStrategy",{enumerable:!0,get:function(){return ln.ConnectionStrategy}});Object.defineProperty(X,"ConnectionOptions",{enumerable:!0,get:function(){return ln.ConnectionOptions}});Object.defineProperty(X,"NullLogger",{enumerable:!0,get:function(){return ln.NullLogger}});Object.defineProperty(X,"createMessageConnection",{enumerable:!0,get:function(){return ln.createMessageConnection}});Object.defineProperty(X,"ProgressType",{enumerable:!0,get:function(){return ln.ProgressType}});Object.defineProperty(X,"Trace",{enumerable:!0,get:function(){return ln.Trace}});Object.defineProperty(X,"TraceFormat",{enumerable:!0,get:function(){return ln.TraceFormat}});Object.defineProperty(X,"SetTraceNotification",{enumerable:!0,get:function(){return ln.SetTraceNotification}});Object.defineProperty(X,"LogTraceNotification",{enumerable:!0,get:function(){return ln.LogTraceNotification}});Object.defineProperty(X,"ConnectionErrors",{enumerable:!0,get:function(){return ln.ConnectionErrors}});Object.defineProperty(X,"ConnectionError",{enumerable:!0,get:function(){return ln.ConnectionError}});Object.defineProperty(X,"CancellationReceiverStrategy",{enumerable:!0,get:function(){return ln.CancellationReceiverStrategy}});Object.defineProperty(X,"CancellationSenderStrategy",{enumerable:!0,get:function(){return ln.CancellationSenderStrategy}});Object.defineProperty(X,"CancellationStrategy",{enumerable:!0,get:function(){return ln.CancellationStrategy}});var rde=Oo();X.RAL=rde.default});var Vu=m(We=>{"use strict";var ode=We&&We.__createBinding||(Object.create?function(n,e,t,i){i===void 0&&(i=t),Object.defineProperty(n,i,{enumerable:!0,get:function(){return e[t]}})}:function(n,e,t,i){i===void 0&&(i=t),n[i]=e[t]}),sde=We&&We.__exportStar||function(n,e){for(var t in n)t!=="default"&&!Object.prototype.hasOwnProperty.call(e,t)&&ode(e,n,t)};Object.defineProperty(We,"__esModule",{value:!0});We.createMessageConnection=We.createServerSocketTransport=We.createClientSocketTransport=We.createServerPipeTransport=We.createClientPipeTransport=We.generateRandomPipeName=We.StreamMessageWriter=We.StreamMessageReader=We.SocketMessageWriter=We.SocketMessageReader=We.IPCMessageWriter=We.IPCMessageReader=void 0;var Qu=QM();Qu.default.install();var Gr=jS(),ZN=require("path"),ade=require("os"),lde=require("crypto"),Ym=require("net");sde(jS(),We);var $N=class extends Gr.AbstractMessageReader{constructor(e){super();this.process=e;let t=this.process;t.on("error",i=>this.fireError(i)),t.on("close",()=>this.fireClose())}listen(e){return this.process.on("message",e),Gr.Disposable.create(()=>this.process.off("message",e))}};We.IPCMessageReader=$N;var XN=class extends Gr.AbstractMessageWriter{constructor(e){super();this.process=e,this.errorCount=0;let t=this.process;t.on("error",i=>this.fireError(i)),t.on("close",()=>this.fireClose)}write(e){try{return typeof this.process.send=="function"&&this.process.send(e,void 0,void 0,t=>{t?(this.errorCount++,this.handleError(t,e)):this.errorCount=0}),Promise.resolve()}catch(t){return this.handleError(t,e),Promise.reject(t)}}handleError(e,t){this.errorCount++,this.fireError(e,t,this.errorCount)}end(){}};We.IPCMessageWriter=XN;var Ku=class extends Gr.ReadableStreamMessageReader{constructor(e,t="utf-8"){super(Qu.default().stream.asReadableStream(e),t)}};We.SocketMessageReader=Ku;var zu=class extends Gr.WriteableStreamMessageWriter{constructor(e,t){super(Qu.default().stream.asWritableStream(e),t);this.socket=e}dispose(){super.dispose(),this.socket.destroy()}};We.SocketMessageWriter=zu;var AS=class extends Gr.ReadableStreamMessageReader{constructor(e,t){super(Qu.default().stream.asReadableStream(e),t)}};We.StreamMessageReader=AS;var OS=class extends Gr.WriteableStreamMessageWriter{constructor(e,t){super(Qu.default().stream.asWritableStream(e),t)}};We.StreamMessageWriter=OS;var JN=process.env.XDG_RUNTIME_DIR,ude=new Map([["linux",107],["darwin",103]]);function cde(){let n=lde.randomBytes(21).toString("hex");if(process.platform==="win32")return`\\\\.\\pipe\\vscode-jsonrpc-${n}-sock`;let e;JN?e=ZN.join(JN,`vscode-ipc-${n}.sock`):e=ZN.join(ade.tmpdir(),`vscode-${n}.sock`);let t=ude.get(process.platform);return t!==void 0&&e.length>=t&&Qu.default().console.warn(`WARNING: IPC handle "${e}" is longer than ${t} characters.`),e}We.generateRandomPipeName=cde;function hde(n,e="utf-8"){let t,i=new Promise((r,o)=>{t=r});return new Promise((r,o)=>{let s=Ym.createServer(a=>{s.close(),t([new Ku(a,e),new zu(a,e)])});s.on("error",o),s.listen(n,()=>{s.removeListener("error",o),r({onConnected:()=>i})})})}We.createClientPipeTransport=hde;function dde(n,e="utf-8"){let t=Ym.createConnection(n);return[new Ku(t,e),new zu(t,e)]}We.createServerPipeTransport=dde;function gde(n,e="utf-8"){let t,i=new Promise((r,o)=>{t=r});return new Promise((r,o)=>{let s=Ym.createServer(a=>{s.close(),t([new Ku(a,e),new zu(a,e)])});s.on("error",o),s.listen(n,"127.0.0.1",()=>{s.removeListener("error",o),r({onConnected:()=>i})})})}We.createClientSocketTransport=gde;function fde(n,e="utf-8"){let t=Ym.createConnection(n,"127.0.0.1");return[new Ku(t,e),new zu(t,e)]}We.createServerSocketTransport=fde;function pde(n){let e=n;return e.read!==void 0&&e.addListener!==void 0}function mde(n){let e=n;return e.write!==void 0&&e.addListener!==void 0}function bde(n,e,t,i){t||(t=Gr.NullLogger);let r=pde(n)?new AS(n):n,o=mde(e)?new OS(e):e;return Gr.ConnectionStrategy.is(i)&&(i={connectionStrategy:i}),Gr.createMessageConnection(r,o,t,i)}We.createMessageConnection=bde});var MS=m((i_e,UN)=>{"use strict";UN.exports=Vu()});var QN={};xs(QN,{AnnotatedTextEdit:()=>Ho,ChangeAnnotation:()=>gl,ChangeAnnotationIdentifier:()=>bi,CodeAction:()=>f0,CodeActionContext:()=>g0,CodeActionKind:()=>d0,CodeDescription:()=>$S,CodeLens:()=>p0,Color:()=>Zm,ColorInformation:()=>HS,ColorPresentation:()=>qS,Command:()=>ec,CompletionItem:()=>t0,CompletionItemKind:()=>QS,CompletionItemTag:()=>zS,CompletionList:()=>i0,CreateFile:()=>Zs,DeleteFile:()=>qo,Diagnostic:()=>Zd,DiagnosticRelatedInformation:()=>Jm,DiagnosticSeverity:()=>ZS,DiagnosticTag:()=>JS,DocumentHighlight:()=>a0,DocumentHighlightKind:()=>s0,DocumentLink:()=>b0,DocumentSymbol:()=>h0,EOL:()=>vde,FoldingRange:()=>WS,FoldingRangeKind:()=>YS,FormattingOptions:()=>m0,Hover:()=>n0,InsertReplaceEdit:()=>VS,InsertTextFormat:()=>KS,InsertTextMode:()=>e0,Location:()=>cn,LocationLink:()=>BS,MarkedString:()=>$d,MarkupContent:()=>Xm,MarkupKind:()=>tc,OptionalVersionedTextDocumentIdentifier:()=>Jd,ParameterInformation:()=>r0,Position:()=>Vt,Range:()=>Ne,RenameFile:()=>Js,SelectionRange:()=>y0,SignatureInformation:()=>o0,SymbolInformation:()=>c0,SymbolKind:()=>l0,SymbolTag:()=>u0,TextDocument:()=>v0,TextDocumentEdit:()=>Ws,TextDocumentIdentifier:()=>XS,TextDocumentItem:()=>GS,TextEdit:()=>un,VersionedTextDocumentIdentifier:()=>US,WorkspaceChange:()=>yde,WorkspaceEdit:()=>$m,integer:()=>NS,uinteger:()=>Wd});var NS,Wd,Vt,Ne,cn,BS,Zm,HS,qS,YS,WS,Jm,ZS,JS,$S,Zd,ec,un,gl,bi,Ho,Ws,Zs,Js,qo,$m,Wm,GN,yde,XS,US,Jd,GS,tc,Xm,QS,KS,zS,VS,e0,t0,i0,$d,n0,r0,o0,s0,a0,l0,u0,c0,h0,d0,g0,f0,p0,m0,b0,y0,vde,v0,wde,Y,Qr=_(()=>{"use strict";(function(n){n.MIN_VALUE=-2147483648,n.MAX_VALUE=2147483647})(NS||(NS={}));(function(n){n.MIN_VALUE=0,n.MAX_VALUE=2147483647})(Wd||(Wd={}));(function(n){function e(i,r){return i===Number.MAX_VALUE&&(i=Wd.MAX_VALUE),r===Number.MAX_VALUE&&(r=Wd.MAX_VALUE),{line:i,character:r}}n.create=e;function t(i){var r=i;return Y.objectLiteral(r)&&Y.uinteger(r.line)&&Y.uinteger(r.character)}n.is=t})(Vt||(Vt={}));(function(n){function e(i,r,o,s){if(Y.uinteger(i)&&Y.uinteger(r)&&Y.uinteger(o)&&Y.uinteger(s))return{start:Vt.create(i,r),end:Vt.create(o,s)};if(Vt.is(i)&&Vt.is(r))return{start:i,end:r};throw new Error("Range#create called with invalid arguments["+i+", "+r+", "+o+", "+s+"]")}n.create=e;function t(i){var r=i;return Y.objectLiteral(r)&&Vt.is(r.start)&&Vt.is(r.end)}n.is=t})(Ne||(Ne={}));(function(n){function e(i,r){return{uri:i,range:r}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Ne.is(r.range)&&(Y.string(r.uri)||Y.undefined(r.uri))}n.is=t})(cn||(cn={}));(function(n){function e(i,r,o,s){return{targetUri:i,targetRange:r,targetSelectionRange:o,originSelectionRange:s}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Ne.is(r.targetRange)&&Y.string(r.targetUri)&&(Ne.is(r.targetSelectionRange)||Y.undefined(r.targetSelectionRange))&&(Ne.is(r.originSelectionRange)||Y.undefined(r.originSelectionRange))}n.is=t})(BS||(BS={}));(function(n){function e(i,r,o,s){return{red:i,green:r,blue:o,alpha:s}}n.create=e;function t(i){var r=i;return Y.numberRange(r.red,0,1)&&Y.numberRange(r.green,0,1)&&Y.numberRange(r.blue,0,1)&&Y.numberRange(r.alpha,0,1)}n.is=t})(Zm||(Zm={}));(function(n){function e(i,r){return{range:i,color:r}}n.create=e;function t(i){var r=i;return Ne.is(r.range)&&Zm.is(r.color)}n.is=t})(HS||(HS={}));(function(n){function e(i,r,o){return{label:i,textEdit:r,additionalTextEdits:o}}n.create=e;function t(i){var r=i;return Y.string(r.label)&&(Y.undefined(r.textEdit)||un.is(r))&&(Y.undefined(r.additionalTextEdits)||Y.typedArray(r.additionalTextEdits,un.is))}n.is=t})(qS||(qS={}));(function(n){n.Comment="comment",n.Imports="imports",n.Region="region"})(YS||(YS={}));(function(n){function e(i,r,o,s,a){var l={startLine:i,endLine:r};return Y.defined(o)&&(l.startCharacter=o),Y.defined(s)&&(l.endCharacter=s),Y.defined(a)&&(l.kind=a),l}n.create=e;function t(i){var r=i;return Y.uinteger(r.startLine)&&Y.uinteger(r.startLine)&&(Y.undefined(r.startCharacter)||Y.uinteger(r.startCharacter))&&(Y.undefined(r.endCharacter)||Y.uinteger(r.endCharacter))&&(Y.undefined(r.kind)||Y.string(r.kind))}n.is=t})(WS||(WS={}));(function(n){function e(i,r){return{location:i,message:r}}n.create=e;function t(i){var r=i;return Y.defined(r)&&cn.is(r.location)&&Y.string(r.message)}n.is=t})(Jm||(Jm={}));(function(n){n.Error=1,n.Warning=2,n.Information=3,n.Hint=4})(ZS||(ZS={}));(function(n){n.Unnecessary=1,n.Deprecated=2})(JS||(JS={}));(function(n){function e(t){var i=t;return i!=null&&Y.string(i.href)}n.is=e})($S||($S={}));(function(n){function e(i,r,o,s,a,l){var u={range:i,message:r};return Y.defined(o)&&(u.severity=o),Y.defined(s)&&(u.code=s),Y.defined(a)&&(u.source=a),Y.defined(l)&&(u.relatedInformation=l),u}n.create=e;function t(i){var r,o=i;return Y.defined(o)&&Ne.is(o.range)&&Y.string(o.message)&&(Y.number(o.severity)||Y.undefined(o.severity))&&(Y.integer(o.code)||Y.string(o.code)||Y.undefined(o.code))&&(Y.undefined(o.codeDescription)||Y.string((r=o.codeDescription)===null||r===void 0?void 0:r.href))&&(Y.string(o.source)||Y.undefined(o.source))&&(Y.undefined(o.relatedInformation)||Y.typedArray(o.relatedInformation,Jm.is))}n.is=t})(Zd||(Zd={}));(function(n){function e(i,r){for(var o=[],s=2;s0&&(a.arguments=o),a}n.create=e;function t(i){var r=i;return Y.defined(r)&&Y.string(r.title)&&Y.string(r.command)}n.is=t})(ec||(ec={}));(function(n){function e(o,s){return{range:o,newText:s}}n.replace=e;function t(o,s){return{range:{start:o,end:o},newText:s}}n.insert=t;function i(o){return{range:o,newText:""}}n.del=i;function r(o){var s=o;return Y.objectLiteral(s)&&Y.string(s.newText)&&Ne.is(s.range)}n.is=r})(un||(un={}));(function(n){function e(i,r,o){var s={label:i};return r!==void 0&&(s.needsConfirmation=r),o!==void 0&&(s.description=o),s}n.create=e;function t(i){var r=i;return r!==void 0&&Y.objectLiteral(r)&&Y.string(r.label)&&(Y.boolean(r.needsConfirmation)||r.needsConfirmation===void 0)&&(Y.string(r.description)||r.description===void 0)}n.is=t})(gl||(gl={}));(function(n){function e(t){var i=t;return typeof i=="string"}n.is=e})(bi||(bi={}));(function(n){function e(o,s,a){return{range:o,newText:s,annotationId:a}}n.replace=e;function t(o,s,a){return{range:{start:o,end:o},newText:s,annotationId:a}}n.insert=t;function i(o,s){return{range:o,newText:"",annotationId:s}}n.del=i;function r(o){var s=o;return un.is(s)&&(gl.is(s.annotationId)||bi.is(s.annotationId))}n.is=r})(Ho||(Ho={}));(function(n){function e(i,r){return{textDocument:i,edits:r}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Jd.is(r.textDocument)&&Array.isArray(r.edits)}n.is=t})(Ws||(Ws={}));(function(n){function e(i,r,o){var s={kind:"create",uri:i};return r!==void 0&&(r.overwrite!==void 0||r.ignoreIfExists!==void 0)&&(s.options=r),o!==void 0&&(s.annotationId=o),s}n.create=e;function t(i){var r=i;return r&&r.kind==="create"&&Y.string(r.uri)&&(r.options===void 0||(r.options.overwrite===void 0||Y.boolean(r.options.overwrite))&&(r.options.ignoreIfExists===void 0||Y.boolean(r.options.ignoreIfExists)))&&(r.annotationId===void 0||bi.is(r.annotationId))}n.is=t})(Zs||(Zs={}));(function(n){function e(i,r,o,s){var a={kind:"rename",oldUri:i,newUri:r};return o!==void 0&&(o.overwrite!==void 0||o.ignoreIfExists!==void 0)&&(a.options=o),s!==void 0&&(a.annotationId=s),a}n.create=e;function t(i){var r=i;return r&&r.kind==="rename"&&Y.string(r.oldUri)&&Y.string(r.newUri)&&(r.options===void 0||(r.options.overwrite===void 0||Y.boolean(r.options.overwrite))&&(r.options.ignoreIfExists===void 0||Y.boolean(r.options.ignoreIfExists)))&&(r.annotationId===void 0||bi.is(r.annotationId))}n.is=t})(Js||(Js={}));(function(n){function e(i,r,o){var s={kind:"delete",uri:i};return r!==void 0&&(r.recursive!==void 0||r.ignoreIfNotExists!==void 0)&&(s.options=r),o!==void 0&&(s.annotationId=o),s}n.create=e;function t(i){var r=i;return r&&r.kind==="delete"&&Y.string(r.uri)&&(r.options===void 0||(r.options.recursive===void 0||Y.boolean(r.options.recursive))&&(r.options.ignoreIfNotExists===void 0||Y.boolean(r.options.ignoreIfNotExists)))&&(r.annotationId===void 0||bi.is(r.annotationId))}n.is=t})(qo||(qo={}));(function(n){function e(t){var i=t;return i&&(i.changes!==void 0||i.documentChanges!==void 0)&&(i.documentChanges===void 0||i.documentChanges.every(function(r){return Y.string(r.kind)?Zs.is(r)||Js.is(r)||qo.is(r):Ws.is(r)}))}n.is=e})($m||($m={}));Wm=function(){function n(e,t){this.edits=e,this.changeAnnotations=t}return n.prototype.insert=function(e,t,i){var r,o;if(i===void 0?r=un.insert(e,t):bi.is(i)?(o=i,r=Ho.insert(e,t,i)):(this.assertChangeAnnotations(this.changeAnnotations),o=this.changeAnnotations.manage(i),r=Ho.insert(e,t,o)),this.edits.push(r),o!==void 0)return o},n.prototype.replace=function(e,t,i){var r,o;if(i===void 0?r=un.replace(e,t):bi.is(i)?(o=i,r=Ho.replace(e,t,i)):(this.assertChangeAnnotations(this.changeAnnotations),o=this.changeAnnotations.manage(i),r=Ho.replace(e,t,o)),this.edits.push(r),o!==void 0)return o},n.prototype.delete=function(e,t){var i,r;if(t===void 0?i=un.del(e):bi.is(t)?(r=t,i=Ho.del(e,t)):(this.assertChangeAnnotations(this.changeAnnotations),r=this.changeAnnotations.manage(t),i=Ho.del(e,r)),this.edits.push(i),r!==void 0)return r},n.prototype.add=function(e){this.edits.push(e)},n.prototype.all=function(){return this.edits},n.prototype.clear=function(){this.edits.splice(0,this.edits.length)},n.prototype.assertChangeAnnotations=function(e){if(e===void 0)throw new Error("Text edit change is not configured to manage change annotations.")},n}(),GN=function(){function n(e){this._annotations=e===void 0?Object.create(null):e,this._counter=0,this._size=0}return n.prototype.all=function(){return this._annotations},Object.defineProperty(n.prototype,"size",{get:function(){return this._size},enumerable:!1,configurable:!0}),n.prototype.manage=function(e,t){var i;if(bi.is(e)?i=e:(i=this.nextId(),t=e),this._annotations[i]!==void 0)throw new Error("Id "+i+" is already in use.");if(t===void 0)throw new Error("No annotation provided for id "+i);return this._annotations[i]=t,this._size++,i},n.prototype.nextId=function(){return this._counter++,this._counter.toString()},n}(),yde=function(){function n(e){var t=this;this._textEditChanges=Object.create(null),e!==void 0?(this._workspaceEdit=e,e.documentChanges?(this._changeAnnotations=new GN(e.changeAnnotations),e.changeAnnotations=this._changeAnnotations.all(),e.documentChanges.forEach(function(i){if(Ws.is(i)){var r=new Wm(i.edits,t._changeAnnotations);t._textEditChanges[i.textDocument.uri]=r}})):e.changes&&Object.keys(e.changes).forEach(function(i){var r=new Wm(e.changes[i]);t._textEditChanges[i]=r})):this._workspaceEdit={}}return Object.defineProperty(n.prototype,"edit",{get:function(){return this.initDocumentChanges(),this._changeAnnotations!==void 0&&(this._changeAnnotations.size===0?this._workspaceEdit.changeAnnotations=void 0:this._workspaceEdit.changeAnnotations=this._changeAnnotations.all()),this._workspaceEdit},enumerable:!1,configurable:!0}),n.prototype.getTextEditChange=function(e){if(Jd.is(e)){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");var t={uri:e.uri,version:e.version},i=this._textEditChanges[t.uri];if(!i){var r=[],o={textDocument:t,edits:r};this._workspaceEdit.documentChanges.push(o),i=new Wm(r,this._changeAnnotations),this._textEditChanges[t.uri]=i}return i}else{if(this.initChanges(),this._workspaceEdit.changes===void 0)throw new Error("Workspace edit is not configured for normal text edit changes.");var i=this._textEditChanges[e];if(!i){var r=[];this._workspaceEdit.changes[e]=r,i=new Wm(r),this._textEditChanges[e]=i}return i}},n.prototype.initDocumentChanges=function(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._changeAnnotations=new GN,this._workspaceEdit.documentChanges=[],this._workspaceEdit.changeAnnotations=this._changeAnnotations.all())},n.prototype.initChanges=function(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._workspaceEdit.changes=Object.create(null))},n.prototype.createFile=function(e,t,i){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");var r;gl.is(t)||bi.is(t)?r=t:i=t;var o,s;if(r===void 0?o=Zs.create(e,i):(s=bi.is(r)?r:this._changeAnnotations.manage(r),o=Zs.create(e,i,s)),this._workspaceEdit.documentChanges.push(o),s!==void 0)return s},n.prototype.renameFile=function(e,t,i,r){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");var o;gl.is(i)||bi.is(i)?o=i:r=i;var s,a;if(o===void 0?s=Js.create(e,t,r):(a=bi.is(o)?o:this._changeAnnotations.manage(o),s=Js.create(e,t,r,a)),this._workspaceEdit.documentChanges.push(s),a!==void 0)return a},n.prototype.deleteFile=function(e,t,i){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");var r;gl.is(t)||bi.is(t)?r=t:i=t;var o,s;if(r===void 0?o=qo.create(e,i):(s=bi.is(r)?r:this._changeAnnotations.manage(r),o=qo.create(e,i,s)),this._workspaceEdit.documentChanges.push(o),s!==void 0)return s},n}();(function(n){function e(i){return{uri:i}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Y.string(r.uri)}n.is=t})(XS||(XS={}));(function(n){function e(i,r){return{uri:i,version:r}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Y.string(r.uri)&&Y.integer(r.version)}n.is=t})(US||(US={}));(function(n){function e(i,r){return{uri:i,version:r}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Y.string(r.uri)&&(r.version===null||Y.integer(r.version))}n.is=t})(Jd||(Jd={}));(function(n){function e(i,r,o,s){return{uri:i,languageId:r,version:o,text:s}}n.create=e;function t(i){var r=i;return Y.defined(r)&&Y.string(r.uri)&&Y.string(r.languageId)&&Y.integer(r.version)&&Y.string(r.text)}n.is=t})(GS||(GS={}));(function(n){n.PlainText="plaintext",n.Markdown="markdown"})(tc||(tc={}));(function(n){function e(t){var i=t;return i===n.PlainText||i===n.Markdown}n.is=e})(tc||(tc={}));(function(n){function e(t){var i=t;return Y.objectLiteral(t)&&tc.is(i.kind)&&Y.string(i.value)}n.is=e})(Xm||(Xm={}));(function(n){n.Text=1,n.Method=2,n.Function=3,n.Constructor=4,n.Field=5,n.Variable=6,n.Class=7,n.Interface=8,n.Module=9,n.Property=10,n.Unit=11,n.Value=12,n.Enum=13,n.Keyword=14,n.Snippet=15,n.Color=16,n.File=17,n.Reference=18,n.Folder=19,n.EnumMember=20,n.Constant=21,n.Struct=22,n.Event=23,n.Operator=24,n.TypeParameter=25})(QS||(QS={}));(function(n){n.PlainText=1,n.Snippet=2})(KS||(KS={}));(function(n){n.Deprecated=1})(zS||(zS={}));(function(n){function e(i,r,o){return{newText:i,insert:r,replace:o}}n.create=e;function t(i){var r=i;return r&&Y.string(r.newText)&&Ne.is(r.insert)&&Ne.is(r.replace)}n.is=t})(VS||(VS={}));(function(n){n.asIs=1,n.adjustIndentation=2})(e0||(e0={}));(function(n){function e(t){return{label:t}}n.create=e})(t0||(t0={}));(function(n){function e(t,i){return{items:t||[],isIncomplete:!!i}}n.create=e})(i0||(i0={}));(function(n){function e(i){return i.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}n.fromPlainText=e;function t(i){var r=i;return Y.string(r)||Y.objectLiteral(r)&&Y.string(r.language)&&Y.string(r.value)}n.is=t})($d||($d={}));(function(n){function e(t){var i=t;return!!i&&Y.objectLiteral(i)&&(Xm.is(i.contents)||$d.is(i.contents)||Y.typedArray(i.contents,$d.is))&&(t.range===void 0||Ne.is(t.range))}n.is=e})(n0||(n0={}));(function(n){function e(t,i){return i?{label:t,documentation:i}:{label:t}}n.create=e})(r0||(r0={}));(function(n){function e(t,i){for(var r=[],o=2;o=0;c--){var h=l[c],d=o.offsetAt(h.range.start),g=o.offsetAt(h.range.end);if(g<=u)a=a.substring(0,d)+h.newText+a.substring(g,a.length);else throw new Error("Overlapping edit");u=d}return a}n.applyEdits=i;function r(o,s){if(o.length<=1)return o;var a=o.length/2|0,l=o.slice(0,a),u=o.slice(a);r(l,s),r(u,s);for(var c=0,h=0,d=0;c0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets},n.prototype.positionAt=function(e){e=Math.max(Math.min(e,this._content.length),0);var t=this.getLineOffsets(),i=0,r=t.length;if(r===0)return Vt.create(0,e);for(;ie?r=o:i=o+1}var s=i-1;return Vt.create(s,e-t[s])},n.prototype.offsetAt=function(e){var t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;var i=t[e.line],r=e.line+1"u"}n.undefined=i;function r(g){return g===!0||g===!1}n.boolean=r;function o(g){return e.call(g)==="[object String]"}n.string=o;function s(g){return e.call(g)==="[object Number]"}n.number=s;function a(g,f,p){return e.call(g)==="[object Number]"&&f<=g&&g<=p}n.numberRange=a;function l(g){return e.call(g)==="[object Number]"&&-2147483648<=g&&g<=2147483647}n.integer=l;function u(g){return e.call(g)==="[object Number]"&&0<=g&&g<=2147483647}n.uinteger=u;function c(g){return e.call(g)==="[object Function]"}n.func=c;function h(g){return g!==null&&typeof g=="object"}n.objectLiteral=h;function d(g,f){return Array.isArray(g)&&g.every(f)}n.typedArray=d})(Y||(Y={}))});var li=m(Qn=>{"use strict";Object.defineProperty(Qn,"__esModule",{value:!0});Qn.ProtocolNotificationType=Qn.ProtocolNotificationType0=Qn.ProtocolRequestType=Qn.ProtocolRequestType0=Qn.RegistrationType=void 0;var ic=Vu(),KN=class{constructor(e){this.method=e}};Qn.RegistrationType=KN;var zN=class extends ic.RequestType0{constructor(e){super(e)}};Qn.ProtocolRequestType0=zN;var VN=class extends ic.RequestType{constructor(e){super(e,ic.ParameterStructures.byName)}};Qn.ProtocolRequestType=VN;var eB=class extends ic.NotificationType0{constructor(e){super(e)}};Qn.ProtocolNotificationType0=eB;var tB=class extends ic.NotificationType{constructor(e){super(e,ic.ParameterStructures.byName)}};Qn.ProtocolNotificationType=tB});var rB=m(Zt=>{"use strict";Object.defineProperty(Zt,"__esModule",{value:!0});Zt.objectLiteral=Zt.typedArray=Zt.stringArray=Zt.array=Zt.func=Zt.error=Zt.number=Zt.string=Zt.boolean=void 0;function Dde(n){return n===!0||n===!1}Zt.boolean=Dde;function iB(n){return typeof n=="string"||n instanceof String}Zt.string=iB;function xde(n){return typeof n=="number"||n instanceof Number}Zt.number=xde;function Cde(n){return n instanceof Error}Zt.error=Cde;function Sde(n){return typeof n=="function"}Zt.func=Sde;function nB(n){return Array.isArray(n)}Zt.array=nB;function Tde(n){return nB(n)&&n.every(e=>iB(e))}Zt.stringArray=Tde;function kde(n,e){return Array.isArray(n)&&n.every(e)}Zt.typedArray=kde;function Ede(n){return n!==null&&typeof n=="object"}Zt.objectLiteral=Ede});var oB=m(Xd=>{"use strict";Object.defineProperty(Xd,"__esModule",{value:!0});Xd.ImplementationRequest=void 0;var Pde=li(),_de;(function(n){n.method="textDocument/implementation",n.type=new Pde.ProtocolRequestType(n.method)})(_de=Xd.ImplementationRequest||(Xd.ImplementationRequest={}))});var sB=m(Ud=>{"use strict";Object.defineProperty(Ud,"__esModule",{value:!0});Ud.TypeDefinitionRequest=void 0;var Rde=li(),Lde;(function(n){n.method="textDocument/typeDefinition",n.type=new Rde.ProtocolRequestType(n.method)})(Lde=Ud.TypeDefinitionRequest||(Ud.TypeDefinitionRequest={}))});var lB=m($s=>{"use strict";Object.defineProperty($s,"__esModule",{value:!0});$s.DidChangeWorkspaceFoldersNotification=$s.WorkspaceFoldersRequest=void 0;var aB=li(),Fde;(function(n){n.type=new aB.ProtocolRequestType0("workspace/workspaceFolders")})(Fde=$s.WorkspaceFoldersRequest||($s.WorkspaceFoldersRequest={}));var Ide;(function(n){n.type=new aB.ProtocolNotificationType("workspace/didChangeWorkspaceFolders")})(Ide=$s.DidChangeWorkspaceFoldersNotification||($s.DidChangeWorkspaceFoldersNotification={}))});var uB=m(Gd=>{"use strict";Object.defineProperty(Gd,"__esModule",{value:!0});Gd.ConfigurationRequest=void 0;var jde=li(),Ade;(function(n){n.type=new jde.ProtocolRequestType("workspace/configuration")})(Ade=Gd.ConfigurationRequest||(Gd.ConfigurationRequest={}))});var hB=m(Xs=>{"use strict";Object.defineProperty(Xs,"__esModule",{value:!0});Xs.ColorPresentationRequest=Xs.DocumentColorRequest=void 0;var cB=li(),Ode;(function(n){n.method="textDocument/documentColor",n.type=new cB.ProtocolRequestType(n.method)})(Ode=Xs.DocumentColorRequest||(Xs.DocumentColorRequest={}));var Mde;(function(n){n.type=new cB.ProtocolRequestType("textDocument/colorPresentation")})(Mde=Xs.ColorPresentationRequest||(Xs.ColorPresentationRequest={}))});var dB=m(Us=>{"use strict";Object.defineProperty(Us,"__esModule",{value:!0});Us.FoldingRangeRequest=Us.FoldingRangeKind=void 0;var Nde=li(),Bde;(function(n){n.Comment="comment",n.Imports="imports",n.Region="region"})(Bde=Us.FoldingRangeKind||(Us.FoldingRangeKind={}));var Hde;(function(n){n.method="textDocument/foldingRange",n.type=new Nde.ProtocolRequestType(n.method)})(Hde=Us.FoldingRangeRequest||(Us.FoldingRangeRequest={}))});var gB=m(Qd=>{"use strict";Object.defineProperty(Qd,"__esModule",{value:!0});Qd.DeclarationRequest=void 0;var qde=li(),Yde;(function(n){n.method="textDocument/declaration",n.type=new qde.ProtocolRequestType(n.method)})(Yde=Qd.DeclarationRequest||(Qd.DeclarationRequest={}))});var fB=m(Kd=>{"use strict";Object.defineProperty(Kd,"__esModule",{value:!0});Kd.SelectionRangeRequest=void 0;var Wde=li(),Zde;(function(n){n.method="textDocument/selectionRange",n.type=new Wde.ProtocolRequestType(n.method)})(Zde=Kd.SelectionRangeRequest||(Kd.SelectionRangeRequest={}))});var mB=m(Cr=>{"use strict";Object.defineProperty(Cr,"__esModule",{value:!0});Cr.WorkDoneProgressCancelNotification=Cr.WorkDoneProgressCreateRequest=Cr.WorkDoneProgress=void 0;var Jde=Vu(),pB=li(),$de;(function(n){n.type=new Jde.ProgressType;function e(t){return t===n.type}n.is=e})($de=Cr.WorkDoneProgress||(Cr.WorkDoneProgress={}));var Xde;(function(n){n.type=new pB.ProtocolRequestType("window/workDoneProgress/create")})(Xde=Cr.WorkDoneProgressCreateRequest||(Cr.WorkDoneProgressCreateRequest={}));var Ude;(function(n){n.type=new pB.ProtocolNotificationType("window/workDoneProgress/cancel")})(Ude=Cr.WorkDoneProgressCancelNotification||(Cr.WorkDoneProgressCancelNotification={}))});var bB=m(Sr=>{"use strict";Object.defineProperty(Sr,"__esModule",{value:!0});Sr.CallHierarchyOutgoingCallsRequest=Sr.CallHierarchyIncomingCallsRequest=Sr.CallHierarchyPrepareRequest=void 0;var w0=li(),Gde;(function(n){n.method="textDocument/prepareCallHierarchy",n.type=new w0.ProtocolRequestType(n.method)})(Gde=Sr.CallHierarchyPrepareRequest||(Sr.CallHierarchyPrepareRequest={}));var Qde;(function(n){n.method="callHierarchy/incomingCalls",n.type=new w0.ProtocolRequestType(n.method)})(Qde=Sr.CallHierarchyIncomingCallsRequest||(Sr.CallHierarchyIncomingCallsRequest={}));var Kde;(function(n){n.method="callHierarchy/outgoingCalls",n.type=new w0.ProtocolRequestType(n.method)})(Kde=Sr.CallHierarchyOutgoingCallsRequest||(Sr.CallHierarchyOutgoingCallsRequest={}))});var yB=m(ze=>{"use strict";Object.defineProperty(ze,"__esModule",{value:!0});ze.SemanticTokensRefreshRequest=ze.SemanticTokensRangeRequest=ze.SemanticTokensDeltaRequest=ze.SemanticTokensRequest=ze.SemanticTokensRegistrationType=ze.TokenFormat=ze.SemanticTokens=ze.SemanticTokenModifiers=ze.SemanticTokenTypes=void 0;var zd=li(),zde;(function(n){n.namespace="namespace",n.type="type",n.class="class",n.enum="enum",n.interface="interface",n.struct="struct",n.typeParameter="typeParameter",n.parameter="parameter",n.variable="variable",n.property="property",n.enumMember="enumMember",n.event="event",n.function="function",n.method="method",n.macro="macro",n.keyword="keyword",n.modifier="modifier",n.comment="comment",n.string="string",n.number="number",n.regexp="regexp",n.operator="operator"})(zde=ze.SemanticTokenTypes||(ze.SemanticTokenTypes={}));var Vde;(function(n){n.declaration="declaration",n.definition="definition",n.readonly="readonly",n.static="static",n.deprecated="deprecated",n.abstract="abstract",n.async="async",n.modification="modification",n.documentation="documentation",n.defaultLibrary="defaultLibrary"})(Vde=ze.SemanticTokenModifiers||(ze.SemanticTokenModifiers={}));var ege;(function(n){function e(t){let i=t;return i!==void 0&&(i.resultId===void 0||typeof i.resultId=="string")&&Array.isArray(i.data)&&(i.data.length===0||typeof i.data[0]=="number")}n.is=e})(ege=ze.SemanticTokens||(ze.SemanticTokens={}));var tge;(function(n){n.Relative="relative"})(tge=ze.TokenFormat||(ze.TokenFormat={}));var ige;(function(n){n.method="textDocument/semanticTokens",n.type=new zd.RegistrationType(n.method)})(ige=ze.SemanticTokensRegistrationType||(ze.SemanticTokensRegistrationType={}));var nge;(function(n){n.method="textDocument/semanticTokens/full",n.type=new zd.ProtocolRequestType(n.method)})(nge=ze.SemanticTokensRequest||(ze.SemanticTokensRequest={}));var rge;(function(n){n.method="textDocument/semanticTokens/full/delta",n.type=new zd.ProtocolRequestType(n.method)})(rge=ze.SemanticTokensDeltaRequest||(ze.SemanticTokensDeltaRequest={}));var oge;(function(n){n.method="textDocument/semanticTokens/range",n.type=new zd.ProtocolRequestType(n.method)})(oge=ze.SemanticTokensRangeRequest||(ze.SemanticTokensRangeRequest={}));var sge;(function(n){n.method="workspace/semanticTokens/refresh",n.type=new zd.ProtocolRequestType0(n.method)})(sge=ze.SemanticTokensRefreshRequest||(ze.SemanticTokensRefreshRequest={}))});var vB=m(Vd=>{"use strict";Object.defineProperty(Vd,"__esModule",{value:!0});Vd.ShowDocumentRequest=void 0;var age=li(),lge;(function(n){n.method="window/showDocument",n.type=new age.ProtocolRequestType(n.method)})(lge=Vd.ShowDocumentRequest||(Vd.ShowDocumentRequest={}))});var wB=m(eg=>{"use strict";Object.defineProperty(eg,"__esModule",{value:!0});eg.LinkedEditingRangeRequest=void 0;var uge=li(),cge;(function(n){n.method="textDocument/linkedEditingRange",n.type=new uge.ProtocolRequestType(n.method)})(cge=eg.LinkedEditingRangeRequest||(eg.LinkedEditingRangeRequest={}))});var DB=m(Pt=>{"use strict";Object.defineProperty(Pt,"__esModule",{value:!0});Pt.WillDeleteFilesRequest=Pt.DidDeleteFilesNotification=Pt.DidRenameFilesNotification=Pt.WillRenameFilesRequest=Pt.DidCreateFilesNotification=Pt.WillCreateFilesRequest=Pt.FileOperationPatternKind=void 0;var nc=li(),hge;(function(n){n.file="file",n.folder="folder"})(hge=Pt.FileOperationPatternKind||(Pt.FileOperationPatternKind={}));var dge;(function(n){n.method="workspace/willCreateFiles",n.type=new nc.ProtocolRequestType(n.method)})(dge=Pt.WillCreateFilesRequest||(Pt.WillCreateFilesRequest={}));var gge;(function(n){n.method="workspace/didCreateFiles",n.type=new nc.ProtocolNotificationType(n.method)})(gge=Pt.DidCreateFilesNotification||(Pt.DidCreateFilesNotification={}));var fge;(function(n){n.method="workspace/willRenameFiles",n.type=new nc.ProtocolRequestType(n.method)})(fge=Pt.WillRenameFilesRequest||(Pt.WillRenameFilesRequest={}));var pge;(function(n){n.method="workspace/didRenameFiles",n.type=new nc.ProtocolNotificationType(n.method)})(pge=Pt.DidRenameFilesNotification||(Pt.DidRenameFilesNotification={}));var mge;(function(n){n.method="workspace/didDeleteFiles",n.type=new nc.ProtocolNotificationType(n.method)})(mge=Pt.DidDeleteFilesNotification||(Pt.DidDeleteFilesNotification={}));var bge;(function(n){n.method="workspace/willDeleteFiles",n.type=new nc.ProtocolRequestType(n.method)})(bge=Pt.WillDeleteFilesRequest||(Pt.WillDeleteFilesRequest={}))});var xB=m(Tr=>{"use strict";Object.defineProperty(Tr,"__esModule",{value:!0});Tr.MonikerRequest=Tr.MonikerKind=Tr.UniquenessLevel=void 0;var yge=li(),vge;(function(n){n.document="document",n.project="project",n.group="group",n.scheme="scheme",n.global="global"})(vge=Tr.UniquenessLevel||(Tr.UniquenessLevel={}));var wge;(function(n){n.import="import",n.export="export",n.local="local"})(wge=Tr.MonikerKind||(Tr.MonikerKind={}));var Dge;(function(n){n.method="textDocument/moniker",n.type=new yge.ProtocolRequestType(n.method)})(Dge=Tr.MonikerRequest||(Tr.MonikerRequest={}))});var EB=m(T=>{"use strict";Object.defineProperty(T,"__esModule",{value:!0});T.DocumentLinkRequest=T.CodeLensRefreshRequest=T.CodeLensResolveRequest=T.CodeLensRequest=T.WorkspaceSymbolRequest=T.CodeActionResolveRequest=T.CodeActionRequest=T.DocumentSymbolRequest=T.DocumentHighlightRequest=T.ReferencesRequest=T.DefinitionRequest=T.SignatureHelpRequest=T.SignatureHelpTriggerKind=T.HoverRequest=T.CompletionResolveRequest=T.CompletionRequest=T.CompletionTriggerKind=T.PublishDiagnosticsNotification=T.WatchKind=T.FileChangeType=T.DidChangeWatchedFilesNotification=T.WillSaveTextDocumentWaitUntilRequest=T.WillSaveTextDocumentNotification=T.TextDocumentSaveReason=T.DidSaveTextDocumentNotification=T.DidCloseTextDocumentNotification=T.DidChangeTextDocumentNotification=T.TextDocumentContentChangeEvent=T.DidOpenTextDocumentNotification=T.TextDocumentSyncKind=T.TelemetryEventNotification=T.LogMessageNotification=T.ShowMessageRequest=T.ShowMessageNotification=T.MessageType=T.DidChangeConfigurationNotification=T.ExitNotification=T.ShutdownRequest=T.InitializedNotification=T.InitializeError=T.InitializeRequest=T.WorkDoneProgressOptions=T.TextDocumentRegistrationOptions=T.StaticRegistrationOptions=T.FailureHandlingKind=T.ResourceOperationKind=T.UnregistrationRequest=T.RegistrationRequest=T.DocumentSelector=T.DocumentFilter=void 0;T.MonikerRequest=T.MonikerKind=T.UniquenessLevel=T.WillDeleteFilesRequest=T.DidDeleteFilesNotification=T.WillRenameFilesRequest=T.DidRenameFilesNotification=T.WillCreateFilesRequest=T.DidCreateFilesNotification=T.FileOperationPatternKind=T.LinkedEditingRangeRequest=T.ShowDocumentRequest=T.SemanticTokensRegistrationType=T.SemanticTokensRefreshRequest=T.SemanticTokensRangeRequest=T.SemanticTokensDeltaRequest=T.SemanticTokensRequest=T.TokenFormat=T.SemanticTokens=T.SemanticTokenModifiers=T.SemanticTokenTypes=T.CallHierarchyPrepareRequest=T.CallHierarchyOutgoingCallsRequest=T.CallHierarchyIncomingCallsRequest=T.WorkDoneProgressCancelNotification=T.WorkDoneProgressCreateRequest=T.WorkDoneProgress=T.SelectionRangeRequest=T.DeclarationRequest=T.FoldingRangeRequest=T.ColorPresentationRequest=T.DocumentColorRequest=T.ConfigurationRequest=T.DidChangeWorkspaceFoldersNotification=T.WorkspaceFoldersRequest=T.TypeDefinitionRequest=T.ImplementationRequest=T.ApplyWorkspaceEditRequest=T.ExecuteCommandRequest=T.PrepareRenameRequest=T.RenameRequest=T.PrepareSupportDefaultBehavior=T.DocumentOnTypeFormattingRequest=T.DocumentRangeFormattingRequest=T.DocumentFormattingRequest=T.DocumentLinkResolveRequest=void 0;var Gs=rB(),ve=li(),xge=oB();Object.defineProperty(T,"ImplementationRequest",{enumerable:!0,get:function(){return xge.ImplementationRequest}});var Cge=sB();Object.defineProperty(T,"TypeDefinitionRequest",{enumerable:!0,get:function(){return Cge.TypeDefinitionRequest}});var CB=lB();Object.defineProperty(T,"WorkspaceFoldersRequest",{enumerable:!0,get:function(){return CB.WorkspaceFoldersRequest}});Object.defineProperty(T,"DidChangeWorkspaceFoldersNotification",{enumerable:!0,get:function(){return CB.DidChangeWorkspaceFoldersNotification}});var Sge=uB();Object.defineProperty(T,"ConfigurationRequest",{enumerable:!0,get:function(){return Sge.ConfigurationRequest}});var SB=hB();Object.defineProperty(T,"DocumentColorRequest",{enumerable:!0,get:function(){return SB.DocumentColorRequest}});Object.defineProperty(T,"ColorPresentationRequest",{enumerable:!0,get:function(){return SB.ColorPresentationRequest}});var Tge=dB();Object.defineProperty(T,"FoldingRangeRequest",{enumerable:!0,get:function(){return Tge.FoldingRangeRequest}});var kge=gB();Object.defineProperty(T,"DeclarationRequest",{enumerable:!0,get:function(){return kge.DeclarationRequest}});var Ege=fB();Object.defineProperty(T,"SelectionRangeRequest",{enumerable:!0,get:function(){return Ege.SelectionRangeRequest}});var D0=mB();Object.defineProperty(T,"WorkDoneProgress",{enumerable:!0,get:function(){return D0.WorkDoneProgress}});Object.defineProperty(T,"WorkDoneProgressCreateRequest",{enumerable:!0,get:function(){return D0.WorkDoneProgressCreateRequest}});Object.defineProperty(T,"WorkDoneProgressCancelNotification",{enumerable:!0,get:function(){return D0.WorkDoneProgressCancelNotification}});var x0=bB();Object.defineProperty(T,"CallHierarchyIncomingCallsRequest",{enumerable:!0,get:function(){return x0.CallHierarchyIncomingCallsRequest}});Object.defineProperty(T,"CallHierarchyOutgoingCallsRequest",{enumerable:!0,get:function(){return x0.CallHierarchyOutgoingCallsRequest}});Object.defineProperty(T,"CallHierarchyPrepareRequest",{enumerable:!0,get:function(){return x0.CallHierarchyPrepareRequest}});var Yo=yB();Object.defineProperty(T,"SemanticTokenTypes",{enumerable:!0,get:function(){return Yo.SemanticTokenTypes}});Object.defineProperty(T,"SemanticTokenModifiers",{enumerable:!0,get:function(){return Yo.SemanticTokenModifiers}});Object.defineProperty(T,"SemanticTokens",{enumerable:!0,get:function(){return Yo.SemanticTokens}});Object.defineProperty(T,"TokenFormat",{enumerable:!0,get:function(){return Yo.TokenFormat}});Object.defineProperty(T,"SemanticTokensRequest",{enumerable:!0,get:function(){return Yo.SemanticTokensRequest}});Object.defineProperty(T,"SemanticTokensDeltaRequest",{enumerable:!0,get:function(){return Yo.SemanticTokensDeltaRequest}});Object.defineProperty(T,"SemanticTokensRangeRequest",{enumerable:!0,get:function(){return Yo.SemanticTokensRangeRequest}});Object.defineProperty(T,"SemanticTokensRefreshRequest",{enumerable:!0,get:function(){return Yo.SemanticTokensRefreshRequest}});Object.defineProperty(T,"SemanticTokensRegistrationType",{enumerable:!0,get:function(){return Yo.SemanticTokensRegistrationType}});var Pge=vB();Object.defineProperty(T,"ShowDocumentRequest",{enumerable:!0,get:function(){return Pge.ShowDocumentRequest}});var _ge=wB();Object.defineProperty(T,"LinkedEditingRangeRequest",{enumerable:!0,get:function(){return _ge.LinkedEditingRangeRequest}});var fl=DB();Object.defineProperty(T,"FileOperationPatternKind",{enumerable:!0,get:function(){return fl.FileOperationPatternKind}});Object.defineProperty(T,"DidCreateFilesNotification",{enumerable:!0,get:function(){return fl.DidCreateFilesNotification}});Object.defineProperty(T,"WillCreateFilesRequest",{enumerable:!0,get:function(){return fl.WillCreateFilesRequest}});Object.defineProperty(T,"DidRenameFilesNotification",{enumerable:!0,get:function(){return fl.DidRenameFilesNotification}});Object.defineProperty(T,"WillRenameFilesRequest",{enumerable:!0,get:function(){return fl.WillRenameFilesRequest}});Object.defineProperty(T,"DidDeleteFilesNotification",{enumerable:!0,get:function(){return fl.DidDeleteFilesNotification}});Object.defineProperty(T,"WillDeleteFilesRequest",{enumerable:!0,get:function(){return fl.WillDeleteFilesRequest}});var C0=xB();Object.defineProperty(T,"UniquenessLevel",{enumerable:!0,get:function(){return C0.UniquenessLevel}});Object.defineProperty(T,"MonikerKind",{enumerable:!0,get:function(){return C0.MonikerKind}});Object.defineProperty(T,"MonikerRequest",{enumerable:!0,get:function(){return C0.MonikerRequest}});var TB;(function(n){function e(t){let i=t;return Gs.string(i.language)||Gs.string(i.scheme)||Gs.string(i.pattern)}n.is=e})(TB=T.DocumentFilter||(T.DocumentFilter={}));var kB;(function(n){function e(t){if(!Array.isArray(t))return!1;for(let i of t)if(!Gs.string(i)&&!TB.is(i))return!1;return!0}n.is=e})(kB=T.DocumentSelector||(T.DocumentSelector={}));var Rge;(function(n){n.type=new ve.ProtocolRequestType("client/registerCapability")})(Rge=T.RegistrationRequest||(T.RegistrationRequest={}));var Lge;(function(n){n.type=new ve.ProtocolRequestType("client/unregisterCapability")})(Lge=T.UnregistrationRequest||(T.UnregistrationRequest={}));var Fge;(function(n){n.Create="create",n.Rename="rename",n.Delete="delete"})(Fge=T.ResourceOperationKind||(T.ResourceOperationKind={}));var Ige;(function(n){n.Abort="abort",n.Transactional="transactional",n.TextOnlyTransactional="textOnlyTransactional",n.Undo="undo"})(Ige=T.FailureHandlingKind||(T.FailureHandlingKind={}));var jge;(function(n){function e(t){let i=t;return i&&Gs.string(i.id)&&i.id.length>0}n.hasId=e})(jge=T.StaticRegistrationOptions||(T.StaticRegistrationOptions={}));var Age;(function(n){function e(t){let i=t;return i&&(i.documentSelector===null||kB.is(i.documentSelector))}n.is=e})(Age=T.TextDocumentRegistrationOptions||(T.TextDocumentRegistrationOptions={}));var Oge;(function(n){function e(i){let r=i;return Gs.objectLiteral(r)&&(r.workDoneProgress===void 0||Gs.boolean(r.workDoneProgress))}n.is=e;function t(i){let r=i;return r&&Gs.boolean(r.workDoneProgress)}n.hasWorkDoneProgress=t})(Oge=T.WorkDoneProgressOptions||(T.WorkDoneProgressOptions={}));var Mge;(function(n){n.type=new ve.ProtocolRequestType("initialize")})(Mge=T.InitializeRequest||(T.InitializeRequest={}));var Nge;(function(n){n.unknownProtocolVersion=1})(Nge=T.InitializeError||(T.InitializeError={}));var Bge;(function(n){n.type=new ve.ProtocolNotificationType("initialized")})(Bge=T.InitializedNotification||(T.InitializedNotification={}));var Hge;(function(n){n.type=new ve.ProtocolRequestType0("shutdown")})(Hge=T.ShutdownRequest||(T.ShutdownRequest={}));var qge;(function(n){n.type=new ve.ProtocolNotificationType0("exit")})(qge=T.ExitNotification||(T.ExitNotification={}));var Yge;(function(n){n.type=new ve.ProtocolNotificationType("workspace/didChangeConfiguration")})(Yge=T.DidChangeConfigurationNotification||(T.DidChangeConfigurationNotification={}));var Wge;(function(n){n.Error=1,n.Warning=2,n.Info=3,n.Log=4})(Wge=T.MessageType||(T.MessageType={}));var Zge;(function(n){n.type=new ve.ProtocolNotificationType("window/showMessage")})(Zge=T.ShowMessageNotification||(T.ShowMessageNotification={}));var Jge;(function(n){n.type=new ve.ProtocolRequestType("window/showMessageRequest")})(Jge=T.ShowMessageRequest||(T.ShowMessageRequest={}));var $ge;(function(n){n.type=new ve.ProtocolNotificationType("window/logMessage")})($ge=T.LogMessageNotification||(T.LogMessageNotification={}));var Xge;(function(n){n.type=new ve.ProtocolNotificationType("telemetry/event")})(Xge=T.TelemetryEventNotification||(T.TelemetryEventNotification={}));var Uge;(function(n){n.None=0,n.Full=1,n.Incremental=2})(Uge=T.TextDocumentSyncKind||(T.TextDocumentSyncKind={}));var Gge;(function(n){n.method="textDocument/didOpen",n.type=new ve.ProtocolNotificationType(n.method)})(Gge=T.DidOpenTextDocumentNotification||(T.DidOpenTextDocumentNotification={}));var Qge;(function(n){function e(i){let r=i;return r!=null&&typeof r.text=="string"&&r.range!==void 0&&(r.rangeLength===void 0||typeof r.rangeLength=="number")}n.isIncremental=e;function t(i){let r=i;return r!=null&&typeof r.text=="string"&&r.range===void 0&&r.rangeLength===void 0}n.isFull=t})(Qge=T.TextDocumentContentChangeEvent||(T.TextDocumentContentChangeEvent={}));var Kge;(function(n){n.method="textDocument/didChange",n.type=new ve.ProtocolNotificationType(n.method)})(Kge=T.DidChangeTextDocumentNotification||(T.DidChangeTextDocumentNotification={}));var zge;(function(n){n.method="textDocument/didClose",n.type=new ve.ProtocolNotificationType(n.method)})(zge=T.DidCloseTextDocumentNotification||(T.DidCloseTextDocumentNotification={}));var Vge;(function(n){n.method="textDocument/didSave",n.type=new ve.ProtocolNotificationType(n.method)})(Vge=T.DidSaveTextDocumentNotification||(T.DidSaveTextDocumentNotification={}));var efe;(function(n){n.Manual=1,n.AfterDelay=2,n.FocusOut=3})(efe=T.TextDocumentSaveReason||(T.TextDocumentSaveReason={}));var tfe;(function(n){n.method="textDocument/willSave",n.type=new ve.ProtocolNotificationType(n.method)})(tfe=T.WillSaveTextDocumentNotification||(T.WillSaveTextDocumentNotification={}));var ife;(function(n){n.method="textDocument/willSaveWaitUntil",n.type=new ve.ProtocolRequestType(n.method)})(ife=T.WillSaveTextDocumentWaitUntilRequest||(T.WillSaveTextDocumentWaitUntilRequest={}));var nfe;(function(n){n.type=new ve.ProtocolNotificationType("workspace/didChangeWatchedFiles")})(nfe=T.DidChangeWatchedFilesNotification||(T.DidChangeWatchedFilesNotification={}));var rfe;(function(n){n.Created=1,n.Changed=2,n.Deleted=3})(rfe=T.FileChangeType||(T.FileChangeType={}));var ofe;(function(n){n.Create=1,n.Change=2,n.Delete=4})(ofe=T.WatchKind||(T.WatchKind={}));var sfe;(function(n){n.type=new ve.ProtocolNotificationType("textDocument/publishDiagnostics")})(sfe=T.PublishDiagnosticsNotification||(T.PublishDiagnosticsNotification={}));var afe;(function(n){n.Invoked=1,n.TriggerCharacter=2,n.TriggerForIncompleteCompletions=3})(afe=T.CompletionTriggerKind||(T.CompletionTriggerKind={}));var lfe;(function(n){n.method="textDocument/completion",n.type=new ve.ProtocolRequestType(n.method)})(lfe=T.CompletionRequest||(T.CompletionRequest={}));var ufe;(function(n){n.method="completionItem/resolve",n.type=new ve.ProtocolRequestType(n.method)})(ufe=T.CompletionResolveRequest||(T.CompletionResolveRequest={}));var cfe;(function(n){n.method="textDocument/hover",n.type=new ve.ProtocolRequestType(n.method)})(cfe=T.HoverRequest||(T.HoverRequest={}));var hfe;(function(n){n.Invoked=1,n.TriggerCharacter=2,n.ContentChange=3})(hfe=T.SignatureHelpTriggerKind||(T.SignatureHelpTriggerKind={}));var dfe;(function(n){n.method="textDocument/signatureHelp",n.type=new ve.ProtocolRequestType(n.method)})(dfe=T.SignatureHelpRequest||(T.SignatureHelpRequest={}));var gfe;(function(n){n.method="textDocument/definition",n.type=new ve.ProtocolRequestType(n.method)})(gfe=T.DefinitionRequest||(T.DefinitionRequest={}));var ffe;(function(n){n.method="textDocument/references",n.type=new ve.ProtocolRequestType(n.method)})(ffe=T.ReferencesRequest||(T.ReferencesRequest={}));var pfe;(function(n){n.method="textDocument/documentHighlight",n.type=new ve.ProtocolRequestType(n.method)})(pfe=T.DocumentHighlightRequest||(T.DocumentHighlightRequest={}));var mfe;(function(n){n.method="textDocument/documentSymbol",n.type=new ve.ProtocolRequestType(n.method)})(mfe=T.DocumentSymbolRequest||(T.DocumentSymbolRequest={}));var bfe;(function(n){n.method="textDocument/codeAction",n.type=new ve.ProtocolRequestType(n.method)})(bfe=T.CodeActionRequest||(T.CodeActionRequest={}));var yfe;(function(n){n.method="codeAction/resolve",n.type=new ve.ProtocolRequestType(n.method)})(yfe=T.CodeActionResolveRequest||(T.CodeActionResolveRequest={}));var vfe;(function(n){n.method="workspace/symbol",n.type=new ve.ProtocolRequestType(n.method)})(vfe=T.WorkspaceSymbolRequest||(T.WorkspaceSymbolRequest={}));var wfe;(function(n){n.method="textDocument/codeLens",n.type=new ve.ProtocolRequestType(n.method)})(wfe=T.CodeLensRequest||(T.CodeLensRequest={}));var Dfe;(function(n){n.method="codeLens/resolve",n.type=new ve.ProtocolRequestType(n.method)})(Dfe=T.CodeLensResolveRequest||(T.CodeLensResolveRequest={}));var xfe;(function(n){n.method="workspace/codeLens/refresh",n.type=new ve.ProtocolRequestType0(n.method)})(xfe=T.CodeLensRefreshRequest||(T.CodeLensRefreshRequest={}));var Cfe;(function(n){n.method="textDocument/documentLink",n.type=new ve.ProtocolRequestType(n.method)})(Cfe=T.DocumentLinkRequest||(T.DocumentLinkRequest={}));var Sfe;(function(n){n.method="documentLink/resolve",n.type=new ve.ProtocolRequestType(n.method)})(Sfe=T.DocumentLinkResolveRequest||(T.DocumentLinkResolveRequest={}));var Tfe;(function(n){n.method="textDocument/formatting",n.type=new ve.ProtocolRequestType(n.method)})(Tfe=T.DocumentFormattingRequest||(T.DocumentFormattingRequest={}));var kfe;(function(n){n.method="textDocument/rangeFormatting",n.type=new ve.ProtocolRequestType(n.method)})(kfe=T.DocumentRangeFormattingRequest||(T.DocumentRangeFormattingRequest={}));var Efe;(function(n){n.method="textDocument/onTypeFormatting",n.type=new ve.ProtocolRequestType(n.method)})(Efe=T.DocumentOnTypeFormattingRequest||(T.DocumentOnTypeFormattingRequest={}));var Pfe;(function(n){n.Identifier=1})(Pfe=T.PrepareSupportDefaultBehavior||(T.PrepareSupportDefaultBehavior={}));var _fe;(function(n){n.method="textDocument/rename",n.type=new ve.ProtocolRequestType(n.method)})(_fe=T.RenameRequest||(T.RenameRequest={}));var Rfe;(function(n){n.method="textDocument/prepareRename",n.type=new ve.ProtocolRequestType(n.method)})(Rfe=T.PrepareRenameRequest||(T.PrepareRenameRequest={}));var Lfe;(function(n){n.type=new ve.ProtocolRequestType("workspace/executeCommand")})(Lfe=T.ExecuteCommandRequest||(T.ExecuteCommandRequest={}));var Ffe;(function(n){n.type=new ve.ProtocolRequestType("workspace/applyEdit")})(Ffe=T.ApplyWorkspaceEditRequest||(T.ApplyWorkspaceEditRequest={}))});var _B=m(Um=>{"use strict";Object.defineProperty(Um,"__esModule",{value:!0});Um.createProtocolConnection=void 0;var PB=Vu();function Ife(n,e,t,i){return PB.ConnectionStrategy.is(i)&&(i={connectionStrategy:i}),PB.createMessageConnection(n,e,t,i)}Um.createProtocolConnection=Ife});var RB=m($i=>{"use strict";var jfe=$i&&$i.__createBinding||(Object.create?function(n,e,t,i){i===void 0&&(i=t),Object.defineProperty(n,i,{enumerable:!0,get:function(){return e[t]}})}:function(n,e,t,i){i===void 0&&(i=t),n[i]=e[t]}),Gm=$i&&$i.__exportStar||function(n,e){for(var t in n)t!=="default"&&!Object.prototype.hasOwnProperty.call(e,t)&&jfe(e,n,t)};Object.defineProperty($i,"__esModule",{value:!0});$i.LSPErrorCodes=$i.createProtocolConnection=void 0;Gm(Vu(),$i);Gm((Qr(),Ha(QN)),$i);Gm(li(),$i);Gm(EB(),$i);var Afe=_B();Object.defineProperty($i,"createProtocolConnection",{enumerable:!0,get:function(){return Afe.createProtocolConnection}});var Ofe;(function(n){n.lspReservedErrorRangeStart=-32899,n.ContentModified=-32801,n.RequestCancelled=-32800,n.lspReservedErrorRangeEnd=-32800})(Ofe=$i.LSPErrorCodes||($i.LSPErrorCodes={}))});var H=m(Kr=>{"use strict";var Mfe=Kr&&Kr.__createBinding||(Object.create?function(n,e,t,i){i===void 0&&(i=t),Object.defineProperty(n,i,{enumerable:!0,get:function(){return e[t]}})}:function(n,e,t,i){i===void 0&&(i=t),n[i]=e[t]}),LB=Kr&&Kr.__exportStar||function(n,e){for(var t in n)t!=="default"&&!Object.prototype.hasOwnProperty.call(e,t)&&Mfe(e,n,t)};Object.defineProperty(Kr,"__esModule",{value:!0});Kr.createProtocolConnection=void 0;var Nfe=MS();LB(MS(),Kr);LB(RB(),Kr);function Bfe(n,e,t,i){return Nfe.createMessageConnection(n,e,t,i)}Kr.createProtocolConnection=Bfe});var Ei=m((S_e,FB)=>{function S0(n,e,t){var i,r,o,s,a;e==null&&(e=100);function l(){var c=Date.now()-s;c=0?i=setTimeout(l,e-c):(i=null,t||(a=n.apply(o,r),o=r=null))}var u=function(){o=this,r=arguments,s=Date.now();var c=t&&!i;return i||(i=setTimeout(l,e)),c&&(a=n.apply(o,r),o=r=null),a};return u.clear=function(){i&&(clearTimeout(i),i=null)},u.flush=function(){i&&(a=n.apply(o,r),o=r=null,clearTimeout(i),i=null)},u}S0.debounce=S0;FB.exports=S0});var jB=m((T_e,IB)=>{"use strict";var Nt={rfc3986:{}};Nt.generate=function(){var n="|",e="0-9",t="["+e+"]",i="a-zA-Z",r="["+i+"]";Nt.rfc3986.cidr=t+n+"[1-2]"+t+n+"3[0-2]";var o=e+"A-Fa-f",s="["+o+"]",a=i+e+"-\\._~",l="!\\$&'\\(\\)\\*\\+,;=",u="%"+o,c=a+u+l+":@",h="["+c+"]",d="0?",g="(?:"+d+d+t+n+d+"[1-9]"+t+n+"1"+t+t+n+"2[0-4]"+t+n+"25[0-5])";Nt.rfc3986.IPv4address="(?:"+g+"\\.){3}"+g;var f=s+"{1,4}",p="(?:"+f+":"+f+"|"+Nt.rfc3986.IPv4address+")",b="(?:"+f+":){6}"+p,v="::(?:"+f+":){5}"+p,w="(?:"+f+")?::(?:"+f+":){4}"+p,D="(?:(?:"+f+":){0,1}"+f+")?::(?:"+f+":){3}"+p,S="(?:(?:"+f+":){0,2}"+f+")?::(?:"+f+":){2}"+p,F="(?:(?:"+f+":){0,3}"+f+")?::"+f+":"+p,L="(?:(?:"+f+":){0,4}"+f+")?::"+p,j="(?:(?:"+f+":){0,5}"+f+")?::"+f,W="(?:(?:"+f+":){0,6}"+f+")?::";Nt.rfc3986.IPv6address="(?:"+b+n+v+n+w+n+D+n+S+n+F+n+L+n+j+n+W+")",Nt.rfc3986.IPvFuture="v"+s+"+\\.["+a+l+":]+",Nt.rfc3986.scheme=r+"["+i+e+"+-\\.]*";var B="["+a+u+l+":]*";Nt.rfc3986.IPLiteral="\\[(?:"+Nt.rfc3986.IPv6address+n+Nt.rfc3986.IPvFuture+")\\]";var N="["+a+u+l+"]{0,255}",I="(?:"+Nt.rfc3986.IPLiteral+n+Nt.rfc3986.IPv4address+n+N+")",M=t+"*",J="(?:"+B+"@)?"+I+"(?::"+M+")?",K=h+"*",ae=h+"+",je="(?:\\/"+K+")*",_e="\\/(?:"+ae+je+")?",Ve=ae+je;Nt.rfc3986.hierPart="(?:(?:\\/\\/"+J+je+")"+n+_e+n+Ve+")",Nt.rfc3986.query="["+c+"\\/\\?]*(?=#|$)",Nt.rfc3986.fragment="["+c+"\\/\\?]*",Nt.rfc3986.uri="^(?:"+Nt.rfc3986.scheme+":"+Nt.rfc3986.hierPart+")(?:\\?"+Nt.rfc3986.query+")?(?:#"+Nt.rfc3986.fragment+")?$"};Nt.generate();IB.exports=Nt.rfc3986});var T0=m((k_e,AB)=>{"use strict";var tg=jB();function Hfe(n){return n.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g,"\\$&")}var ig={Uri:{createUriRegex:function(n){if(n=n||{},typeof n!="object"||Array.isArray(n))throw new Error("options must be an object");var e="";if(n.scheme){if(Array.isArray(n.scheme)||(n.scheme=[n.scheme]),n.scheme.length<=0)throw new Error("scheme must have at least 1 scheme specified");for(var t=0;t=97&&o<=122||o>=65&&o<=90||o>=48&&o<=57||o===45||o===46||o===95||o===126||e&&o===47)i!==-1&&(t+=encodeURIComponent(n.substring(i,r)),i=-1),t!==void 0&&(t+=n.charAt(r));else{t===void 0&&(t=n.substr(0,r));var s=HB[o];s!==void 0?(i!==-1&&(t+=encodeURIComponent(n.substring(i,r)),i=-1),t+=s):i===-1&&(i=r)}}return i!==-1&&(t+=encodeURIComponent(n.substring(i))),t!==void 0?t:n}function Gfe(n){for(var e=void 0,t=0;t1&&n.scheme==="file"?t="//"+n.authority+n.path:n.path.charCodeAt(0)===47&&(n.path.charCodeAt(1)>=65&&n.path.charCodeAt(1)<=90||n.path.charCodeAt(1)>=97&&n.path.charCodeAt(1)<=122)&&n.path.charCodeAt(2)===58?e?t=n.path.substr(1):t=n.path[1].toLowerCase()+n.path.substr(2):t=n.path,ng&&(t=t.replace(/\//g,"\\")),t}function k0(n,e){var t=e?Gfe:MB,i="",r=n.scheme,o=n.authority,s=n.path,a=n.query,l=n.fragment;if(r&&(i+=r,i+=":"),(o||r==="file")&&(i+=kr,i+=kr),o){var u=o.indexOf("@");if(u!==-1){var c=o.substr(0,u);o=o.substr(u+1),u=c.indexOf(":"),u===-1?i+=t(c,!1):(i+=t(c.substr(0,u),!1),i+=":",i+=t(c.substr(u+1),!1)),i+="@"}o=o.toLowerCase(),u=o.indexOf(":"),u===-1?i+=t(o,!1):(i+=t(o.substr(0,u),!1),i+=o.substr(u))}if(s){if(s.length>=3&&s.charCodeAt(0)===47&&s.charCodeAt(2)===58){var h=s.charCodeAt(1);h>=65&&h<=90&&(s="/"+String.fromCharCode(h+32)+":"+s.substr(3))}else if(s.length>=2&&s.charCodeAt(1)===58){var h=s.charCodeAt(0);h>=65&&h<=90&&(s=String.fromCharCode(h+32)+":"+s.substr(2))}i+=t(s,!0)}return a&&(i+="?",i+=t(a,!1)),l&&(i+="#",i+=e?l:MB(l,!1)),i}function YB(n){try{return decodeURIComponent(n)}catch{return n.length>3?n.substr(0,3)+YB(n.substr(3)):n}}function Qm(n){return n.match(NB)?n.replace(NB,function(e){return YB(e)}):n}var qfe,Bt,ng,OB,Yfe,Wfe,Zfe,at,kr,Ufe,O,BB,rc,HB,NB,we=_(()=>{"use strict";qfe=function(){var n=function(e,t){return n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(i,r){i.__proto__=r}||function(i,r){for(var o in r)r.hasOwnProperty(o)&&(i[o]=r[o])},n(e,t)};return function(e,t){n(e,t);function i(){this.constructor=e}e.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}}();typeof process=="object"?ng=process.platform==="win32":typeof navigator=="object"&&(OB=navigator.userAgent,ng=OB.indexOf("Windows")>=0);Yfe=/^\w[\w\d+.-]*$/,Wfe=/^\//,Zfe=/^\/\//;at="",kr="/",Ufe=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/,O=function(){function n(e,t,i,r,o,s){s===void 0&&(s=!1),typeof e=="object"?(this.scheme=e.scheme||at,this.authority=e.authority||at,this.path=e.path||at,this.query=e.query||at,this.fragment=e.fragment||at):(this.scheme=$fe(e,s),this.authority=t||at,this.path=Xfe(this.scheme,i||at),this.query=r||at,this.fragment=o||at,Jfe(this,s))}return n.isUri=function(e){return e instanceof n?!0:e?typeof e.authority=="string"&&typeof e.fragment=="string"&&typeof e.path=="string"&&typeof e.query=="string"&&typeof e.scheme=="string"&&typeof e.fsPath=="function"&&typeof e.with=="function"&&typeof e.toString=="function":!1},Object.defineProperty(n.prototype,"fsPath",{get:function(){return qB(this,!1)},enumerable:!0,configurable:!0}),n.prototype.with=function(e){if(!e)return this;var t=e.scheme,i=e.authority,r=e.path,o=e.query,s=e.fragment;return t===void 0?t=this.scheme:t===null&&(t=at),i===void 0?i=this.authority:i===null&&(i=at),r===void 0?r=this.path:r===null&&(r=at),o===void 0?o=this.query:o===null&&(o=at),s===void 0?s=this.fragment:s===null&&(s=at),t===this.scheme&&i===this.authority&&r===this.path&&o===this.query&&s===this.fragment?this:new rc(t,i,r,o,s)},n.parse=function(e,t){t===void 0&&(t=!1);var i=Ufe.exec(e);return i?new rc(i[2]||at,Qm(i[4]||at),Qm(i[5]||at),Qm(i[7]||at),Qm(i[9]||at),t):new rc(at,at,at,at,at)},n.file=function(e){var t=at;if(ng&&(e=e.replace(/\\/g,kr)),e[0]===kr&&e[1]===kr){var i=e.indexOf(kr,2);i===-1?(t=e.substring(2),e=kr):(t=e.substring(2,i),e=e.substring(i)||kr)}return new rc("file",t,e,at,at)},n.from=function(e){return new rc(e.scheme,e.authority,e.path,e.query,e.fragment)},n.prototype.toString=function(e){return e===void 0&&(e=!1),k0(this,e)},n.prototype.toJSON=function(){return this},n.revive=function(e){if(e){if(e instanceof n)return e;var t=new rc(e);return t._formatted=e.external,t._fsPath=e._sep===BB?e.fsPath:null,t}else return e},n}(),BB=ng?1:void 0,rc=function(n){qfe(e,n);function e(){var t=n!==null&&n.apply(this,arguments)||this;return t._formatted=null,t._fsPath=null,t}return Object.defineProperty(e.prototype,"fsPath",{get:function(){return this._fsPath||(this._fsPath=qB(this,!1)),this._fsPath},enumerable:!0,configurable:!0}),e.prototype.toString=function(t){return t===void 0&&(t=!1),t?k0(this,!0):(this._formatted||(this._formatted=k0(this,!1)),this._formatted)},e.prototype.toJSON=function(){var t={$mid:1};return this._fsPath&&(t.fsPath=this._fsPath,t._sep=BB),this._formatted&&(t.external=this._formatted),this.path&&(t.path=this.path),this.scheme&&(t.scheme=this.scheme),this.authority&&(t.authority=this.authority),this.query&&(t.query=this.query),this.fragment&&(t.fragment=this.fragment),t},e}(O),HB=(Bt={},Bt[58]="%3A",Bt[47]="%2F",Bt[63]="%3F",Bt[35]="%23",Bt[91]="%5B",Bt[93]="%5D",Bt[64]="%40",Bt[33]="%21",Bt[36]="%24",Bt[38]="%26",Bt[39]="%27",Bt[40]="%28",Bt[41]="%29",Bt[42]="%2A",Bt[43]="%2B",Bt[44]="%2C",Bt[59]="%3B",Bt[61]="%3D",Bt[32]="%20",Bt);NB=/(%[0-9A-Za-z][0-9A-Za-z])+/g});var XB=m((P_e,$B)=>{$B.exports=JB;JB.sync=Kfe;var WB=require("fs");function Qfe(n,e){var t=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!t||(t=t.split(";"),t.indexOf("")!==-1))return!0;for(var i=0;i{KB.exports=GB;GB.sync=zfe;var UB=require("fs");function GB(n,e,t){UB.stat(n,function(i,r){t(i,i?!1:QB(r,e))})}function zfe(n,e){return QB(UB.statSync(n),e)}function QB(n,e){return n.isFile()&&Vfe(n,e)}function Vfe(n,e){var t=n.mode,i=n.uid,r=n.gid,o=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),s=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),a=parseInt("100",8),l=parseInt("010",8),u=parseInt("001",8),c=a|l,h=t&u||t&l&&r===s||t&a&&i===o||t&c&&o===0;return h}});var eH=m((L_e,VB)=>{var R_e=require("fs"),Km;process.platform==="win32"||global.TESTING_WINDOWS?Km=XB():Km=zB();VB.exports=E0;E0.sync=epe;function E0(n,e,t){if(typeof e=="function"&&(t=e,e={}),!t){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(i,r){E0(n,e||{},function(o,s){o?r(o):i(s)})})}Km(n,e||{},function(i,r){i&&(i.code==="EACCES"||e&&e.ignoreErrors)&&(i=null,r=!1),t(i,r)})}function epe(n,e){try{return Km.sync(n,e||{})}catch(t){if(e&&e.ignoreErrors||t.code==="EACCES")return!1;throw t}}});var rg=m((F_e,sH)=>{var oc=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",tH=require("path"),tpe=oc?";":":",iH=eH(),nH=n=>Object.assign(new Error(`not found: ${n}`),{code:"ENOENT"}),rH=(n,e)=>{let t=e.colon||tpe,i=n.match(/\//)||oc&&n.match(/\\/)?[""]:[...oc?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(t)],r=oc?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",o=oc?r.split(t):[""];return oc&&n.indexOf(".")!==-1&&o[0]!==""&&o.unshift(""),{pathEnv:i,pathExt:o,pathExtExe:r}},oH=(n,e,t)=>{typeof e=="function"&&(t=e,e={}),e||(e={});let{pathEnv:i,pathExt:r,pathExtExe:o}=rH(n,e),s=[],a=u=>new Promise((c,h)=>{if(u===i.length)return e.all&&s.length?c(s):h(nH(n));let d=i[u],g=/^".*"$/.test(d)?d.slice(1,-1):d,f=tH.join(g,n),p=!g&&/^\.[\\\/]/.test(n)?n.slice(0,2)+f:f;c(l(p,u,0))}),l=(u,c,h)=>new Promise((d,g)=>{if(h===r.length)return d(a(c+1));let f=r[h];iH(u+f,{pathExt:o},(p,b)=>{if(!p&&b)if(e.all)s.push(u+f);else return d(u+f);return d(l(u,c,h+1))})});return t?a(0).then(u=>t(null,u),t):a(0)},ipe=(n,e)=>{e=e||{};let{pathEnv:t,pathExt:i,pathExtExe:r}=rH(n,e),o=[];for(let s=0;shpe,OperatingSystem:()=>lH,Platform:()=>aH,globals:()=>cpe,isLinux:()=>ope,isMacintosh:()=>sc,isNative:()=>spe,isWeb:()=>ape,isWindows:()=>Xi,language:()=>rpe,platform:()=>lpe});var Vm,eb,P0,_0,npe,rpe,aH,zm,Xi,sc,ope,spe,ape,lpe,upe,cpe,lH,hpe,ac=_(()=>{"use strict";Vm=!1,eb=!1,P0=!1,_0=!1,npe=!1,rpe="en";typeof process=="object"&&typeof process.nextTick=="function"&&typeof process.platform=="string"&&(Vm=process.platform==="win32",eb=process.platform==="darwin",P0=process.platform==="linux",_0=!0);aH=(r=>(r[r.Web=0]="Web",r[r.Mac=1]="Mac",r[r.Linux=2]="Linux",r[r.Windows=3]="Windows",r))(aH||{}),zm=0;_0&&(eb?zm=1:Vm?zm=3:P0&&(zm=2));Xi=Vm,sc=eb,ope=P0,spe=_0,ape=npe,lpe=zm,upe=typeof self=="object"?self:typeof global=="object"?global:{},cpe=upe,lH=(i=>(i[i.Windows=1]="Windows",i[i.Macintosh=2]="Macintosh",i[i.Linux=3]="Linux",i))(lH||{}),hpe=eb?2:Vm?1:3});function og(n){return!!(pl.MarkupContent.is(n)&&n.kind==pl.MarkupKind.Markdown)}function bt(n){return n<=0?Promise.resolve(void 0):new Promise(e=>{setTimeout(()=>{e(void 0)},n)})}function fH(n){return new Promise(e=>{process.nextTick(()=>{n&&n(),e(void 0)})})}function zr(){return new Promise(n=>{setImmediate(()=>{n(void 0)})})}function tb(n,e,t,i){return n?(Xi&&!i&&!n.startsWith("jdt://")&&(n=R0.default.win32.normalize(n)),R0.default.isAbsolute(n)?O.file(n).toString():dH.default.isValid(n)?O.parse(n).toString():t!=""?`${t}:${e}`:`unknown:${e}`):`untitled:${e}`}function Z(n){for(;n.length;){let e=n.pop();e&&e.dispose()}}function sg(n){try{gH.default.sync(n)}catch{return!1}return!0}function Vr(n,e={},t){return Xi||(e.shell=e.shell||process.env.SHELL),e.maxBuffer=500*1024,new Promise((i,r)=>{let o;t&&(o=setTimeout(()=>{r(new Error(`timeout after ${t}s`))},t*1e3)),(0,uH.exec)(n,e,(s,a,l)=>{if(o&&clearTimeout(o),s){r(new Error(`exited with ${s.code} -${s} -${l}`));return}i(a)})})}function lc(n,e){let t=(0,cH.default)(e,100);try{let i=hH.default.watch(n,{persistent:!0,recursive:!1,encoding:"utf8"},()=>{t()});return pl.Disposable.create(()=>{t.clear(),i.close()})}catch{return pl.Disposable.create(()=>{t.clear()})}}function pH(n){try{return process.kill(n,0)==!0}catch(e){return e.code==="EPERM"}}function L0(n){return n=="n"||n=="o"||n=="x"||n=="v"?"":n=="i"?"":n=="s"?"":""}function ag(n,e,t=3){if(n.length==0)return Promise.resolve();let i=0,r=n.length,o=n.slice();return new Promise(s=>{let a=l=>{let u=()=>{if(i=i+1,i==r)s();else if(o.length){let c=o.shift();a(c)}};e(l).then(u,u)};for(let l=0;l{"use strict";uH=require("child_process"),cH=C(Ei()),hH=C(require("fs")),dH=C(T0()),R0=C(require("path")),pl=C(H());we();gH=C(rg());ac();A_e=q()("util-index"),Er="coc-settings.json"});function uc(n){return n&&typeof n.word=="string"&&n.user_data!==""}function Kn(n){return typeof n=="boolean"}function Ee(n){return typeof n=="string"}function ib(n){return typeof n=="number"}function Qs(n){return typeof n=="function"}function _t(n){return n!=null&&typeof n=="object"&&!Array.isArray(n)&&!(n instanceof RegExp)&&!(n instanceof Date)}function mH(n){if(!_t(n))return!1;for(let e in n)if(dpe.call(n,e))return!1;return!0}function F0(n,e){return Array.isArray(n)&&n.every(e)}var dpe,In=_(()=>{"use strict";dpe=Object.prototype.hasOwnProperty});function Pr(n){if(!n||typeof n!="object"||n instanceof RegExp)return n;let e=Array.isArray(n)?[]:{};return Object.keys(n).forEach(t=>{n[t]&&typeof n[t]=="object"?e[t]=Pr(n[t]):e[t]=n[t]}),e}function bH(n){if(!n||typeof n!="object")return n;let e=[n];for(;e.length>0;){let t=e.shift();Object.freeze(t);for(let i in t)if(gpe.call(t,i)){let r=t[i];typeof r=="object"&&!Object.isFrozen(r)&&e.push(r)}}return n}function I0(n,e,t=!0){return _t(n)?(_t(e)&&Object.keys(e).forEach(i=>{i in n?t&&(_t(n[i])&&_t(e[i])?I0(n[i],e[i],t):n[i]=e[i]):n[i]=e[i]}),n):e}function Fe(n,e){if(n===e)return!0;if(n==null||e===null||e===void 0||typeof n!=typeof e||typeof n!="object"||Array.isArray(n)!==Array.isArray(e))return!1;let t,i;if(Array.isArray(n)){if(n.length!==e.length)return!1;for(t=0;t{"use strict";In();gpe=Object.prototype.hasOwnProperty});function yH(n){return n>=97&&n<=122?1:n>=65&&n<=90?2:0}function vH(n,e){let t=e==0?0:yH(n[e-1]);for(let i=e;i0&&r!=t)return[i,n[i]];t=r}}function wH(n,e){let t=[];for(let i=0;i0?n[0].toUpperCase()+n.slice(1):""}function Ze(n,e){let t=n.slice(0,e);return Buffer.byteLength(t)}function Ui(n,e){return Buffer.from(n,"utf8").slice(0,e).toString("utf8").length}function et(n,e,t){return Buffer.from(n,"utf8").slice(e,t).toString("utf8")}function hc(n){let e=n.charCodeAt(0);return e>128?!1:!!(e==95||e>=48&&e<=57||j0(e))}function j0(n){return n>=65&&n<=90||n>=97&&n<=122}function DH(n,e){return e&&n.endsWith(` -`)?n.slice(0,-1).split(` -`):n.split(` -`)}var Pe=_(()=>{"use strict"});var dc,fpe,xH,E,le=_(()=>{"use strict";dc=C(H());z();Jt();Pe();fpe=q()("events"),xH=class{constructor(){this.handlers=new Map;this._recentInserts=[];this._lastChange=0;this._insertMode=!1;this._pumAlignTop=!1;this._pumVisible=!1;this.completing=!1}get cursor(){return this._cursor}get bufnr(){return this._bufnr}get pumvisible(){return this._pumVisible}get pumAlignTop(){return this._pumAlignTop}get insertMode(){return this._insertMode}get lastChangeTs(){return this._lastChange}race(e,t){let i=[];return new Promise(r=>{if(typeof t=="number"){let o=setTimeout(()=>{Z(i),r(void 0)},t);i.push(dc.Disposable.create(()=>{clearTimeout(o)}))}else dc.CancellationToken.is(t)&&t.onCancellationRequested(()=>{Z(i),r(void 0)},null,i);e.forEach(o=>{this.on(o,(...s)=>{Z(i),r({name:o,args:s})},null,i)})})}async fire(e,t){var r,o;let i=this.handlers.get(e);if(e=="InsertEnter")this._insertMode=!0;else if(e=="InsertLeave")this._insertMode=!1,this._pumVisible=!1,this._recentInserts=[];else if(e=="CursorHoldI"||e=="CursorMovedI")this._bufnr=t[0],this._insertMode||(this._insertMode=!0,this.fire("InsertEnter",[t[0]]));else if(e=="CursorHold"||e=="CursorMoved")this._bufnr=t[0],this._insertMode&&(this._insertMode=!1,this.fire("InsertLeave",[t[0]]));else if(e=="MenuPopupChanged")this._pumVisible=!0,this._pumAlignTop=t[1]>t[0].row;else if(e=="CompleteDone")this._pumVisible=!1;else if(e=="InsertCharPre")this._recentInserts.push([t[1],t[0]]);else if(e=="TextChanged")this._lastChange=Date.now();else if(e=="BufEnter")this._bufnr=t[0];else if(e=="TextChangedI"||e=="TextChangedP"){let s=this._recentInserts.filter(u=>u[0]==t[0]);this._bufnr=t[0],this._recentInserts=[],this._pumVisible=e=="TextChangedP",this._lastChange=Date.now();let a=t[1],l=et((r=a.line)!=null?r:"",0,a.col-1);if(a.pre=l,this._cursor=Object.freeze({bufnr:t[0],lnum:a.lnum,col:a.col,insert:!0}),s.length&&l.length){let u=l.slice(-1);s.findIndex(c=>c[1]==u)!==-1&&(a.insertChar=u,process.nextTick(()=>{this.fire("TextInsert",[...t,u])}))}}if(e=="CursorMoved"||e=="CursorMovedI"){t.push(this._recentInserts.length>0);let s={bufnr:t[0],lnum:t[1][0],col:t[1][1],insert:e=="CursorMovedI"};if(this._cursor&&Fe(this._cursor,s))return;this._cursor=Object.freeze(s)}if(i)try{t.forEach(s=>{typeof s=="object"&&Object.freeze(s)}),await Promise.all(i.slice().map(s=>s(t)))}catch(s){if(s instanceof Error&&((o=s.message)==null?void 0:o.includes("transport disconnected")))return;fpe.error(`Error on event: ${e}`,s instanceof Error?s.stack:s)}}on(e,t,i,r){if(Array.isArray(e)){let o=r||[];for(let s of e)this.on(s,t,i,o);return dc.Disposable.create(()=>{Z(o)})}else{let o=this.handlers.get(e)||[],s=l=>new Promise((u,c)=>{try{Promise.resolve(t.apply(i!=null?i:null,l)).then(()=>{u(void 0)},h=>{c(h)})}catch(h){c(h)}});o.push(s),this.handlers.set(e,o);let a=dc.Disposable.create(()=>{let l=o.indexOf(s);l!==-1&&o.splice(l,1)});return Array.isArray(r)&&r.push(a),a}}},E=new xH});function _H(){return{baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}function ppe(n){gc=n}function ui(n,e){if(e){if(mpe.test(n))return n.replace(bpe,CH)}else if(ype.test(n))return n.replace(vpe,CH);return n}function RH(n){return n.replace(Dpe,(e,t)=>(t=t.toLowerCase(),t==="colon"?":":t.charAt(0)==="#"?t.charAt(1)==="x"?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}function lt(n,e){n=n.source||n,e=e||"";let t={replace:(i,r)=>(r=r.source||r,r=r.replace(xpe,"$1"),n=n.replace(i,r),t),getRegex:()=>new RegExp(n,e)};return t}function SH(n,e,t){if(n){let i;try{i=decodeURIComponent(RH(t)).replace(Cpe,"").toLowerCase()}catch{return null}if(i.indexOf("javascript:")===0||i.indexOf("vbscript:")===0||i.indexOf("data:")===0)return null}e&&!Spe.test(t)&&(t=Ppe(e,t));try{t=encodeURI(t).replace(/%25/g,"%")}catch{return null}return t}function Ppe(n,e){nb[" "+n]||(Tpe.test(n)?nb[" "+n]=n+"/":nb[" "+n]=rb(n,"/",!0)),n=nb[" "+n];let t=n.indexOf(":")===-1;return e.substring(0,2)==="//"?t?e:n.replace(kpe,"$1")+e:e.charAt(0)==="/"?t?e:n.replace(Epe,"$1")+e:n+e}function _r(n){let e=1,t,i;for(;e{let l=!1,u=s;for(;--u>=0&&a[u]==="\\";)l=!l;return l?"|":" |"}),i=t.split(/ \|/),r=0;if(i[0].trim()||i.shift(),i.length>0&&!i[i.length-1].trim()&&i.pop(),i.length>e)i.splice(e);else for(;i.length1;)e&1&&(t+=n),e>>=1,n+=n;return t+n}function EH(n,e,t,i){let r=e.href,o=e.title?ui(e.title):null,s=n[1].replace(/\\([\[\]])/g,"$1");if(n[0].charAt(0)!=="!"){i.state.inLink=!0;let a={type:"link",raw:t,href:r,title:o,text:s,tokens:i.inlineTokens(s,[])};return i.state.inLink=!1,a}else return{type:"image",raw:t,href:r,title:o,text:ui(s)}}function Rpe(n,e){let t=n.match(/^(\s+)(?:```)/);if(t===null)return e;let i=t[1];return e.split(` -`).map(r=>{let o=r.match(/^\s+/);if(o===null)return r;let[s]=o;return s.length>=i.length?r.slice(i.length):r}).join(` -`)}function Lpe(n){return n.replace(/---/g,"\u2014").replace(/--/g,"\u2013").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1\u2018").replace(/'/g,"\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1\u201C").replace(/"/g,"\u201D").replace(/\.{3}/g,"\u2026")}function PH(n){let e="",t,i,r=n.length;for(t=0;t.5&&(i="x"+i.toString(16)),e+="&#"+i+";";return e}function fe(n,e,t){if(typeof n>"u"||n===null)throw new Error("marked(): input parameter is undefined or null");if(typeof n!="string")throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected");if(typeof e=="function"&&(t=e,e=null),e=_r({},fe.defaults,e||{}),LH(e),t){let i=e.highlight,r;try{r=eo.lex(n,e)}catch(a){return t(a)}let o=function(a){let l;if(!a)try{e.walkTokens&&fe.walkTokens(r,e.walkTokens),l=to.parse(r,e)}catch(u){a=u}return e.highlight=i,a?t(a):t(null,l)};if(!i||i.length<3||(delete e.highlight,!r.length))return o();let s=0;fe.walkTokens(r,function(a){a.type==="code"&&(s++,setTimeout(()=>{i(a.text,a.lang,function(l,u){if(l)return o(l);u!=null&&u!==a.text&&(a.text=u,a.escaped=!0),s--,s===0&&o()})},0))}),s===0&&o();return}try{let i=eo.lex(n,e);return e.walkTokens&&fe.walkTokens(i,e.walkTokens),to.parse(i,e)}catch(i){if(i.message+=` -Please report this to https://github.com/markedjs/marked.`,e.silent)return"

An error occurred:

"+ui(i.message+"",!0)+"
";throw i}}var gc,mpe,bpe,ype,vpe,wpe,CH,Dpe,xpe,Cpe,Spe,nb,Tpe,kpe,Epe,ob,sb,he,ee,eo,ab,A0,O0,to,W_e,Z_e,J_e,$_e,X_e,U_e,G_e,FH=_(()=>{gc=_H();mpe=/[&<>"']/,bpe=/[&<>"']/g,ype=/[<>"']|&(?!#?\w+;)/,vpe=/[<>"']|&(?!#?\w+;)/g,wpe={"&":"&","<":"<",">":">",'"':""","'":"'"},CH=n=>wpe[n];Dpe=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;xpe=/(^|[^\[])\^/g;Cpe=/[^\w:]/g,Spe=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;nb={},Tpe=/^[^:]+:\/*[^/]*$/,kpe=/^([^:]+:)[\s\S]*$/,Epe=/^([^:]+:\/*[^/]*)[\s\S]*$/;ob={exec:function(){}};sb=class{constructor(e){this.options=e||gc}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let i=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?i:rb(i,` -`)}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let i=t[0],r=Rpe(i,t[3]||"");return{type:"code",raw:i,lang:t[2]?t[2].trim():t[2],text:r}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let i=t[2].trim();if(/#$/.test(i)){let o=rb(i,"#");(this.options.pedantic||!o||/ $/.test(o))&&(i=o.trim())}let r={type:"heading",raw:t[0],depth:t[1].length,text:i,tokens:[]};return this.lexer.inline(r.text,r.tokens),r}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let i=t[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:t[0],tokens:this.lexer.blockTokens(i,[]),text:i}}}list(e){let t=this.rules.block.list.exec(e);if(t){let i,r,o,s,a,l,u,c,h,d,g,f,p=t[1].trim(),b=p.length>1,v={type:"list",raw:"",ordered:b,start:b?+p.slice(0,-1):"",loose:!1,items:[]};p=b?`\\d{1,9}\\${p.slice(-1)}`:`\\${p}`,this.options.pedantic&&(p=b?p:"[*+-]");let w=new RegExp(`^( {0,3}${p})((?: [^\\n]*)?(?:\\n|$))`);for(;e&&(f=!1,!(!(t=w.exec(e))||this.rules.block.hr.test(e)));){if(i=t[0],e=e.substring(i.length),c=t[2].split(` -`,1)[0],h=e.split(` -`,1)[0],this.options.pedantic?(s=2,g=c.trimLeft()):(s=t[2].search(/[^ ]/),s=s>4?1:s,g=c.slice(s),s+=t[1].length),l=!1,!c&&/^ *$/.test(h)&&(i+=h+` -`,e=e.substring(h.length+1),f=!0),!f){let S=new RegExp(`^ {0,${Math.min(3,s-1)}}(?:[*+-]|\\d{1,9}[.)])`);for(;e&&(d=e.split(` -`,1)[0],c=d,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),!S.test(c));){if(c.search(/[^ ]/)>=s||!c.trim())g+=` -`+c.slice(s);else if(!l)g+=` -`+c;else break;!l&&!c.trim()&&(l=!0),i+=d+` -`,e=e.substring(d.length+1)}}v.loose||(u?v.loose=!0:/\n *\n *$/.test(i)&&(u=!0)),this.options.gfm&&(r=/^\[[ xX]\] /.exec(g),r&&(o=r[0]!=="[ ] ",g=g.replace(/^\[[ xX]\] +/,""))),v.items.push({type:"list_item",raw:i,task:!!r,checked:o,loose:!1,text:g}),v.raw+=i}v.items[v.items.length-1].raw=i.trimRight(),v.items[v.items.length-1].text=g.trimRight(),v.raw=v.raw.trimRight();let D=v.items.length;for(a=0;aL.type==="space"),F=S.every(L=>{let j=L.raw.split(""),W=0;for(let B of j)if(B===` -`&&(W+=1),W>1)return!0;return!1});!v.loose&&S.length&&F&&(v.loose=!0,v.items[a].loose=!0)}return v}}html(e){let t=this.rules.block.html.exec(e);if(t){let i={type:"html",raw:t[0],pre:!this.options.sanitizer&&(t[1]==="pre"||t[1]==="script"||t[1]==="style"),text:t[0]};return this.options.sanitize&&(i.type="paragraph",i.text=this.options.sanitizer?this.options.sanitizer(t[0]):ui(t[0]),i.tokens=[],this.lexer.inline(i.text,i.tokens)),i}}def(e){let t=this.rules.block.def.exec(e);if(t){t[3]&&(t[3]=t[3].substring(1,t[3].length-1));let i=t[1].toLowerCase().replace(/\s+/g," ");return{type:"def",tag:i,raw:t[0],href:t[2],title:t[3]}}}table(e){let t=this.rules.block.table.exec(e);if(t){let i={type:"table",header:TH(t[1]).map(r=>({text:r})),align:t[2].replace(/^ *|\| *$/g,"").split(/ *\| */),rows:t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split(` -`):[]};if(i.header.length===i.align.length){i.raw=t[0];let r=i.align.length,o,s,a,l;for(o=0;o({text:u}));for(r=i.header.length,s=0;s/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):ui(t[0]):t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let i=t[2].trim();if(!this.options.pedantic&&/^$/.test(i))return;let s=rb(i.slice(0,-1),"\\");if((i.length-s.length)%2===0)return}else{let s=_pe(t[2],"()");if(s>-1){let l=(t[0].indexOf("!")===0?5:4)+t[1].length+s;t[2]=t[2].substring(0,s),t[0]=t[0].substring(0,l).trim(),t[3]=""}}let r=t[2],o="";if(this.options.pedantic){let s=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r);s&&(r=s[1],o=s[3])}else o=t[3]?t[3].slice(1,-1):"";return r=r.trim(),/^$/.test(i)?r=r.slice(1):r=r.slice(1,-1)),EH(t,{href:r&&r.replace(this.rules.inline._escapes,"$1"),title:o&&o.replace(this.rules.inline._escapes,"$1")},t[0],this.lexer)}}reflink(e,t){let i;if((i=this.rules.inline.reflink.exec(e))||(i=this.rules.inline.nolink.exec(e))){let r=(i[2]||i[1]).replace(/\s+/g," ");if(r=t[r.toLowerCase()],!r||!r.href){let o=i[0].charAt(0);return{type:"text",raw:o,text:o}}return EH(i,r,i[0],this.lexer)}}emStrong(e,t,i=""){let r=this.rules.inline.emStrong.lDelim.exec(e);if(!r||r[3]&&i.match(/[\p{L}\p{N}]/u))return;let o=r[1]||r[2]||"";if(!o||o&&(i===""||this.rules.inline.punctuation.exec(i))){let s=r[0].length-1,a,l,u=s,c=0,h=r[0][0]==="*"?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(h.lastIndex=0,t=t.slice(-1*e.length+s);(r=h.exec(t))!=null;){if(a=r[1]||r[2]||r[3]||r[4]||r[5]||r[6],!a)continue;if(l=a.length,r[3]||r[4]){u+=l;continue}else if((r[5]||r[6])&&s%3&&!((s+l)%3)){c+=l;continue}if(u-=l,u>0)continue;if(l=Math.min(l,l+u+c),Math.min(s,l)%2){let g=e.slice(1,s+r.index+l);return{type:"em",raw:e.slice(0,s+r.index+l+1),text:g,tokens:this.lexer.inlineTokens(g,[])}}let d=e.slice(2,s+r.index+l-1);return{type:"strong",raw:e.slice(0,s+r.index+l+1),text:d,tokens:this.lexer.inlineTokens(d,[])}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let i=t[2].replace(/\n/g," "),r=/[^ ]/.test(i),o=/^ /.test(i)&&/ $/.test(i);return r&&o&&(i=i.substring(1,i.length-1)),i=ui(i,!0),{type:"codespan",raw:t[0],text:i}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){let t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2],[])}}autolink(e,t){let i=this.rules.inline.autolink.exec(e);if(i){let r,o;return i[2]==="@"?(r=ui(this.options.mangle?t(i[1]):i[1]),o="mailto:"+r):(r=ui(i[1]),o=r),{type:"link",raw:i[0],text:r,href:o,tokens:[{type:"text",raw:r,text:r}]}}}url(e,t){let i;if(i=this.rules.inline.url.exec(e)){let r,o;if(i[2]==="@")r=ui(this.options.mangle?t(i[0]):i[0]),o="mailto:"+r;else{let s;do s=i[0],i[0]=this.rules.inline._backpedal.exec(i[0])[0];while(s!==i[0]);r=ui(i[0]),i[1]==="www."?o="http://"+r:o=r}return{type:"link",raw:i[0],text:r,href:o,tokens:[{type:"text",raw:r,text:r}]}}}inlineText(e,t){let i=this.rules.inline.text.exec(e);if(i){let r;return this.lexer.state.inRawBlock?r=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):ui(i[0]):i[0]:r=ui(this.options.smartypants?t(i[0]):i[0]),{type:"text",raw:i[0],text:r}}}},he={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3}bull)( [^\n]+?)?(?:\n|$)/,html:"^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *(?:\n *)?]+)>?(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,table:ob,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,text:/^[^\n]+/};he._label=/(?!\s*\])(?:\\.|[^\[\]\\])+/;he._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;he.def=lt(he.def).replace("label",he._label).replace("title",he._title).getRegex();he.bullet=/(?:[*+-]|\d{1,9}[.)])/;he.listItemStart=lt(/^( *)(bull) */).replace("bull",he.bullet).getRegex();he.list=lt(he.list).replace(/bull/g,he.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+he.def.source+")").getRegex();he._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";he._comment=/|$)/;he.html=lt(he.html,"i").replace("comment",he._comment).replace("tag",he._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();he.paragraph=lt(he._paragraph).replace("hr",he.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",he._tag).getRegex();he.blockquote=lt(he.blockquote).replace("paragraph",he.paragraph).getRegex();he.normal=_r({},he);he.gfm=_r({},he.normal,{table:"^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"});he.gfm.table=lt(he.gfm.table).replace("hr",he.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",he._tag).getRegex();he.gfm.paragraph=lt(he._paragraph).replace("hr",he.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("table",he.gfm.table).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",he._tag).getRegex();he.pedantic=_r({},he.normal,{html:lt(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",he._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:ob,paragraph:lt(he.normal._paragraph).replace("hr",he.hr).replace("heading",` *#{1,6} *[^ -]`).replace("lheading",he.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});ee={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:ob,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(ref)\]/,nolink:/^!?\[(ref)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,rDelimUnd:/^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:ob,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~";ee.punctuation=lt(ee.punctuation).replace(/punctuation/g,ee._punctuation).getRegex();ee.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;ee.escapedEmSt=/\\\*|\\_/g;ee._comment=lt(he._comment).replace("(?:-->|$)","-->").getRegex();ee.emStrong.lDelim=lt(ee.emStrong.lDelim).replace(/punct/g,ee._punctuation).getRegex();ee.emStrong.rDelimAst=lt(ee.emStrong.rDelimAst,"g").replace(/punct/g,ee._punctuation).getRegex();ee.emStrong.rDelimUnd=lt(ee.emStrong.rDelimUnd,"g").replace(/punct/g,ee._punctuation).getRegex();ee._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;ee._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;ee._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;ee.autolink=lt(ee.autolink).replace("scheme",ee._scheme).replace("email",ee._email).getRegex();ee._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;ee.tag=lt(ee.tag).replace("comment",ee._comment).replace("attribute",ee._attribute).getRegex();ee._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;ee._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;ee._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;ee.link=lt(ee.link).replace("label",ee._label).replace("href",ee._href).replace("title",ee._title).getRegex();ee.reflink=lt(ee.reflink).replace("label",ee._label).replace("ref",he._label).getRegex();ee.nolink=lt(ee.nolink).replace("ref",he._label).getRegex();ee.reflinkSearch=lt(ee.reflinkSearch,"g").replace("reflink",ee.reflink).replace("nolink",ee.nolink).getRegex();ee.normal=_r({},ee);ee.pedantic=_r({},ee.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:lt(/^!?\[(label)\]\((.*?)\)/).replace("label",ee._label).getRegex(),reflink:lt(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",ee._label).getRegex()});ee.gfm=_r({},ee.normal,{escape:lt(ee.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\(i=a.call({lexer:this},e,t))?(e=e.substring(i.raw.length),t.push(i),!0):!1))){if(i=this.tokenizer.space(e)){e=e.substring(i.raw.length),i.raw.length===1&&t.length>0?t[t.length-1].raw+=` -`:t.push(i);continue}if(i=this.tokenizer.code(e)){e=e.substring(i.raw.length),r=t[t.length-1],r&&(r.type==="paragraph"||r.type==="text")?(r.raw+=` -`+i.raw,r.text+=` -`+i.text,this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(i);continue}if(i=this.tokenizer.fences(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.heading(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.hr(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.blockquote(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.list(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.html(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.def(e)){e=e.substring(i.raw.length),r=t[t.length-1],r&&(r.type==="paragraph"||r.type==="text")?(r.raw+=` -`+i.raw,r.text+=` -`+i.raw,this.inlineQueue[this.inlineQueue.length-1].src=r.text):this.tokens.links[i.tag]||(this.tokens.links[i.tag]={href:i.href,title:i.title});continue}if(i=this.tokenizer.table(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.lheading(e)){e=e.substring(i.raw.length),t.push(i);continue}if(o=e,this.options.extensions&&this.options.extensions.startBlock){let a=1/0,l=e.slice(1),u;this.options.extensions.startBlock.forEach(function(c){u=c.call({lexer:this},l),typeof u=="number"&&u>=0&&(a=Math.min(a,u))}),a<1/0&&a>=0&&(o=e.substring(0,a+1))}if(this.state.top&&(i=this.tokenizer.paragraph(o))){r=t[t.length-1],s&&r.type==="paragraph"?(r.raw+=` -`+i.raw,r.text+=` -`+i.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(i),s=o.length!==e.length,e=e.substring(i.raw.length);continue}if(i=this.tokenizer.text(e)){e=e.substring(i.raw.length),r=t[t.length-1],r&&r.type==="text"?(r.raw+=` -`+i.raw,r.text+=` -`+i.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(i);continue}if(e){let a="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(a);break}else throw new Error(a)}}return this.state.top=!0,t}inline(e,t){this.inlineQueue.push({src:e,tokens:t})}inlineTokens(e,t=[]){let i,r,o,s=e,a,l,u;if(this.tokens.links){let c=Object.keys(this.tokens.links);if(c.length>0)for(;(a=this.tokenizer.rules.inline.reflinkSearch.exec(s))!=null;)c.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(s=s.slice(0,a.index)+"["+kH("a",a[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(a=this.tokenizer.rules.inline.blockSkip.exec(s))!=null;)s=s.slice(0,a.index)+"["+kH("a",a[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;(a=this.tokenizer.rules.inline.escapedEmSt.exec(s))!=null;)s=s.slice(0,a.index)+"++"+s.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);for(;e;)if(l||(u=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some(c=>(i=c.call({lexer:this},e,t))?(e=e.substring(i.raw.length),t.push(i),!0):!1))){if(i=this.tokenizer.escape(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.tag(e)){e=e.substring(i.raw.length),r=t[t.length-1],r&&i.type==="text"&&r.type==="text"?(r.raw+=i.raw,r.text+=i.text):t.push(i);continue}if(i=this.tokenizer.link(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(i.raw.length),r=t[t.length-1],r&&i.type==="text"&&r.type==="text"?(r.raw+=i.raw,r.text+=i.text):t.push(i);continue}if(i=this.tokenizer.emStrong(e,s,u)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.codespan(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.br(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.del(e)){e=e.substring(i.raw.length),t.push(i);continue}if(i=this.tokenizer.autolink(e,PH)){e=e.substring(i.raw.length),t.push(i);continue}if(!this.state.inLink&&(i=this.tokenizer.url(e,PH))){e=e.substring(i.raw.length),t.push(i);continue}if(o=e,this.options.extensions&&this.options.extensions.startInline){let c=1/0,h=e.slice(1),d;this.options.extensions.startInline.forEach(function(g){d=g.call({lexer:this},h),typeof d=="number"&&d>=0&&(c=Math.min(c,d))}),c<1/0&&c>=0&&(o=e.substring(0,c+1))}if(i=this.tokenizer.inlineText(o,Lpe)){e=e.substring(i.raw.length),i.raw.slice(-1)!=="_"&&(u=i.raw.slice(-1)),l=!0,r=t[t.length-1],r&&r.type==="text"?(r.raw+=i.raw,r.text+=i.text):t.push(i);continue}if(e){let c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}else throw new Error(c)}}return t}},ab=class{constructor(e){this.options=e||gc}code(e,t,i){let r=(t||"").match(/\S*/)[0];if(this.options.highlight){let o=this.options.highlight(e,r);o!=null&&o!==e&&(i=!0,e=o)}return e=e.replace(/\n$/,"")+` -`,r?'
'+(i?e:ui(e,!0))+`
-`:"
"+(i?e:ui(e,!0))+`
-`}blockquote(e){return`
-`+e+`
-`}html(e){return e}heading(e,t,i,r){return this.options.headerIds?"'+e+" -`:""+e+" -`}hr(){return this.options.xhtml?`
-`:`
-`}list(e,t,i){let r=t?"ol":"ul",o=t&&i!==1?' start="'+i+'"':"";return"<"+r+o+`> -`+e+" -`}listitem(e){return"
  • "+e+`
  • -`}checkbox(e){return" "}paragraph(e){return"

    "+e+`

    -`}table(e,t){return t&&(t=""+t+""),` - -`+e+` -`+t+`
    -`}tablerow(e){return` -`+e+` -`}tablecell(e,t){let i=t.header?"th":"td";return(t.align?"<"+i+' align="'+t.align+'">':"<"+i+">")+e+" -`}strong(e){return""+e+""}em(e){return""+e+""}codespan(e){return""+e+""}br(){return this.options.xhtml?"
    ":"
    "}del(e){return""+e+""}link(e,t,i){if(e=SH(this.options.sanitize,this.options.baseUrl,e),e===null)return i;let r='",r}image(e,t,i){if(e=SH(this.options.sanitize,this.options.baseUrl,e),e===null)return i;let r=''+i+'":">",r}text(e){return e}},A0=class{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,i){return""+i}image(e,t,i){return""+i}br(){return""}},O0=class{constructor(){this.seen={}}serialize(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/ig,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")}getNextSafeSlug(e,t){let i=e,r=0;if(this.seen.hasOwnProperty(i)){r=this.seen[e];do r++,i=e+"-"+r;while(this.seen.hasOwnProperty(i))}return t||(this.seen[e]=r,this.seen[i]=0),i}slug(e,t={}){let i=this.serialize(e);return this.getNextSafeSlug(i,t.dryrun)}},to=class{constructor(e){this.options=e||gc,this.options.renderer=this.options.renderer||new ab,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new A0,this.slugger=new O0}static parse(e,t){return new to(t).parse(e)}static parseInline(e,t){return new to(t).parseInline(e)}parse(e,t=!0){let i="",r,o,s,a,l,u,c,h,d,g,f,p,b,v,w,D,S,F,L,j=e.length;for(r=0;r0&&w.tokens[0].type==="paragraph"?(w.tokens[0].text=F+" "+w.tokens[0].text,w.tokens[0].tokens&&w.tokens[0].tokens.length>0&&w.tokens[0].tokens[0].type==="text"&&(w.tokens[0].tokens[0].text=F+" "+w.tokens[0].tokens[0].text)):w.tokens.unshift({type:"text",text:F}):v+=F),v+=this.parse(w.tokens,b),d+=this.renderer.listitem(v,S,D);i+=this.renderer.list(d,f,p);continue}case"html":{i+=this.renderer.html(g.text);continue}case"paragraph":{i+=this.renderer.paragraph(this.parseInline(g.tokens));continue}case"text":{for(d=g.tokens?this.parseInline(g.tokens):g.text;r+1{if(r.extensions&&(i=!0,r.extensions.forEach(o=>{if(!o.name)throw new Error("extension name required");if(o.renderer){let s=t.renderers?t.renderers[o.name]:null;s?t.renderers[o.name]=function(...a){let l=o.renderer.apply(this,a);return l===!1&&(l=s.apply(this,a)),l}:t.renderers[o.name]=o.renderer}if(o.tokenizer){if(!o.level||o.level!=="block"&&o.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");t[o.level]?t[o.level].unshift(o.tokenizer):t[o.level]=[o.tokenizer],o.start&&(o.level==="block"?t.startBlock?t.startBlock.push(o.start):t.startBlock=[o.start]:o.level==="inline"&&(t.startInline?t.startInline.push(o.start):t.startInline=[o.start]))}o.childTokens&&(t.childTokens[o.name]=o.childTokens)})),r.renderer){let o=fe.defaults.renderer||new ab;for(let s in r.renderer){let a=o[s];o[s]=(...l)=>{let u=r.renderer[s].apply(o,l);return u===!1&&(u=a.apply(o,l)),u}}e.renderer=o}if(r.tokenizer){let o=fe.defaults.tokenizer||new sb;for(let s in r.tokenizer){let a=o[s];o[s]=(...l)=>{let u=r.tokenizer[s].apply(o,l);return u===!1&&(u=a.apply(o,l)),u}}e.tokenizer=o}if(r.walkTokens){let o=fe.defaults.walkTokens;e.walkTokens=function(s){r.walkTokens.call(this,s),o&&o.call(this,s)}}i&&(e.extensions=t),fe.setOptions(e)})};fe.walkTokens=function(n,e){for(let t of n)switch(e.call(fe,t),t.type){case"table":{for(let i of t.header)fe.walkTokens(i.tokens,e);for(let i of t.rows)for(let r of i)fe.walkTokens(r.tokens,e);break}case"list":{fe.walkTokens(t.items,e);break}default:fe.defaults.extensions&&fe.defaults.extensions.childTokens&&fe.defaults.extensions.childTokens[t.type]?fe.defaults.extensions.childTokens[t.type].forEach(function(i){fe.walkTokens(t[i],e)}):t.tokens&&fe.walkTokens(t.tokens,e)}};fe.parseInline=function(n,e){if(typeof n>"u"||n===null)throw new Error("marked.parseInline(): input parameter is undefined or null");if(typeof n!="string")throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected");e=_r({},fe.defaults,e||{}),LH(e);try{let t=eo.lexInline(n,e);return e.walkTokens&&fe.walkTokens(t,e.walkTokens),to.parseInline(t,e)}catch(t){if(t.message+=` -Please report this to https://github.com/markedjs/marked.`,e.silent)return"

    An error occurred:

    "+ui(t.message+"",!0)+"
    ";throw t}};fe.Parser=to;fe.parser=to.parse;fe.Renderer=ab;fe.TextRenderer=A0;fe.Lexer=eo;fe.lexer=eo.lex;fe.Tokenizer=sb;fe.Slugger=O0;fe.parse=fe;W_e=fe.options,Z_e=fe.setOptions,J_e=fe.use,$_e=fe.walkTokens,X_e=fe.parseInline,U_e=to.parse,G_e=eo.lex});var OH=m((K_e,AH)=>{var jH={};AH.exports=jH;var IH={reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29],black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39],grey:[90,39],bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],blackBG:[40,49],redBG:[41,49],greenBG:[42,49],yellowBG:[43,49],blueBG:[44,49],magentaBG:[45,49],cyanBG:[46,49],whiteBG:[47,49]};Object.keys(IH).forEach(function(n){var e=IH[n],t=jH[n]=[];t.open="\x1B["+e[0]+"m",t.close="\x1B["+e[1]+"m"})});var NH=m((z_e,MH)=>{var lg=process.argv;MH.exports=function(){return lg.indexOf("--no-color")!==-1||lg.indexOf("--color=false")!==-1?!1:lg.indexOf("--color")!==-1||lg.indexOf("--color=true")!==-1||lg.indexOf("--color=always")!==-1?!0:process.stdout&&!process.stdout.isTTY?!1:process.platform==="win32"||"COLORTERM"in process.env?!0:process.env.TERM==="dumb"?!1:!!/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)}()});var HH=m((V_e,BH)=>{BH.exports=function(e,t){var i="";e=e||"Run the trap, drop the bass",e=e.split("");var r={a:["@","\u0104","\u023A","\u0245","\u0394","\u039B","\u0414"],b:["\xDF","\u0181","\u0243","\u026E","\u03B2","\u0E3F"],c:["\xA9","\u023B","\u03FE"],d:["\xD0","\u018A","\u0500","\u0501","\u0502","\u0503"],e:["\xCB","\u0115","\u018E","\u0258","\u03A3","\u03BE","\u04BC","\u0A6C"],f:["\u04FA"],g:["\u0262"],h:["\u0126","\u0195","\u04A2","\u04BA","\u04C7","\u050A"],i:["\u0F0F"],j:["\u0134"],k:["\u0138","\u04A0","\u04C3","\u051E"],l:["\u0139"],m:["\u028D","\u04CD","\u04CE","\u0520","\u0521","\u0D69"],n:["\xD1","\u014B","\u019D","\u0376","\u03A0","\u048A"],o:["\xD8","\xF5","\xF8","\u01FE","\u0298","\u047A","\u05DD","\u06DD","\u0E4F"],p:["\u01F7","\u048E"],q:["\u09CD"],r:["\xAE","\u01A6","\u0210","\u024C","\u0280","\u042F"],s:["\xA7","\u03DE","\u03DF","\u03E8"],t:["\u0141","\u0166","\u0373"],u:["\u01B1","\u054D"],v:["\u05D8"],w:["\u0428","\u0460","\u047C","\u0D70"],x:["\u04B2","\u04FE","\u04FC","\u04FD"],y:["\xA5","\u04B0","\u04CB"],z:["\u01B5","\u0240"]};return e.forEach(function(o){o=o.toLowerCase();var s=r[o]||[" "],a=Math.floor(Math.random()*s.length);typeof r[o]<"u"?i+=r[o][a]:i+=o}),i}});var YH=m((eRe,qH)=>{qH.exports=function(e,t){e=e||" he is here ";var i={up:["\u030D","\u030E","\u0304","\u0305","\u033F","\u0311","\u0306","\u0310","\u0352","\u0357","\u0351","\u0307","\u0308","\u030A","\u0342","\u0313","\u0308","\u034A","\u034B","\u034C","\u0303","\u0302","\u030C","\u0350","\u0300","\u0301","\u030B","\u030F","\u0312","\u0313","\u0314","\u033D","\u0309","\u0363","\u0364","\u0365","\u0366","\u0367","\u0368","\u0369","\u036A","\u036B","\u036C","\u036D","\u036E","\u036F","\u033E","\u035B","\u0346","\u031A"],down:["\u0316","\u0317","\u0318","\u0319","\u031C","\u031D","\u031E","\u031F","\u0320","\u0324","\u0325","\u0326","\u0329","\u032A","\u032B","\u032C","\u032D","\u032E","\u032F","\u0330","\u0331","\u0332","\u0333","\u0339","\u033A","\u033B","\u033C","\u0345","\u0347","\u0348","\u0349","\u034D","\u034E","\u0353","\u0354","\u0355","\u0356","\u0359","\u035A","\u0323"],mid:["\u0315","\u031B","\u0300","\u0301","\u0358","\u0321","\u0322","\u0327","\u0328","\u0334","\u0335","\u0336","\u035C","\u035D","\u035E","\u035F","\u0360","\u0362","\u0338","\u0337","\u0361"," \u0489"]},r=[].concat(i.up,i.down,i.mid),o={};function s(u){var c=Math.floor(Math.random()*u);return c}function a(u){var c=!1;return r.filter(function(h){c=h===u}),c}function l(u,c){var h="",d,g;c=c||{},c.up=c.up||!0,c.mid=c.mid||!0,c.down=c.down||!0,c.size=c.size||"maxi",u=u.split("");for(g in u)if(!a(g)){switch(h=h+u[g],d={up:0,down:0,mid:0},c.size){case"mini":d.up=s(8),d.min=s(2),d.down=s(8);break;case"maxi":d.up=s(16)+3,d.min=s(4)+1,d.down=s(64)+3;break;default:d.up=s(8)+1,d.mid=s(6)/2,d.down=s(8)+1;break}var f=["up","mid","down"];for(var p in f)for(var b=f[p],v=0;v<=d[b];v++)c[b]&&(h=h+i[b][s(i[b].length)])}return h}return l(e)}});var ZH=m((tRe,WH)=>{var M0=fc();WH.exports=function(){return function(n,e,t){if(n===" ")return n;switch(e%3){case 0:return M0.red(n);case 1:return M0.white(n);case 2:return M0.blue(n)}}}()});var $H=m((iRe,JH)=>{var Fpe=fc();JH.exports=function(n,e,t){return e%2===0?n:Fpe.inverse(n)}});var UH=m((nRe,XH)=>{var Ipe=fc();XH.exports=function(){var n=["red","yellow","green","blue","magenta"];return function(e,t,i){return e===" "?e:Ipe[n[t++%n.length]](e)}}()});var QH=m((rRe,GH)=>{var jpe=fc();GH.exports=function(){var n=["underline","inverse","grey","yellow","red","green","blue","white","cyan","magenta"];return function(e,t,i){return e===" "?e:jpe[n[Math.round(Math.random()*(n.length-1))]](e)}}()});var fc=m((sRe,iq)=>{var tt={};iq.exports=tt;tt.themes={};var Ks=tt.styles=OH(),VH=Object.defineProperties;tt.supportsColor=NH();typeof tt.enabled>"u"&&(tt.enabled=tt.supportsColor);tt.stripColors=tt.strip=function(n){return(""+n).replace(/\x1B\[\d+m/g,"")};var oRe=tt.stylize=function(e,t){return Ks[t].open+e+Ks[t].close},Ape=/[|\\{}()[\]^$+*?.]/g,Ope=function(n){if(typeof n!="string")throw new TypeError("Expected a string");return n.replace(Ape,"\\$&")};function eq(n){var e=function t(){return Npe.apply(t,arguments)};return e._styles=n,e.__proto__=Mpe,e}var tq=function(){var n={};return Ks.grey=Ks.gray,Object.keys(Ks).forEach(function(e){Ks[e].closeRe=new RegExp(Ope(Ks[e].close),"g"),n[e]={get:function(){return eq(this._styles.concat(e))}}}),n}(),Mpe=VH(function(){},tq);function Npe(){var n=arguments,e=n.length,t=e!==0&&String(arguments[0]);if(e>1)for(var i=1;i{var qpe=fc();nq.exports=qpe});var sq=m(pc=>{pc.repeat=function(n,e){return Array(e+1).join(n)};pc.pad=function(n,e,t,i){if(e+1>=n.length)switch(i){case"left":n=Array(e+1-n.length).join(t)+n;break;case"both":var r=Math.ceil((padlen=e-n.length)/2),o=padlen-r;n=Array(o+1).join(t)+n+Array(r+1).join(t);break;default:n=n+Array(e+1-n.length).join(t)}return n};pc.truncate=function(n,e,t){return t=t||"\u2026",n.length>=e?n.substr(0,e-t.length)+t:n};function oq(n,e){for(var t in e)t==="__proto__"||t==="constructor"||t==="prototype"||(e[t]&&e[t].constructor&&e[t].constructor===Object?(n[t]=n[t]||{},oq(n[t],e[t])):n[t]=e[t]);return n}pc.options=oq;pc.strlen=function(n){var e=/\u001b\[(?:\d*;){0,5}\d*m/g,t=(""+n).replace(e,""),i=t.split(` -`);return i.reduce(function(r,o){return o.length>r?o.length:r},0)}});var aq=m((uRe,B0)=>{var Ype=rq(),ml=sq(),N0=ml.repeat,Wpe=ml.truncate,Zpe=ml.pad;function ug(n){this.options=ml.options({chars:{top:"\u2500","top-mid":"\u252C","top-left":"\u250C","top-right":"\u2510",bottom:"\u2500","bottom-mid":"\u2534","bottom-left":"\u2514","bottom-right":"\u2518",left:"\u2502","left-mid":"\u251C",mid:"\u2500","mid-mid":"\u253C",right:"\u2502","right-mid":"\u2524",middle:"\u2502"},truncate:"\u2026",colWidths:[],colAligns:[],style:{"padding-left":1,"padding-right":1,head:["red"],border:["grey"],compact:!1},head:[]},n)}ug.prototype.__proto__=Array.prototype;ug.prototype.__defineGetter__("width",function(){var n=this.toString().split(` -`);return n.length?n[0].length:0});ug.prototype.render;ug.prototype.toString=function(){var n="",e=this.options,t=e.style,i=e.head,r=e.chars,o=e.truncate,s=e.colWidths||new Array(this.head.length),a=0;if(!i.length&&!this.length)return"";if(!s.length){var l=this.slice(0);i.length&&(l=l.concat([i])),l.forEach(function(v){if(typeof v=="object"&&v.length)u(v);else{var w=Object.keys(v)[0],D=v[w];s[0]=Math.max(s[0]||0,c(w)||0),typeof D=="object"&&D.length?u(D,1):s[1]=Math.max(s[1]||0,c(D)||0)}})}a=(s.length==1?s[0]:s.reduce(function(v,w){return v+w}))+s.length+1;function u(v,D){var D=D||0;v.forEach(function(S,F){s[F+D]=Math.max(s[F+D]||0,c(S)||0)})}function c(v){return typeof v=="object"&&v.width!=null?v.width:(typeof v=="object"?ml.strlen(v.text):ml.strlen(v))+(t["padding-left"]||0)+(t["padding-right"]||0)}function h(L,w,D,S){var F=0,L=w+N0(L,a-2)+D;return s.forEach(function(j,W){W!=s.length-1&&(F+=j+1,L=L.substr(0,F)+S+L.substr(F+1))}),f(e.style.border,L)}function d(){var v=h(r.top,r["top-left"]||r.top,r["top-right"]||r.top,r["top-mid"]);v&&(n+=v+` -`)}function g(v,w){var D=[],S=0;if(!Array.isArray(v)&&typeof v=="object"){var F=Object.keys(v)[0],L=v[F],j=!0;Array.isArray(L)?(v=L,v.unshift(F)):v=[F,L]}v.forEach(function(N,I){var M=N.toString().split(` -`).reduce(function(K,ae){return K.push(p(ae,I)),K},[]),J=M.length;J>S&&(S=J),D.push({contents:M,height:J})});var W=new Array(S);D.forEach(function(N,I){N.contents.forEach(function(K,ae){W[ae]||(W[ae]=[]),(w||j&&I===0&&e.style.head)&&(K=f(e.style.head,K)),W[ae].push(K)});for(var M=N.height,J=S;M0&&(B+=` -`+f(e.style.border,r.left)),B+=N.join(f(e.style.border,r.middle))+f(e.style.border,r.right)}),f(e.style.border,r.left)+B}function f(v,w){return w?(v.forEach(function(D){w=Ype[D](w)}),w):""}function p(D,w){var D=String(typeof D=="object"&&D.text?D.text:D),S=ml.strlen(D),F=s[w]-(t["padding-left"]||0)-(t["padding-right"]||0),L=e.colAligns[w]||"left";return N0(" ",t["padding-left"]||0)+(S==F?D:S{"use strict";var lq=(n=0)=>e=>`\x1B[${38+n};5;${e}m`,uq=(n=0)=>(e,t,i)=>`\x1B[${38+n};2;${e};${t};${i}m`;function Jpe(){let n=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[t,i]of Object.entries(e)){for(let[r,o]of Object.entries(i))e[r]={open:`\x1B[${o[0]}m`,close:`\x1B[${o[1]}m`},i[r]=e[r],n.set(o[0],o[1]);Object.defineProperty(e,t,{value:i,enumerable:!1})}return Object.defineProperty(e,"codes",{value:n,enumerable:!1}),e.color.close="\x1B[39m",e.bgColor.close="\x1B[49m",e.color.ansi256=lq(),e.color.ansi16m=uq(),e.bgColor.ansi256=lq(10),e.bgColor.ansi16m=uq(10),Object.defineProperties(e,{rgbToAnsi256:{value:(t,i,r)=>t===i&&i===r?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(i/255*5)+Math.round(r/255*5),enumerable:!1},hexToRgb:{value:t=>{let i=/(?[a-f\d]{6}|[a-f\d]{3})/i.exec(t.toString(16));if(!i)return[0,0,0];let{colorString:r}=i.groups;r.length===3&&(r=r.split("").map(s=>s+s).join(""));let o=Number.parseInt(r,16);return[o>>16&255,o>>8&255,o&255]},enumerable:!1},hexToAnsi256:{value:t=>e.rgbToAnsi256(...e.hexToRgb(t)),enumerable:!1}}),e}Object.defineProperty(cq,"exports",{enumerable:!0,get:Jpe})});function dq(n){return`${yi.default.gray.open}${n}${yi.default.gray.close}`}function H0(n){return`${yi.default.magenta.open}${n}${yi.default.magenta.close}`}function gq(n){return`${yi.default.bold.open}${n}${yi.default.bold.close}`}function q0(n){return`${yi.default.underline.open}${n}${yi.default.underline.close}`}function fq(n){return`${yi.default.strikethrough.open}${n}${yi.default.strikethrough.close}`}function pq(n){return`${yi.default.italic.open}${n}${yi.default.italic.close}`}function mq(n){return`${yi.default.yellow.open}${n}${yi.default.yellow.close}`}function Y0(n){return`${yi.default.blue.open}${n}${yi.default.blue.close}`}var yi,bq=_(()=>{"use strict";yi=C(hq())});function Rr(n){return n}function Qpe(n){return dq(n.replace(/(<([^>]+)>)/ig,""))}function yq(n,e){return e?n.replace(Gpe,/\n/g):n}function zpe(n,e){return e.replace(/(^|\n)(.+)/g,"$1"+n+"$2")}function Vpe(n,e){return e&&n+e.split(` -`).join(` -`+n)}function ime(n,e){let t=new RegExp("(\\S(?: | )?)((?:"+e+")+)("+Sq+"(?:.*)+)$","gm");return n.replace(t,`$1 -`+e+"$2$3")}function kq(n){return" ".repeat(n.length)}function nme(n,e){return Tq(e,n)?e:kq(J0)+e}function rme(n,e){let t=nme.bind(null,e);return n.split(` -`).filter(Rr).map(t).join(` -`)}function ome(n,e,t){return Tq(e,n)?{num:t+1,line:e.replace(J0,vq(t+1))}:{num:t,line:kq(vq(t))+e}}function sme(n,e){let t=ome.bind(null,e),i=0;return n.split(` -`).filter(Rr).map(r=>{let o=t(r,i);return i=o.num,o.line}).join(` -`)}function ame(n,e,t){return n=n.trim(),n=e?sme(n,t):rme(n,t),n}function cg(n){return n+` - -`}function lme(n){return n.replace(Upe,":")}function wq(n,e=null){if(!n)return[];e=e||Rr;let t=e(n).split(` -`),i=[];return t.forEach(function(r){if(!r)return;let o=r.replace(Xpe,"").split(xq);i.push(o.splice(0,o.length-1))}),i}function Eq(n){return n.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function ume(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'")}var Dq,hRe,xq,Z0,Xpe,Cq,Upe,Gpe,Kpe,eme,tme,Sq,Tq,J0,vq,W0,Pq,$0,_q=_(()=>{"use strict";Dq=C(aq());bq();hRe=q()("markdown-renderer"),xq="^*||*^",Z0="*|*|*|*",Xpe=new RegExp(Eq(Z0),"g"),Cq="*#COLON|*",Upe=new RegExp(Eq(Cq),"g"),Gpe="\r";Kpe={code:Rr,blockquote:Rr,html:Qpe,heading:H0,firstHeading:H0,hr:Rr,listitem:Rr,list:ame,table:Rr,paragraph:Rr,strong:gq,em:pq,codespan:mq,del:fq,link:q0,href:q0,text:Rr,unescape:!0,emoji:!1,width:80,showSectionPrefix:!0,tab:2,tableOptions:{}};eme="\\*",tme="\\d+\\.",Sq="(?:"+[eme,tme].join("|")+")";Tq=function(n,e){return n.match("^(?:"+e+")*"+Sq)};J0="* ";vq=function(n){return n+". "};W0=new Map,Pq=class{constructor(e={},t={}){this.options=e;this.highlightOptions=t;this.o=Object.assign({},Kpe,e),this.tab=" ",this.tableSettings=this.o.tableOptions,this.unescape=this.o.unescape?ume:Rr,this.highlightOptions=t||{},this.transform=this.compose(lme,this.unescape)}text(e){return this.o.text(e)}code(e,t,i){return"``` "+t+` -`+e+"\n```\n"}blockquote(e){return cg(this.o.blockquote(Vpe(this.tab,e.trim())))}html(e){return this.o.html(e)}heading(e,t,i){return e=this.transform(e),e=(this.o.showSectionPrefix?new Array(t+1).join("#")+" ":"")+e,cg(t===1?this.o.firstHeading(e):this.o.heading(e))}hr(){return`\u2500\u2500\u2500 -`}list(e,t){return e=this.o.list(e,t,this.tab),cg(ime(zpe(this.tab,e),this.tab))}listitem(e){let t=this.compose(this.o.listitem,this.transform);return e.indexOf(` -`)!==-1&&(e=e.trim()),` -`+J0+t(e)}checkbox(e){return"["+(e?"X":" ")+"] "}paragraph(e){return e=this.compose(this.o.paragraph,this.transform)(e),cg(e)}table(e,t){let i=new Dq.default(Object.assign({},{head:wq(e)[0]},this.tableSettings));return wq(t,this.transform).forEach(function(r){i.push(r)}),cg(this.o.table(i.toString()))}tablerow(e){return Z0+e+Z0+` -`}tablecell(e,t){return e+xq}strong(e){return this.o.strong(e)}em(e){return e=yq(e,this.o.reflowText),this.o.em(e)}codespan(e){return e=yq(e,this.o.reflowText),this.o.codespan(e.replace(/:/g,Cq))}br(){return` -`}del(e){return this.o.del(e)}link(e,t,i){let r;try{r=decodeURIComponent(unescape(e)).replace(/[^\w:]/g,"").toLowerCase()}catch{return""}if(r.startsWith("javascript:"))return"";if(i&&e&&i!=e&&W0.set(i,e),i&&i!=e)return Y0(i);let o=this.o.href(e);return this.o.link(o)}image(e,t,i){let r="!["+i;return t&&(r+=" \u2013 "+t),r+"]("+e+")"}compose(...e){return(...t)=>{for(let i=e.length;i-- >0;)t=[e[i].apply(this,t)];return t[0]}}static getLinks(){let e=[];for(let[t,i]of W0.entries())e.push(`${Y0(t)}: ${i}`);return W0.clear(),e}},$0=Pq});function mc(n,e=!1){let t=hg(n),i=[],r="";for(let o of t){if(!o.text)continue;let{foreground:s,background:a}=o,l=Q(r),u=[l,l+Q(o.text)];if(s&&a){let c=`CocList${hn(s)}${hn(a)}`;i.push({span:u,hlGroup:c})}else if(s){let c;e?s=="yellow"?c="CocMarkdownCode":s=="blue"?c="CocMarkdownLink":s=="magenta"?c="CocMarkdownHeader":c=`CocListFg${hn(s)}`:c=`CocListFg${hn(s)}`,i.push({span:u,hlGroup:c})}else if(a){let c=`CocListBg${hn(a)}`;i.push({span:u,hlGroup:c})}o.bold?i.push({span:u,hlGroup:"CocBold"}):o.italic?i.push({span:u,hlGroup:"CocItalic"}):o.underline?i.push({span:u,hlGroup:"CocUnderline"}):o.strikethrough&&i.push({span:u,hlGroup:"CocStrikeThrough"}),r=r+o.text}return{line:r,highlights:i}}function hg(n){let e=null,t=null,i="",r=[],o=[],s={},a;a=()=>{let l,u;i.length?i=i.substr(0,i.length-1):o.length&&(l=o.length-1,u=o[l].text,u.length===1?o.pop():o[l].text=u.substr(0,u.length-1))};for(let l=0;l{Rq[u]?s.foreground=Rq[u]:Lq[u]?s.background=Lq[u]:u==39?delete s.foreground:u==49?delete s.background:Fq[u]?s[Fq[u]]=!0:u==22?s.bold=!1:u==23?s.italic=!1:u==24?s.underline=!1:u==29&&(s.strikethrough=!1)}),r=[]):t+=n[l];continue}n[l]=="\x1B"?e=n[l]:n[l]=="\b"?a():i+=n[l]}return i&&(s.text=i+(e||""),o.push(s)),o}var Rq,Lq,Fq,bc=_(()=>{"use strict";Pe();Rq={30:"black",31:"red",32:"green",33:"yellow",34:"blue",35:"magenta",36:"cyan",37:"white",90:"grey"},Lq={40:"black",41:"red",42:"green",43:"yellow",44:"blue",45:"magenta",46:"cyan",47:"white"},Fq={1:"bold",3:"italic",4:"underline",9:"strikethrough"}});var jq=m((pRe,Iq)=>{"use strict";Iq.exports=({onlyFirst:n=!1}={})=>{let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(e,n?void 0:"g")}});var dg=m((mRe,Aq)=>{"use strict";var cme=jq();Aq.exports=n=>typeof n=="string"?n.replace(cme(),""):n});function lb(n,e={}){let t=[],i=[],r=[],o=0;for(let s of n){let a=t.length,{content:l,filetype:u}=s,c=s.highlights;if(u=="markdown"){let h=gme(l,e);r.push(...h.codes.map(d=>(d.startLine=d.startLine+a,d.endLine=d.endLine+a,d))),i.push(...h.highlights.map(d=>(d.lnum=d.lnum+a,d))),t.push(...h.lines)}else{let h=l.trim().split(/\r?\n/);hme.includes(s.filetype)?r.push({hlGroup:`Coc${u}Float`,startLine:a,endLine:a+h.length}):r.push({filetype:s.filetype,startLine:a,endLine:a+h.length}),t.push(...h)}if(Array.isArray(c)&&i.push(...c.map(h=>Object.assign({},h,{lnum:h.lnum+a}))),Array.isArray(s.active)){let h=dme(l,a,s.active);h.length&&i.push(...h)}o!=n.length-1&&t.push("\u2500"),o=o+1}return{lines:t,highlights:i,codes:r}}function dme(n,e,t){let i=[],[r,o]=t,s=n.split(/\r?\n/),a=0,l=!1;for(let u=0;uo){let h=Q(c.slice(0,o-a));i.push({colStart:0,colEnd:h,lnum:u+e,hlGroup:"CocUnderline"}),l=!1;break}else{let h=Q(c);i.push({colStart:0,colEnd:h,lnum:u+e,hlGroup:"CocUnderline"})}else if(a+c.length>r){l=!0;let h=Q(c.slice(0,r-a));if(a+c.length>o){let d=Q(c.slice(0,o-a));l=!1,i.push({colStart:h,colEnd:d,lnum:u+e,hlGroup:"CocUnderline"});break}else{let d=Q(c);i.push({colStart:h,colEnd:d,lnum:u+e,hlGroup:"CocUnderline"})}}a=a+c.length+1}return i}function gme(n,e){fe.setOptions({renderer:new $0,gfm:!0,breaks:!0});let t=[],i=[],r=[],o=0,s=!1,a,l=0,u=fe(n),c=$0.getLinks();c.length&&(u=u+` - -`+c.join(` -`)),u=u.replace(/\s*$/,"");let h=u.split(/\n/);for(let d=0;d{"use strict";FH();_q();bc();Pe();Oq=C(dg()),hme=["Error","Warning","Info","Hint"],DRe=q()("markdown-index")});var ei,io=_(()=>{"use strict";ei=class{constructor(){this.tasks=[];this.count=1}sched(){this.count>0&&this.tasks.length>0&&(this.count--,this.tasks.shift()())}get busy(){return this.count==0}acquire(){return new Promise(e=>{let t=()=>{let i=!1;e(()=>{i||(i=!0,this.count++,this.sched())})};this.tasks.push(t),process.nextTick(this.sched.bind(this))})}use(e){return this.acquire().then(t=>e().then(i=>(t(),i)).catch(i=>{throw t(),i}))}}});var Mq,Nq,fme,RRe,ci,Zo=_(()=>{"use strict";Mq=C(Ei()),Nq=C(H());le();X0();z();io();Jt();fme=process.env.VIM_NODE_RPC=="1",RRe=q()("model-float"),ci=class{constructor(e){this.nvim=e;this.winid=0;this._bufnr=0;this.mutex=new ei;this.disposables=[];this.onCursorMoved=(0,Mq.default)(this._onCursorMoved.bind(this),100)}bindEvents(e,t){let i=["InsertLeave","InsertEnter","BufEnter"];for(let r of i)E.on(r,o=>{o!=this._bufnr&&this.close()},null,this.disposables);E.on("MenuPopupChanged",()=>{E.pumAlignTop==t&&this.close()},null,this.disposables),this.disposables.push(Nq.Disposable.create(()=>{this.onCursorMoved.clear()})),E.on("CursorMoved",this.onCursorMoved.bind(this,e),this,this.disposables),E.on("CursorMovedI",this.onCursorMoved.bind(this,e),this,this.disposables)}unbind(){this.disposables.length&&(Z(this.disposables),this.disposables=[])}_onCursorMoved(e,t,i){if(t!=this._bufnr&&!(t==this.targetBufnr&&Fe(i,this.cursor))&&(e||t!=this.targetBufnr||!E.insertMode)){this.close();return}}async create(e,t=!1,i=0){await this.show(e,{offsetX:i})}applyFloatConfig(e,t){for(let i of Object.keys(t)){if(i=="border"){t.border&&(e.border=[1,1,1,1]);continue}e[i]=t[i]}return e}async show(e,t={}){if(e.length==0||e.every(o=>o.content.length==0)){this.close();return}let i=Date.now(),r=await this.mutex.acquire();try{await this.createPopup(e,t,i),r()}catch(o){this.nvim.echoError(o),r()}}async createPopup(e,t,i){e=e.filter(p=>p.content.trim().length>0);let{lines:r,codes:o,highlights:s}=lb(e),a={codes:o,highlights:s,pumAlignTop:E.pumAlignTop,preferTop:typeof t.preferTop=="boolean"?t.preferTop:!1,offsetX:t.offsetX||0,title:t.title||"",close:t.close?1:0,rounded:t.rounded?1:0,modes:t.modes||["n","i","ic","s"]};fme||(typeof t.winblend=="number"&&(a.winblend=t.winblend),t.focusable!=null&&(a.focusable=t.focusable?1:0),t.shadow&&(a.shadow=1)),t.maxHeight&&(a.maxHeight=t.maxHeight),t.maxWidth&&(a.maxWidth=t.maxWidth),t.border&&!t.border.every(p=>p==0)&&(a.border=t.border),t.title&&!a.border&&(a.border=[1,1,1,1]),t.highlight&&(a.highlight=t.highlight),t.borderhighlight&&(a.borderhighlight=[t.borderhighlight]),t.cursorline&&(a.cursorline=1);let l=t.autoHide!=!1;l&&(a.autohide=1),this.unbind();let u=await this.nvim.call("coc#dialog#create_cursor_float",[this.winid,this._bufnr,r,a]);if(this.nvim.redrawVim(),!u||u.length==0||this.closeTs>i){let p=u&&u.length>0?u[2]:this.winid;p&&(this.winid=0,this.nvim.call("coc#float#close",[p],!0),this.nvim.redrawVim());return}let[c,h,d,g,f]=u;this.winid=d,this._bufnr=g,this.targetBufnr=c,this.cursor=h,this.bindEvents(l,f==1)}close(){let{winid:e,nvim:t}=this;this.closeTs=Date.now(),this.unbind(),e&&(this.winid=0,t.call("coc#float#close",[e],!0),t.redrawVim())}checkRetrigger(e){return!!(this.winid&&this.targetBufnr==e)}get bufnr(){return this._bufnr}get buffer(){return this.bufnr?this.nvim.createBuffer(this.bufnr):null}get window(){return this.winid?this.nvim.createWindow(this.winid):null}async activated(){return this.winid?await this.nvim.call("coc#float#valid",[this.winid])!=0:!1}dispose(){this.cursor=void 0,this.close()}}});var Hq=m((FRe,Bq)=>{Bq.exports=function(n,e){for(var t=[],i=0;i{"use strict";Zq.exports=Yq;function Yq(n,e,t){n instanceof RegExp&&(n=qq(n,t)),e instanceof RegExp&&(e=qq(e,t));var i=Wq(n,e,t);return i&&{start:i[0],end:i[1],pre:t.slice(0,i[0]),body:t.slice(i[0]+n.length,i[1]),post:t.slice(i[1]+e.length)}}function qq(n,e){var t=e.match(n);return t?t[0]:null}Yq.range=Wq;function Wq(n,e,t){var i,r,o,s,a,l=t.indexOf(n),u=t.indexOf(e,l+1),c=l;if(l>=0&&u>0){if(n===e)return[l,u];for(i=[],o=t.length;c>=0&&!a;)c==l?(i.push(c),l=t.indexOf(n,c+1)):i.length==1?a=[i.pop(),u]:(r=i.pop(),r=0?l:u;i.length&&(a=[o,s])}return a}});var Vq=m((jRe,zq)=>{var mme=Hq(),$q=Jq();zq.exports=vme;var Xq="\0SLASH"+Math.random()+"\0",Uq="\0OPEN"+Math.random()+"\0",G0="\0CLOSE"+Math.random()+"\0",Gq="\0COMMA"+Math.random()+"\0",Qq="\0PERIOD"+Math.random()+"\0";function U0(n){return parseInt(n,10)==n?parseInt(n,10):n.charCodeAt(0)}function bme(n){return n.split("\\\\").join(Xq).split("\\{").join(Uq).split("\\}").join(G0).split("\\,").join(Gq).split("\\.").join(Qq)}function yme(n){return n.split(Xq).join("\\").split(Uq).join("{").split(G0).join("}").split(Gq).join(",").split(Qq).join(".")}function Kq(n){if(!n)return[""];var e=[],t=$q("{","}",n);if(!t)return n.split(",");var i=t.pre,r=t.body,o=t.post,s=i.split(",");s[s.length-1]+="{"+r+"}";var a=Kq(o);return o.length&&(s[s.length-1]+=a.shift(),s.push.apply(s,a)),e.push.apply(e,s),e}function vme(n){return n?(n.substr(0,2)==="{}"&&(n="\\{\\}"+n.substr(2)),yc(bme(n),!0).map(yme)):[]}function wme(n){return"{"+n+"}"}function Dme(n){return/^-?0\d/.test(n)}function xme(n,e){return n<=e}function Cme(n,e){return n>=e}function yc(n,e){var t=[],i=$q("{","}",n);if(!i||/\$$/.test(i.pre))return[n];var r=/^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(i.body),o=/^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(i.body),s=r||o,a=i.body.indexOf(",")>=0;if(!s&&!a)return i.post.match(/,.*\}/)?(n=i.pre+"{"+i.body+G0+i.post,yc(n)):[n];var l;if(s)l=i.body.split(/\.\./);else if(l=Kq(i.body),l.length===1&&(l=yc(l[0],!1).map(wme),l.length===1)){var c=i.post.length?yc(i.post,!1):[""];return c.map(function(I){return i.pre+l[0]+I})}var u=i.pre,c=i.post.length?yc(i.post,!1):[""],h;if(s){var d=U0(l[0]),g=U0(l[1]),f=Math.max(l[0].length,l[1].length),p=l.length==3?Math.abs(U0(l[2])):1,b=xme,v=g0){var L=new Array(F+1).join("0");D<0?S="-"+L+S.slice(1):S=L+S}}h.push(S)}}else h=mme(l,function(N){return yc(N,!1)});for(var j=0;j{o2.exports=zn;zn.Minimatch=hi;var gg={sep:"/"};try{gg=require("path")}catch{}var z0=zn.GLOBSTAR=hi.GLOBSTAR={},Sme=Vq(),e2={"!":{open:"(?:(?!(?:",close:"))[^/]*?)"},"?":{open:"(?:",close:")?"},"+":{open:"(?:",close:")+"},"*":{open:"(?:",close:")*"},"@":{open:"(?:",close:")"}},Q0="[^/]",K0=Q0+"*?",Tme="(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?",kme="(?:(?!(?:\\/|^)\\.).)*?",t2=Eme("().*{}+?[]^$\\!");function Eme(n){return n.split("").reduce(function(e,t){return e[t]=!0,e},{})}var n2=/\/+/;zn.filter=Pme;function Pme(n,e){return e=e||{},function(t,i,r){return zn(t,n,e)}}function i2(n,e){n=n||{},e=e||{};var t={};return Object.keys(e).forEach(function(i){t[i]=e[i]}),Object.keys(n).forEach(function(i){t[i]=n[i]}),t}zn.defaults=function(n){if(!n||!Object.keys(n).length)return zn;var e=zn,t=function(r,o,s){return e.minimatch(r,o,i2(n,s))};return t.Minimatch=function(r,o){return new e.Minimatch(r,i2(n,o))},t};hi.defaults=function(n){return!n||!Object.keys(n).length?hi:zn.defaults(n).Minimatch};function zn(n,e,t){if(typeof e!="string")throw new TypeError("glob pattern string required");return t||(t={}),!t.nocomment&&e.charAt(0)==="#"?!1:e.trim()===""?n==="":new hi(e,t).match(n)}function hi(n,e){if(!(this instanceof hi))return new hi(n,e);if(typeof n!="string")throw new TypeError("glob pattern string required");e||(e={}),n=n.trim(),gg.sep!=="/"&&(n=n.split(gg.sep).join("/")),this.options=e,this.set=[],this.pattern=n,this.regexp=null,this.negate=!1,this.comment=!1,this.empty=!1,this.make()}hi.prototype.debug=function(){};hi.prototype.make=_me;function _me(){if(!this._made){var n=this.pattern,e=this.options;if(!e.nocomment&&n.charAt(0)==="#"){this.comment=!0;return}if(!n){this.empty=!0;return}this.parseNegate();var t=this.globSet=this.braceExpand();e.debug&&(this.debug=console.error),this.debug(this.pattern,t),t=this.globParts=t.map(function(i){return i.split(n2)}),this.debug(this.pattern,t),t=t.map(function(i,r,o){return i.map(this.parse,this)},this),this.debug(this.pattern,t),t=t.filter(function(i){return i.indexOf(!1)===-1}),this.debug(this.pattern,t),this.set=t}}hi.prototype.parseNegate=Rme;function Rme(){var n=this.pattern,e=!1,t=this.options,i=0;if(!t.nonegate){for(var r=0,o=n.length;r"u"?this.pattern:n,typeof n>"u")throw new TypeError("undefined pattern");return e.nobrace||!n.match(/\{.*\}/)?[n]:Sme(n)}hi.prototype.parse=Lme;var ub={};function Lme(n,e){if(n.length>1024*64)throw new TypeError("pattern is too long");var t=this.options;if(!t.noglobstar&&n==="**")return z0;if(n==="")return"";var i="",r=!!t.nocase,o=!1,s=[],a=[],l,u=!1,c=-1,h=-1,d=n.charAt(0)==="."?"":t.dot?"(?!(?:^|\\/)\\.{1,2}(?:$|\\/))":"(?!\\.)",g=this;function f(){if(l){switch(l){case"*":i+=K0,r=!0;break;case"?":i+=Q0,r=!0;break;default:i+="\\"+l;break}g.debug("clearStateChar %j %j",l,i),l=!1}}for(var p=0,b=n.length,v;p-1;W--){var B=a[W],N=i.slice(0,B.reStart),I=i.slice(B.reStart,B.reEnd-8),M=i.slice(B.reEnd-8,B.reEnd),J=i.slice(B.reEnd);M+=J;var K=N.split("(").length-1,ae=J;for(p=0;p=0&&(r=n[o],!r);o--);for(o=0;o>> no match, partial?`,n,c,e,h),c===s))}var g;if(typeof l=="string"?(i.nocase?g=u.toLowerCase()===l.toLowerCase():g=u===l,this.debug("string match",l,u,g)):(g=u.match(l),this.debug("pattern match",l,u,g)),!g)return!1}if(r===s&&o===a)return!0;if(r===s)return t;if(o===a){var f=r===s-1&&n[r]==="";return f}throw new Error("wtf?")};function jme(n){return n.replace(/\\(.)/g,"$1")}function Ame(n){return n.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")}});var s2=m(V0=>{var bl=require("path"),Vs=process.platform==="win32",zs=require("fs"),Ome=process.env.NODE_DEBUG&&/fs/.test(process.env.NODE_DEBUG);function Mme(){var n;if(Ome){var e=new Error;n=t}else n=i;return n;function t(r){r&&(e.message=r.message,r=e,i(r))}function i(r){if(r){if(process.throwDeprecation)throw r;if(!process.noDeprecation){var o="fs: missing callback "+(r.stack||r.message);process.traceDeprecation?console.trace(o):console.error(o)}}}}function Nme(n){return typeof n=="function"?n:Mme()}var ORe=bl.normalize;Vs?Jo=/(.*?)(?:[\/\\]+|$)/g:Jo=/(.*?)(?:[\/]+|$)/g;var Jo;Vs?fg=/^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/:fg=/^[\/]*/;var fg;V0.realpathSync=function(e,t){if(e=bl.resolve(e),t&&Object.prototype.hasOwnProperty.call(t,e))return t[e];var i=e,r={},o={},s,a,l,u;c();function c(){var b=fg.exec(e);s=b[0].length,a=b[0],l=b[0],u="",Vs&&!o[l]&&(zs.lstatSync(l),o[l]=!0)}for(;s=e.length)return t&&(t[r]=e),i(null,e);Jo.lastIndex=a;var b=Jo.exec(e);return c=l,l+=b[0],u=c+b[1],a=Jo.lastIndex,s[u]||t&&t[u]===u?process.nextTick(d):t&&Object.prototype.hasOwnProperty.call(t,u)?p(t[u]):zs.lstat(u,g)}function g(b,v){if(b)return i(b);if(!v.isSymbolicLink())return s[u]=!0,t&&(t[u]=u),process.nextTick(d);if(!Vs){var w=v.dev.toString(32)+":"+v.ino.toString(32);if(o.hasOwnProperty(w))return f(null,o[w],u)}zs.stat(u,function(D){if(D)return i(D);zs.readlink(u,function(S,F){Vs||(o[w]=F),f(S,F)})})}function f(b,v,w){if(b)return i(b);var D=bl.resolve(c,v);t&&(t[w]=D),p(D)}function p(b){e=bl.resolve(b,e.slice(a)),h()}}});var nT=m((NRe,c2)=>{c2.exports=ea;ea.realpath=ea;ea.sync=iT;ea.realpathSync=iT;ea.monkeypatch=Hme;ea.unmonkeypatch=qme;var vc=require("fs"),eT=vc.realpath,tT=vc.realpathSync,Bme=process.version,a2=/^v[0-5]\./.test(Bme),l2=s2();function u2(n){return n&&n.syscall==="realpath"&&(n.code==="ELOOP"||n.code==="ENOMEM"||n.code==="ENAMETOOLONG")}function ea(n,e,t){if(a2)return eT(n,e,t);typeof e=="function"&&(t=e,e=null),eT(n,e,function(i,r){u2(i)?l2.realpath(n,e,t):t(i,r)})}function iT(n,e){if(a2)return tT(n,e);try{return tT(n,e)}catch(t){if(u2(t))return l2.realpathSync(n,e);throw t}}function Hme(){vc.realpath=ea,vc.realpathSync=iT}function qme(){vc.realpath=eT,vc.realpathSync=tT}});var h2=m((BRe,rT)=>{typeof Object.create=="function"?rT.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:rT.exports=function(e,t){if(t){e.super_=t;var i=function(){};i.prototype=t.prototype,e.prototype=new i,e.prototype.constructor=e}}});var d2=m((HRe,sT)=>{try{if(oT=require("util"),typeof oT.inherits!="function")throw"";sT.exports=oT.inherits}catch{sT.exports=h2()}var oT});var hb=m((qRe,cb)=>{"use strict";function g2(n){return n.charAt(0)==="/"}function f2(n){var e=/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/,t=e.exec(n),i=t[1]||"",r=Boolean(i&&i.charAt(1)!==":");return Boolean(t[2]||r)}cb.exports=process.platform==="win32"?f2:g2;cb.exports.posix=g2;cb.exports.win32=f2});var lT=m(ta=>{ta.setopts=Xme;ta.ownProp=p2;ta.makeAbs=pg;ta.finish=Ume;ta.mark=Gme;ta.isIgnored=b2;ta.childrenIgnored=Qme;function p2(n,e){return Object.prototype.hasOwnProperty.call(n,e)}var Yme=require("fs"),wc=require("path"),Wme=Vn(),m2=hb(),aT=Wme.Minimatch;function Zme(n,e){return n.localeCompare(e,"en")}function Jme(n,e){n.ignore=e.ignore||[],Array.isArray(n.ignore)||(n.ignore=[n.ignore]),n.ignore.length&&(n.ignore=n.ignore.map($me))}function $me(n){var e=null;if(n.slice(-3)==="/**"){var t=n.replace(/(\/\*\*)+$/,"");e=new aT(t,{dot:!0})}return{matcher:new aT(n,{dot:!0}),gmatcher:e}}function Xme(n,e,t){if(t||(t={}),t.matchBase&&e.indexOf("/")===-1){if(t.noglobstar)throw new Error("base matching requires globstar");e="**/"+e}n.silent=!!t.silent,n.pattern=e,n.strict=t.strict!==!1,n.realpath=!!t.realpath,n.realpathCache=t.realpathCache||Object.create(null),n.follow=!!t.follow,n.dot=!!t.dot,n.mark=!!t.mark,n.nodir=!!t.nodir,n.nodir&&(n.mark=!0),n.sync=!!t.sync,n.nounique=!!t.nounique,n.nonull=!!t.nonull,n.nosort=!!t.nosort,n.nocase=!!t.nocase,n.stat=!!t.stat,n.noprocess=!!t.noprocess,n.absolute=!!t.absolute,n.fs=t.fs||Yme,n.maxLength=t.maxLength||1/0,n.cache=t.cache||Object.create(null),n.statCache=t.statCache||Object.create(null),n.symlinks=t.symlinks||Object.create(null),Jme(n,t),n.changedCwd=!1;var i=process.cwd();p2(t,"cwd")?(n.cwd=wc.resolve(t.cwd),n.changedCwd=n.cwd!==i):n.cwd=i,n.root=t.root||wc.resolve(n.cwd,"/"),n.root=wc.resolve(n.root),process.platform==="win32"&&(n.root=n.root.replace(/\\/g,"/")),n.cwdAbs=m2(n.cwd)?n.cwd:pg(n,n.cwd),process.platform==="win32"&&(n.cwdAbs=n.cwdAbs.replace(/\\/g,"/")),n.nomount=!!t.nomount,t.nonegate=!0,t.nocomment=!0,n.minimatch=new aT(e,t),n.options=n.minimatch.options}function Ume(n){for(var e=n.nounique,t=e?[]:Object.create(null),i=0,r=n.matches.length;i{D2.exports=w2;w2.GlobSync=ti;var Kme=nT(),y2=Vn(),WRe=y2.Minimatch,ZRe=gb().Glob,JRe=require("util"),uT=require("path"),v2=require("assert"),db=hb(),yl=lT(),zme=yl.setopts,cT=yl.ownProp,Vme=yl.childrenIgnored,ebe=yl.isIgnored;function w2(n,e){if(typeof e=="function"||arguments.length===3)throw new TypeError(`callback provided to sync glob -See: https://github.com/isaacs/node-glob/issues/167`);return new ti(n,e).found}function ti(n,e){if(!n)throw new Error("must provide pattern");if(typeof e=="function"||arguments.length===3)throw new TypeError(`callback provided to sync glob -See: https://github.com/isaacs/node-glob/issues/167`);if(!(this instanceof ti))return new ti(n,e);if(zme(this,n,e),this.noprocess)return this;var t=this.minimatch.set.length;this.matches=new Array(t);for(var i=0;ithis.maxLength)return!1;if(!this.stat&&cT(this.cache,e)){var s=this.cache[e];if(Array.isArray(s)&&(s="DIR"),!t||s==="DIR")return s;if(t&&s==="FILE")return!1}var i,r=this.statCache[e];if(!r){var o;try{o=this.fs.lstatSync(e)}catch(a){if(a&&(a.code==="ENOENT"||a.code==="ENOTDIR"))return this.statCache[e]=!1,!1}if(o&&o.isSymbolicLink())try{r=this.fs.statSync(e)}catch{r=o}else r=o}this.statCache[e]=r;var s=!0;return r&&(s=r.isDirectory()?"DIR":"FILE"),this.cache[e]=this.cache[e]||s,t&&s==="FILE"?!1:s};ti.prototype._mark=function(n){return yl.mark(this,n)};ti.prototype._makeAbs=function(n){return yl.makeAbs(this,n)}});var hT=m((XRe,S2)=>{S2.exports=C2;function C2(n,e){if(n&&e)return C2(n)(e);if(typeof n!="function")throw new TypeError("need wrapper function");return Object.keys(n).forEach(function(i){t[i]=n[i]}),t;function t(){for(var i=new Array(arguments.length),r=0;r{var T2=hT();dT.exports=T2(fb);dT.exports.strict=T2(k2);fb.proto=fb(function(){Object.defineProperty(Function.prototype,"once",{value:function(){return fb(this)},configurable:!0}),Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return k2(this)},configurable:!0})});function fb(n){var e=function(){return e.called?e.value:(e.called=!0,e.value=n.apply(this,arguments))};return e.called=!1,e}function k2(n){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=n.apply(this,arguments)},t=n.name||"Function wrapped with `once`";return e.onceError=t+" shouldn't be called more than once",e.called=!1,e}});var P2=m((GRe,E2)=>{var tbe=hT(),mg=Object.create(null),ibe=gT();E2.exports=tbe(nbe);function nbe(n,e){return mg[n]?(mg[n].push(e),null):(mg[n]=[e],rbe(n))}function rbe(n){return ibe(function e(){var t=mg[n],i=t.length,r=obe(arguments);try{for(var o=0;oi?(t.splice(0,i),process.nextTick(function(){e.apply(null,r)})):delete mg[n]}})}function obe(n){for(var e=n.length,t=[],i=0;i{R2.exports=vl;var sbe=nT(),_2=Vn(),QRe=_2.Minimatch,abe=d2(),lbe=require("events").EventEmitter,fT=require("path"),pT=require("assert"),bg=hb(),bT=x2(),wl=lT(),ube=wl.setopts,mT=wl.ownProp,yT=P2(),KRe=require("util"),cbe=wl.childrenIgnored,hbe=wl.isIgnored,dbe=gT();function vl(n,e,t){if(typeof e=="function"&&(t=e,e={}),e||(e={}),e.sync){if(t)throw new TypeError("callback provided to sync glob");return bT(n,e)}return new Ue(n,e,t)}vl.sync=bT;var gbe=vl.GlobSync=bT.GlobSync;vl.glob=vl;function fbe(n,e){if(e===null||typeof e!="object")return n;for(var t=Object.keys(e),i=t.length;i--;)n[t[i]]=e[t[i]];return n}vl.hasMagic=function(n,e){var t=fbe({},e);t.noprocess=!0;var i=new Ue(n,t),r=i.minimatch.set;if(!n)return!1;if(r.length>1)return!0;for(var o=0;othis.maxLength)return e();if(!this.stat&&mT(this.cache,t)){var r=this.cache[t];if(Array.isArray(r)&&(r="DIR"),!i||r==="DIR")return e(null,r);if(i&&r==="FILE")return e()}var o,s=this.statCache[t];if(s!==void 0){if(s===!1)return e(null,s);var a=s.isDirectory()?"DIR":"FILE";return i&&a==="FILE"?e():e(null,a,s)}var l=this,u=yT("stat\0"+t,c);u&&l.fs.lstat(t,u);function c(h,d){if(d&&d.isSymbolicLink())return l.fs.stat(t,function(g,f){g?l._stat2(n,t,null,d,e):l._stat2(n,t,g,f,e)});l._stat2(n,t,h,d,e)}};Ue.prototype._stat2=function(n,e,t,i,r){if(t&&(t.code==="ENOENT"||t.code==="ENOTDIR"))return this.statCache[e]=!1,r();var o=n.slice(-1)==="/";if(this.statCache[e]=i,e.slice(-1)==="/"&&i&&!i.isDirectory())return r(null,!1,i);var s=!0;return i&&(s=i.isDirectory()?"DIR":"FILE"),this.cache[e]=this.cache[e]||s,o&&s==="FILE"?r():r(null,s,i)}});async function Ht(n){let e=null;try{e=await Lr.default.stat(n)}catch{}return e}async function j2(n){if(!n)return!1;let e=await Ht(n);if(!e||!e.isFile())return!1;let t=null;try{let{stdout:r}=await DT.default.promisify(wT.exec)("git rev-parse --show-toplevel",{cwd:Gi.default.dirname(n)});t=r.trim()}catch{}if(!t)return!1;let i=Gi.default.relative(t,n);try{let{stdout:r}=await DT.default.promisify(wT.exec)(`git check-ignore ${i}`,{cwd:t});return r.trim()==i}catch{}return!1}function vT(n,e=[]){return!e||!e.length?!1:e.some(t=>(0,xT.default)(n,t,{dot:!0}))}function mb(n,e,t,i=!1,r=!0,o=[]){let s=yg(n);if(r&&t&&Ae(t,s,!0)&&!vT(t,o)&&pb(t,e))return t;let a=s.split(Gi.default.sep);if(i){for(;a.length>0;){let l=a.join(Gi.default.sep);if(!vT(l,o)&&pb(l,e))return l;a.pop()}return null}else{let l=[a.shift()];for(let u of a){l.push(u);let c=l.join(Gi.default.sep);if(!vT(c,o)&&pb(c,e))return c}return null}}async function A2(n,e,t=500){return new Promise((i,r)=>{let o=setTimeout(()=>{a.abort(),i(!1)},t),s=!1,a=(0,I2.default)(e,{nosort:!0,dot:!0,cwd:n,nodir:!0,absolute:!1},l=>{if(clearTimeout(o),l)return r(l);i(s)});a.on("match",()=>{clearTimeout(o),s=!0,a.abort(),i(!0)}),a.on("end",()=>{clearTimeout(o),i(s)})})}function pb(n,e){try{let t=Lr.default.readdirSync(n);for(let i of e)if(i.includes("*")?xT.default.match(t,i,{nobrace:!0,noext:!0,nocomment:!0,nonegate:!0,dot:!0}).length!==0:t.includes(i))return!0}catch{}return!1}function Dc(n,e){let t=Gi.default.parse(e).root,i=Array.isArray(n)?n:[n];for(;e&&e!==t;){if(pb(e,i))for(let o of i){let s=Gi.default.join(e,o);if(Lr.default.existsSync(s))return s}e=Gi.default.dirname(e)}return null}function xc(n,e){return new Promise((t,i)=>{Lr.default.readFile(n,e,(r,o)=>{r&&i(r),t(o)})})}function O2(n){let e,t=0;return new Promise((i,r)=>{Lr.default.createReadStream(n).on("error",o=>r(o)).on("data",o=>{for(e=0;ei(t))})}function ia(n,e,t){if(!Lr.default.existsSync(n))return Promise.reject(new Error(`file does not exist: ${n}`));let i=[],r=Lr.default.createReadStream(n,{encoding:"utf8"}),o=CT.default.createInterface({input:r,crlfDelay:1/0,terminal:!1}),s=0;return new Promise((a,l)=>{o.on("line",u=>{s>=e&&s<=t&&i.push(u),s==t&&o.close(),s=s+1}),o.on("close",()=>{a(i),r.close()}),o.on("error",l)})}function M2(n,e){if(!Lr.default.existsSync(n))return Promise.reject(new Error(`file does not exist: ${n}`));let t=Lr.default.createReadStream(n,{encoding:"utf8"}),i=CT.default.createInterface({input:t,crlfDelay:1/0,terminal:!1}),r=0;return new Promise((o,s)=>{i.on("line",a=>{if(r==e){r==0&&a.startsWith("\uFEFF")&&(a=a.slice(1)),i.close(),t.close(),o(a);return}r=r+1}),i.on("error",s)})}function ii(n,e,t){return t=typeof t=="boolean"?t:Xi||sc,!n||!e?!1:t?n.toLowerCase()===e.toLowerCase():n===e}function L2(n,e){return Xi||sc?n.toLowerCase().startsWith(e.toLowerCase()):n.startsWith(e)}async function bb(n,e){await Lr.default.writeFile(n,e,{encoding:"utf8"})}function vg(n){return n.startsWith("file:")}function Ae(n,e,t=!1){let i=yg(Gi.default.resolve(Gi.default.normalize(n))),r=yg(Gi.default.resolve(Gi.default.normalize(e)));return i=="//"&&(i="/"),ii(i,r)?!!t:i.endsWith(Gi.default.sep)?L2(r,i):L2(r,i)&&r[i.length]==Gi.default.sep}function yg(n,e=F2.default.platform()){return e!="win32"||n[1]!=":"?n:n[0].toUpperCase()+n.slice(1)}var wT,Lr,xT,F2,Gi,CT,DT,I2,VRe,Je=_(()=>{"use strict";wT=require("child_process"),Lr=C(Rn()),xT=C(Vn()),F2=C(require("os")),Gi=C(require("path")),CT=C(require("readline")),DT=C(require("util")),I2=C(gb());ac();VRe=q()("util-fs")});function Pi(n,e){return ut(n.start,e)===0&&ut(n.end,e)===0}function N2(n,e){return n.line===e.line&&n.character===e.character}function B2(n,e){let{start:t,end:i}=n;if(t.line>i.line||t.line===i.line&&t.character>i.character){let r=t;t=i,i=r}return t=Cc.Position.create(Math.max(0,t.line),Math.max(0,t.character)),i=Cc.Position.create(Math.max(0,i.line),Math.max(0,i.character)),{start:t,end:i}}function yb(n,e){return De(n.end,e.start)==0||De(e.end,n.start)==0}function Sc(n,e){let{start:t,end:i}=n;return!(De(i,e.start)<=0||De(t,e.end)>=0)}function Dl(n,e){return!!(ut(n.start,e)==0||ut(n.end,e)==0||Pi(e,n))}function H2(n,e){let{line:t,character:i}=e,{start:r,end:o}=n,s=o.line==r.line?o.character+i:o.character;return Cc.Range.create(r.line+t,i+r.character,o.line+t,s)}function q2(n,e){let{start:t,end:i}=e;return n>=t.line&&n<=i.line}function Ct(n){let{start:e,end:t}=n;return e.line==t.line&&e.character==t.character}function ut(n,e){let{start:t,end:i}=e;return De(n,t)<0?-1:De(n,i)>0?1:0}function De(n,e){return n.line>e.line||e.line==n.line&&n.character>e.character?1:e.line==n.line&&n.character==e.character?0:-1}function Y2(n){return n.start.line==n.end.line}function _i(n,e){let t=e.split(/\r?\n/),i=t.length,r=t[i-1],o=i==1?n.character+e.length:r.length;return Cc.Position.create(n.line+i-1,o)}var Cc,yt=_(()=>{"use strict";Cc=C(H())});var tLe,vb,W2=_(()=>{"use strict";tLe=q()("outpubChannel"),vb=class{constructor(e,t,i){this.name=e;this.nvim=t;this.onDispose=i;this.lines=[""];this._disposed=!1;this.created=!1;if(!/^[\w\s-.]+$/.test(e))throw new Error(`Invalid channel name "${e}", only word characters and white space allowed.`)}get content(){return this.lines.join(` -`)}_append(e){let{nvim:t}=this,i=this.lines.length-1,r=e.split(/\r?\n/),o=this.lines[i]+r[0];this.lines[i]=o;let s=r.slice(1);this.lines=this.lines.concat(s),this.created&&(t.pauseNotification(),t.call("setbufline",[this.bufname,"$",o],!0),s.length&&t.call("appendbufline",[this.bufname,"$",s],!0),t.resumeNotification(!1,!0))}append(e){!this.validate()||this._append(e)}appendLine(e){!this.validate()||this._append(e+` -`)}clear(e){if(!this.validate())return;let{nvim:t}=this;this.lines=e?this.lines.slice(-e):[],this.created&&(t.pauseNotification(),t.call("deletebufline",[this.bufname,1,"$"],!0),this.lines.length&&t.call("appendbufline",[this.bufname,"$",this.lines],!0),t.resumeNotification(!0,!0))}hide(){this.created=!1,this.nvim.command(`exe 'silent! bd! '.fnameescape('${this.bufname}')`,!0)}get bufname(){return`output:///${this.name}`}show(e,t="vs"){let{nvim:i}=this;i.pauseNotification(),i.command(`exe '${t} '.fnameescape('${this.bufname}')`,!0),e&&i.command("wincmd p",!0),i.resumeNotification(!0,!0),this.created=!0}validate(){return!this._disposed}dispose(){this.onDispose&&this.onDispose(),this._disposed=!0,this.hide(),this.lines=[]}}});var oLe,Z2,$o,wb=_(()=>{"use strict";le();W2();oLe=q()("core-channels"),Z2=class{constructor(){this.outputChannels=new Map;this.bufnrs=new Map;this.disposable=E.on("BufUnload",e=>{let t=this.bufnrs.get(e);if(t){let i=this.outputChannels.get(t);i&&(i.created=!1)}})}getProvider(e){return{onDidChange:null,provideTextDocumentContent:async i=>{let r=this.get(i.path.slice(1));if(!r)return"";e.pauseNotification(),e.call("bufnr",["%"],!0),e.command("setlocal nospell nofoldenable nowrap noswapfile",!0),e.command("setlocal buftype=nofile bufhidden=hide",!0),e.command("setfiletype log",!0);let o=await e.resumeNotification();return this.bufnrs.set(o[0][0],r.name),r.created=!0,r.content}}}get names(){return Array.from(this.outputChannels.keys())}get(e){return this.outputChannels.get(e)}create(e,t){if(this.outputChannels.has(e))return this.outputChannels.get(e);let i=new vb(e,t,()=>{this.outputChannels.delete(e)});return this.outputChannels.set(e,i),i}show(e,t,i){let r=this.outputChannels.get(e);!r||r.show(i,t)}dispose(){this.disposable.dispose();for(let e of this.outputChannels.values())e.dispose();this.outputChannels.clear()}},$o=new Z2});var aLe,Db,J2=_(()=>{"use strict";aLe=q()("model-terminal"),Db=class{constructor(e,t,i,r,o){this.cmd=e;this.args=t;this.nvim=i;this._name=r;this.strictEnv=o;this.pid=0}async start(e,t){let{nvim:i}=this,r=[this.cmd,...this.args],[o,s]=await i.call("coc#terminal#start",[r,e,t||{},!!this.strictEnv]);this.bufnr=o,this.pid=s}onExit(e){this.exitStatus={code:e===-1?void 0:e}}get name(){return this._name||this.cmd}get processId(){return Promise.resolve(this.pid)}sendText(e,t=!0){!this.bufnr||this.nvim.call("coc#terminal#send",[this.bufnr,e,t],!0)}async show(e){let{bufnr:t,nvim:i}=this;if(!t)return;let[r,o,s]=await i.eval(`[bufloaded(${t}),bufwinid(${t}),win_getid()]`);return r?(s==o||(i.pauseNotification(),o==-1?(i.command(`below ${t}sb`,!0),i.command("resize 8",!0),i.call("coc#util#do_autocmd",["CocTerminalOpen"],!0)):i.call("win_gotoid",[o],!0),i.command("normal! G",!0),e&&i.command("wincmd p",!0),await i.resumeNotification()),!0):!1}async hide(){let{bufnr:e,nvim:t}=this;!e||await t.eval(`coc#window#close(bufwinid(${e}))`)}dispose(){this.exitStatus||(this.exitStatus={code:void 0});let{bufnr:e,nvim:t}=this;!e||(this.bufnr=void 0,t.call("coc#terminal#close",[e],!0))}}});var ST,bbe,xb,$2=_(()=>{"use strict";J2();ST=C(H());z();le();bbe=q()("core-terminals"),xb=class{constructor(){this._terminals=new Map;this.disposables=[];this._onDidOpenTerminal=new ST.Emitter;this._onDidCloseTerminal=new ST.Emitter;this.onDidCloseTerminal=this._onDidCloseTerminal.event;this.onDidOpenTerminal=this._onDidOpenTerminal.event;E.on("BufUnload",e=>{if(this._terminals.has(e)){bbe.debug("terminal detach",e);let t=this._terminals.get(e);this._onDidCloseTerminal.fire(t),this._terminals.delete(e)}},null,this.disposables),E.on("TermExit",(e,t)=>{let i=this._terminals.get(e);i&&(i.onExit(t),i.dispose())},null,this.disposables)}get terminals(){return Array.from(this._terminals.values())}async createTerminal(e,t){let i=t.cwd,r=t.shellPath,o=t.shellArgs;r||(r=await e.getOption("shell")),i||(i=await e.call("getcwd"));let s=new Db(r,o||[],e,t.name,t.strictEnv);return await s.start(i,t.env),this._terminals.set(s.bufnr,s),this._onDidOpenTerminal.fire(s),s}reset(){for(let e of this._terminals.values())e.dispose();this._terminals.clear()}dispose(){this._onDidOpenTerminal.dispose(),this._onDidCloseTerminal.dispose(),Z(this.disposables),this.reset()}}});async function Cb(n){let[e,t]=await n.eval("[line('.')-1, strpart(getline('.'), 0, col('.') - 1)]");return Tc.Position.create(e,t.length)}async function Sb(n,e){return await n.callAsync("coc#dialog#prompt_confirm",[e])==1}async function X2(n,e,t){await n.call("coc#cursor#move_to",[e.line,e.character]),t&&n.command("redraw",!0)}async function U2(n){return await n.call("coc#cursor#char_offset")}async function G2(n){let[e,t]=await n.call("coc#cursor#screen_pos");return{row:e,col:t}}function Q2(n,e,t="MoreMsg",i=!1){n[i||ybe?"callTimer":"call"]("coc#ui#echo_messages",[t,("[coc.nvim] "+e).split(` -`)],!0)}async function K2(n,e){if(e==="line"){let i=await n.call("line",["."]);return Tc.Range.create(i-1,0,i,0)}if(e==="cursor"){let[i,r]=await n.eval("coc#cursor#position()");return Tc.Range.create(i,r,i,r)}let t=await n.call("coc#cursor#get_selection",[e==="char"?1:0]);return t?Tc.Range.create(t[0],t[1],t[2],t[3]):null}async function z2(n,e,t){let{start:i,end:r}=e,[o,s]=await n.eval(`[getline(${i.line+1}),getline(${r.line+1})]`),a=o.length>0?Q(o.slice(0,i.character)):0,l,u,c=r.character==0;if(c){u=r.line==0?0:r.line-1;let h=await n.call("getline",[u+1]);l=Q(h)}else u=r.line,l=s.length>0?Q(s.slice(0,r.character)):0;n.pauseNotification(),n.command(`noa call cursor(${i.line+1},${a+1})`,!0),n.command("normal! v",!0),n.command(`noa call cursor(${u+1},${l})`,!0),c&&n.command("normal! $",!0),await n.resumeNotification(t)}var Tc,ybe,Tb=_(()=>{"use strict";Tc=C(H());Pe();ybe=process.env.VIM_NODE_RPC=="1"});var kb,kT=_(()=>{kb="0.0.81"});var wg,Dg,Eb,Pb,xg,_b,Fr=_(()=>{"use strict";wg=(i=>(i[i.Buffer=0]="Buffer",i[i.LanguageServer=1]="LanguageServer",i[i.Global=2]="Global",i))(wg||{}),Dg=(i=>(i[i.Native=0]="Native",i[i.Remote=1]="Remote",i[i.Service=2]="Service",i))(Dg||{}),Eb=(i=>(i[i.More=0]="More",i[i.Warning=1]="Warning",i[i.Error=2]="Error",i))(Eb||{}),Pb=(i=>(i[i.Global=0]="Global",i[i.User=1]="User",i[i.Workspace=2]="Workspace",i))(Pb||{}),xg=(s=>(s[s.Initial=0]="Initial",s[s.Starting=1]="Starting",s[s.StartFailed=2]="StartFailed",s[s.Running=3]="Running",s[s.Stopping=4]="Stopping",s[s.Stopped=5]="Stopped",s))(xg||{}),_b=(r=>(r[r.Unknown=0]="Unknown",r[r.File=1]="File",r[r.Directory=2]="Directory",r[r.SymbolicLink=64]="SymbolicLink",r))(_b||{})});function ET(n,e){if(n.length<=1)return n;let t=n.length/2|0,i=n.slice(0,t),r=n.slice(t);ET(i,e),ET(r,e);let o=0,s=0,a=0;for(;ot.line||e.line===t.line&&e.character>t.character?{start:t,end:e}:n}function wbe(n){let e=eY(n.range);return e!==n.range?{newText:n.newText,range:e}:n}var kc,jn,Ec=_(()=>{"use strict";kc=class{constructor(e,t,i,r){this._uri=e,this._languageId=t,this._version=i,this._content=r,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){let t=this.offsetAt(e.start),i=this.offsetAt(e.end);return this._content.substring(t,i)}return this._content}update(e,t){for(let i of e)if(kc.isIncremental(i)){let r=eY(i.range),o=this.offsetAt(r.start),s=this.offsetAt(r.end);this._content=this._content.substring(0,o)+i.text+this._content.substring(s,this._content.length);let a=Math.max(r.start.line,0),l=Math.max(r.end.line,0),u=this._lineOffsets,c=V2(i.text,!1,o);if(l-a===c.length)for(let d=0,g=c.length;de?r=s:i=s+1}let o=i-1;return{line:o,character:e-t[o]}}offsetAt(e){let t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;let i=t[e.line],r=e.line+1{let d=c.range.start.line-h.range.start.line;return d===0?c.range.start.character-h.range.start.character:d}),l=0,u=[];for(let c of a){let h=r.offsetAt(c.range.start);if(hl&&u.push(s.substring(l,h)),c.newText.length&&u.push(c.newText),l=r.offsetAt(c.range.end)}return u.push(s.substr(l)),u.join("")}n.applyEdits=i})(jn||(jn={}))});function Sg(n,e){e===void 0&&(e=!1);var t=n.length,i=0,r="",o=0,s=16,a=0,l=0,u=0,c=0,h=0;function d(D,S){for(var F=0,L=0;F=48&&j<=57)L=L*16+j-48;else if(j>=65&&j<=70)L=L*16+j-65+10;else if(j>=97&&j<=102)L=L*16+j-97+10;else break;i++,F++}return F=t){D+=n.substring(S,i),h=2;break}var F=n.charCodeAt(i);if(F===34){D+=n.substring(S,i),i++;break}if(F===92){if(D+=n.substring(S,i),i++,i>=t){h=2;break}var L=n.charCodeAt(i++);switch(L){case 34:D+='"';break;case 92:D+="\\";break;case 47:D+="/";break;case 98:D+="\b";break;case 102:D+="\f";break;case 110:D+=` -`;break;case 114:D+="\r";break;case 116:D+=" ";break;case 117:var j=d(4,!0);j>=0?D+=String.fromCharCode(j):h=4;break;default:h=5}S=i;continue}if(F>=0&&F<=31)if(Cg(F)){D+=n.substring(S,i),h=2;break}else h=6;i++}return D}function b(){if(r="",h=0,o=i,l=a,c=u,i>=t)return o=t,s=17;var D=n.charCodeAt(i);if(PT(D)){do i++,r+=String.fromCharCode(D),D=n.charCodeAt(i);while(PT(D));return s=15}if(Cg(D))return i++,r+=String.fromCharCode(D),D===13&&n.charCodeAt(i)===10&&(i++,r+=` -`),a++,u=i,s=14;switch(D){case 123:return i++,s=1;case 125:return i++,s=2;case 91:return i++,s=3;case 93:return i++,s=4;case 58:return i++,s=6;case 44:return i++,s=5;case 34:return i++,r=p(),s=10;case 47:var S=i-1;if(n.charCodeAt(i+1)===47){for(i+=2;i=12&&D<=15);return D}return{setPosition:g,getPosition:function(){return i},scan:e?w:b,getToken:function(){return s},getTokenValue:function(){return r},getTokenOffset:function(){return o},getTokenLength:function(){return i-o},getTokenStartLine:function(){return l},getTokenStartCharacter:function(){return o-c},getTokenError:function(){return h}}}function PT(n){return n===32||n===9||n===11||n===12||n===160||n===5760||n>=8192&&n<=8203||n===8239||n===8287||n===12288||n===65279}function Cg(n){return n===10||n===13||n===8232||n===8233}function Pc(n){return n>=48&&n<=57}var Rb=_(()=>{"use strict"});function RT(n,e,t){var i,r,o,s,a;if(e){for(s=e.offset,a=s+e.length,o=s;o>0&&!Tg(n,o-1);)o--;for(var l=a;ls)&&n.substring(J,K)!==M&&v.push({offset:J,length:K-J,content:M})}var D=b();if(D!==17){var S=g.getTokenOffset()+o,F=_T(d,i);w(F,o,S)}for(;D!==17;){for(var L=g.getTokenOffset()+g.getTokenLength()+o,j=b(),W="",B=!1;!c&&(j===12||j===13);){var N=g.getTokenOffset()+o;w(" ",L,N),L=g.getTokenOffset()+g.getTokenLength()+o,B=j===12,W=B?p():"",j=b()}if(j===2)D!==1&&(h--,W=p());else if(j===4)D!==3&&(h--,W=p());else{switch(D){case 3:case 1:h++,W=p();break;case 5:case 12:W=p();break;case 13:c?W=p():B||(W=" ");break;case 6:B||(W=" ");break;case 10:if(j===6){B||(W="");break}case 7:case 8:case 9:case 11:case 2:case 4:j===12||j===13?B||(W=" "):j!==5&&j!==17&&(f=!0);break;case 16:f=!0;break}c&&(j===12||j===13)&&(W=p())}j===17&&(W=t.insertFinalNewline?u:"");var I=g.getTokenOffset()+o;w(W,L,I),D=j}return v}function _T(n,e){for(var t="",i=0;i{"use strict";Rb()});function tY(n,e,t){e===void 0&&(e=[]),t===void 0&&(t=kg.DEFAULT);var i=null,r=[],o=[];function s(l){Array.isArray(r)?r.push(l):i!==null&&(r[i]=l)}var a={onObjectBegin:function(){var l={};s(l),o.push(r),r=l,i=null},onObjectProperty:function(l){i=l},onObjectEnd:function(){r=o.pop()},onArrayBegin:function(){var l=[];s(l),o.push(r),r=l,i=null},onArrayEnd:function(){r=o.pop()},onLiteralValue:s,onError:function(l,u,c){e.push({error:l,offset:u,length:c})}};return IT(n,a,t),r[0]}function FT(n,e,t){e===void 0&&(e=[]),t===void 0&&(t=kg.DEFAULT);var i={type:"array",offset:-1,length:-1,children:[],parent:void 0};function r(l){i.type==="property"&&(i.length=l-i.offset,i=i.parent)}function o(l){return i.children.push(l),l}var s={onObjectBegin:function(l){i=o({type:"object",offset:l,length:-1,parent:i,children:[]})},onObjectProperty:function(l,u,c){i=o({type:"property",offset:u,length:-1,parent:i,children:[]}),i.children.push({type:"string",value:l,offset:u,length:c,parent:i})},onObjectEnd:function(l,u){r(l+u),i.length=l+u-i.offset,i=i.parent,r(l+u)},onArrayBegin:function(l,u){i=o({type:"array",offset:l,length:-1,parent:i,children:[]})},onArrayEnd:function(l,u){i.length=l+u-i.offset,i=i.parent,r(l+u)},onLiteralValue:function(l,u,c){o({type:Tbe(l),offset:u,length:c,parent:i,value:l}),r(u+c)},onSeparator:function(l,u,c){i.type==="property"&&(l===":"?i.colonOffset=u:l===","&&r(u))},onError:function(l,u,c){e.push({error:l,offset:u,length:c})}};IT(n,s,t);var a=i.children[0];return a&&delete a.parent,a}function Lb(n,e){if(!!n){for(var t=n,i=0,r=e;i=t.children.length)return;t=t.children[c]}}return t}}function IT(n,e,t){t===void 0&&(t=kg.DEFAULT);var i=Sg(n,!1);function r(B){return B?function(){return B(i.getTokenOffset(),i.getTokenLength(),i.getTokenStartLine(),i.getTokenStartCharacter())}:function(){return!0}}function o(B){return B?function(N){return B(N,i.getTokenOffset(),i.getTokenLength(),i.getTokenStartLine(),i.getTokenStartCharacter())}:function(){return!0}}var s=r(e.onObjectBegin),a=o(e.onObjectProperty),l=r(e.onObjectEnd),u=r(e.onArrayBegin),c=r(e.onArrayEnd),h=o(e.onLiteralValue),d=o(e.onSeparator),g=r(e.onComment),f=o(e.onError),p=t&&t.disallowComments,b=t&&t.allowTrailingComma;function v(){for(;;){var B=i.scan();switch(i.getTokenError()){case 4:w(14);break;case 5:w(15);break;case 3:w(13);break;case 1:p||w(11);break;case 2:w(12);break;case 6:w(16);break}switch(B){case 12:case 13:p?w(10):g();break;case 16:w(1);break;case 15:case 14:break;default:return B}}}function w(B,N,I){if(N===void 0&&(N=[]),I===void 0&&(I=[]),f(B),N.length+I.length>0)for(var M=i.getToken();M!==17;){if(N.indexOf(M)!==-1){v();break}else if(I.indexOf(M)!==-1)break;M=v()}}function D(B){var N=i.getTokenValue();return B?h(N):a(N),v(),!0}function S(){switch(i.getToken()){case 11:var B=i.getTokenValue(),N=Number(B);isNaN(N)&&(w(2),N=0),h(N);break;case 7:h(null);break;case 8:h(!0);break;case 9:h(!1);break;default:return!1}return v(),!0}function F(){return i.getToken()!==10?(w(3,[],[2,5]),!1):(D(!1),i.getToken()===6?(d(":"),v(),W()||w(4,[],[2,5])):w(5,[],[2,5]),!0)}function L(){s(),v();for(var B=!1;i.getToken()!==2&&i.getToken()!==17;){if(i.getToken()===5){if(B||w(4,[],[]),d(","),v(),i.getToken()===2&&b)break}else B&&w(6,[],[]);F()||w(4,[],[2,5]),B=!0}return l(),i.getToken()!==2?w(7,[2],[]):v(),!0}function j(){u(),v();for(var B=!1;i.getToken()!==4&&i.getToken()!==17;){if(i.getToken()===5){if(B||w(4,[],[]),d(","),v(),i.getToken()===4&&b)break}else B&&w(6,[],[]);W()||w(4,[],[4,5]),B=!0}return c(),i.getToken()!==4?w(8,[4],[]):v(),!0}function W(){switch(i.getToken()){case 3:return j();case 1:return L();case 10:return D(!0);default:return S()}}return v(),i.getToken()===17?t.allowEmptyContent?!0:(w(4,[],[]),!1):W()?(i.getToken()!==17&&w(9,[],[]),!0):(w(4,[],[]),!1)}function Tbe(n){switch(typeof n){case"boolean":return"boolean";case"number":return"number";case"string":return"string";case"object":{if(n){if(Array.isArray(n))return"array"}else return"null";return"object"}default:return"null"}}var kg,jT=_(()=>{"use strict";Rb();(function(n){n.DEFAULT={allowTrailingComma:!1}})(kg||(kg={}))});function iY(n,e,t,i){for(var r,o=e.slice(),s=[],a=FT(n,s),l=void 0,u=void 0;o.length>0&&(u=o.pop(),l=Lb(a,o),l===void 0&&t!==void 0);)typeof u=="string"?t=(r={},r[u]=t,r):t=[t];if(l)if(l.type==="object"&&typeof u=="string"&&Array.isArray(l.children)){var c=Lb(l,[u]);if(c!==void 0)if(t===void 0){if(!c.parent)throw new Error("Malformed AST");var h=l.children.indexOf(c.parent),d=void 0,g=c.parent.offset+c.parent.length;if(h>0){var f=l.children[h-1];d=f.offset+f.length}else if(d=l.offset+1,l.children.length>1){var p=l.children[1];g=p.offset}return xl(n,{offset:d,length:g-d,content:""},i)}else return xl(n,{offset:c.offset,length:c.length,content:JSON.stringify(t)},i);else{if(t===void 0)return[];var b=JSON.stringify(u)+": "+JSON.stringify(t),v=i.getInsertionIndex?i.getInsertionIndex(l.children.map(function(B){return B.children[0].value})):l.children.length,w=void 0;if(v>0){var f=l.children[v-1];w={offset:f.offset+f.length,length:0,content:","+b}}else l.children.length===0?w={offset:l.offset+1,length:0,content:b}:w={offset:l.offset+1,length:0,content:b+","};return xl(n,w,i)}}else if(l.type==="array"&&typeof u=="number"&&Array.isArray(l.children)){var D=u;if(D===-1){var b=""+JSON.stringify(t),w=void 0;if(l.children.length===0)w={offset:l.offset+1,length:0,content:b};else{var f=l.children[l.children.length-1];w={offset:f.offset+f.length,length:0,content:","+b}}return xl(n,w,i)}else if(t===void 0&&l.children.length>=0){var S=u,F=l.children[S],w=void 0;if(l.children.length===1)w={offset:l.offset+1,length:l.length-2,content:""};else if(l.children.length-1===S){var f=l.children[S-1],L=f.offset+f.length,j=l.offset+l.length;w={offset:L,length:j-2-L,content:""}}else w={offset:F.offset,length:l.children[S+1].offset-F.offset,content:""};return xl(n,w,i)}else if(t!==void 0){var w=void 0,b=""+JSON.stringify(t);if(!i.isArrayInsertion&&l.children.length>u){var W=l.children[u];w={offset:W.offset,length:W.length,content:b}}else if(l.children.length===0||u===0)w={offset:l.offset+1,length:0,content:l.children.length===0?b:b+","};else{var v=u>l.children.length?l.children.length:u,f=l.children[v-1];w={offset:f.offset+f.length,length:0,content:","+b}}return xl(n,w,i)}else throw new Error("Can not "+(t===void 0?"remove":i.isArrayInsertion?"insert":"modify")+" Array index "+D+" as length is not sufficient")}else throw new Error("Can not add "+(typeof u!="number"?"index":"property")+" to parent of type "+l.type);else{if(t===void 0)throw new Error("Can not delete in empty document");return xl(n,{offset:a?a.offset:0,length:a?a.length:0,content:JSON.stringify(t)},i)}}function xl(n,e,t){if(!t.formattingOptions)return[e];var i=Fb(n,e),r=e.offset,o=e.offset+e.content.length;if(e.length===0||e.content.length===0){for(;r>0&&!Tg(i,r-1);)r--;for(;o=0;a--){var l=s[a];i=Fb(i,l),r=Math.min(r,l.offset),o=Math.max(o,l.offset+l.length),o+=l.content.length-l.length}var u=n.length-(i.length-o)-r;return[{offset:r,length:u,content:i.substring(r,o)}]}function Fb(n,e){return n.substring(0,e.offset)+e.content+n.substring(e.offset+e.length)}var nY=_(()=>{"use strict";LT();jT()});function rY(n,e,t,i){return iY(n,e,t,i)}function oY(n,e){for(var t=e.length-1;t>=0;t--)n=Fb(n,e[t]);return n}var _c,Eg=_(()=>{"use strict";LT();nY();Rb();jT();_c=tY});function aY(n){let e={};for(let t of Object.keys(n))if(t.indexOf(".")==-1)e[t]=n[t];else{let i=t.split("."),r=e,o=i.length;for(let s=0;s"u"?t:o}function OT(){let n=Ab.default.join(_be,"data/schema.json"),e=Ib.default.readFileSync(n,"utf8"),{properties:t}=JSON.parse(e),i={};return Object.keys(t).forEach(r=>{let o=t[r].default;o!==void 0&&Pg(i,r,o,s=>{Pbe.error(s)})}),{contents:i}}function AT(n,e){let t=[];for(let i of Object.keys(n)){let r=n[i],o=e?`${e}.${i}`:i;t.push(o),_t(r)&&t.push(...AT(r,o))}return t}function hY(n,e){let t=[],i=AT(n),r=AT(e),o=r.filter(a=>!i.includes(a)),s=i.filter(a=>!r.includes(a));t.push(...o),t.push(...s);for(let a of i){if(!r.includes(a))continue;let l=jb(n,a),u=jb(e,a);Fe(l,u)||t.push(a)}return t}var sY,Ib,Ab,Pbe,_be,Ob=_(()=>{"use strict";sY=C(H());Ec();Eg();In();Jt();Ib=C(require("fs"));we();Ab=C(require("path")),Pbe=q()("configuration-util"),_be=(0,Ab.dirname)(__dirname)});var dn,MT=_(()=>{"use strict";In();Jt();Ob();dn=class{constructor(e={}){this._contents=e}get contents(){return this._contents}clone(){return new dn(Pr(this._contents))}getValue(e){return e?jb(this.contents,e):this.contents}merge(...e){let t=Pr(this.contents);for(let i of e)this.mergeContents(t,i.contents);return new dn(t)}freeze(){return Object.isFrozen(this._contents)||Object.freeze(this._contents),this}mergeContents(e,t){for(let i of Object.keys(t)){if(i in e&&_t(e[i])&&_t(t[i])){this.mergeContents(e[i],t[i]);continue}e[i]=Pr(t[i])}}setValue(e,t){Pg(this.contents,e,t,i=>{console.error(i)})}removeValue(e){uY(this.contents,e)}}});var Mb,dY=_(()=>{"use strict";MT();Mb=class{constructor(e,t,i,r=new dn){this._defaultConfiguration=e;this._userConfiguration=t;this._workspaceConfiguration=i;this._memoryConfiguration=r}getConsolidateConfiguration(){return this._consolidateConfiguration||(this._consolidateConfiguration=this._defaultConfiguration.merge(this._userConfiguration,this._workspaceConfiguration,this._memoryConfiguration),this._consolidateConfiguration=this._consolidateConfiguration.freeze()),this._consolidateConfiguration}getValue(e){return this.getConsolidateConfiguration().getValue(e)}inspect(e){let t=this.getConsolidateConfiguration(),{_workspaceConfiguration:i,_memoryConfiguration:r}=this;return{default:this._defaultConfiguration.freeze().getValue(e),user:this._userConfiguration.freeze().getValue(e),workspace:i.freeze().getValue(e),memory:r.freeze().getValue(e),value:t.getValue(e)}}get defaults(){return this._defaultConfiguration}get user(){return this._userConfiguration}get workspace(){return this._workspaceConfiguration}toData(){return{defaults:{contents:this._defaultConfiguration.contents},user:{contents:this._userConfiguration.contents},workspace:{contents:this._workspaceConfiguration.contents}}}}});function NT(n,e){if(e){if(n&&n.hasOwnProperty(e))return n[e];let t=e.split("."),i=n;for(let r=0;i&&r{"use strict";BT=C(require("fs")),gY=C(require("os")),no=C(require("path")),HT=C(H());we();Fr();z();Je();In();Jt();dY();MT();Ob();Rc=q()("configurations");Xo=class{constructor(e,t){this.userConfigFile=e;this._proxy=t;this.cwd=process.cwd();this._errorItems=[];this._folderConfigurations=new Map;this._onError=new HT.Emitter;this._onChange=new HT.Emitter;this.disposables=[];this.onError=this._onError.event;this.onDidChange=this._onChange.event;let i=this.parseContentFromFile(e),r={defaults:OT(),user:i,workspace:{contents:{}}};this._configuration=Xo.parse(r),this.watchFile(e,1),this.addFolderFromCwd()}parseContentFromFile(e){if(!e)return{contents:{}};let t=O.file(e).toString();this._errorItems=this._errorItems.filter(r=>r.location.uri!=t);let i=lY(e,r=>{this._errorItems.push(...r)});return this._onError.fire(this._errorItems),i}get errorItems(){return this._errorItems}get foldConfigurations(){return this._folderConfigurations}extendsDefaults(e){let{defaults:t}=this._configuration,{contents:i}=t;i=Pr(i),Object.keys(e).forEach(o=>{Pg(i,o,e[o],s=>{Rc.error(s)})});let r={defaults:{contents:i},user:this._configuration.user,workspace:this._configuration.workspace};this._configuration=Xo.parse(r)}updateUserConfig(e){if(!e||Object.keys(e).length==0)return;let{user:t}=this._configuration,i=t.clone();Object.keys(e).forEach(r=>{let o=e[r];if(o===void 0)i.removeValue(r);else if(_t(o))for(let s of Object.keys(o))i.setValue(`${r}.${s}`,o[s]);else i.setValue(r,o)}),this.changeConfiguration(1,i,void 0)}get defaults(){return this._configuration.defaults}get user(){return this._configuration.user}get workspace(){return this._configuration.workspace}addFolderFile(e,t=!0,i=!1){if(!BT.default.existsSync(e)||ii(this.userConfigFile,e)||ii(e,no.default.join(gY.default.homedir(),`.vim/${Er}`)))return!1;this._folderConfigurations.has(e)||this.watchFile(e,2);let r=this.updateFolderConfiguration(e);return Rc.info(`Add folder configuration from ${i?"cwd":"file"}:`,e),t&&this.workspaceConfigFile!==e&&(this.workspaceConfigFile=e,Rc.info(`Change folder configuration from ${i?"cwd":"file"} to:`,e),this.changeConfiguration(2,r,e)),!0}addFolderFromCwd(){let e=no.default.join(this.cwd,`.vim/${Er}`);this.addFolderFile(e,!0,!0)}watchFile(e,t){if(!BT.default.existsSync(e)||global.__TEST__)return;let i=t===2,r=lc(e,()=>{let o=this.parseContentFromFile(e);i?(this._folderConfigurations.set(e,new dn(o.contents)),ii(this.workspaceConfigFile,e)&&this.changeConfiguration(t,o,e)):this.changeConfiguration(t,o,e)});this.disposables.push(r)}updateFolderConfiguration(e){let t=this.parseContentFromFile(e);return this._folderConfigurations.set(e,new dn(t.contents)),t}changeConfiguration(e,t,i){let{defaults:r,user:o,workspace:s}=this._configuration,a={defaults:e==0?t:r,user:e==1?t:o,workspace:e==2?t:s},l=Xo.parse(a),u=hY(this._configuration.getValue(),l.getValue());u.length!=0&&(this._configuration=l,this._onChange.fire({affectsConfiguration:(c,h)=>{if(!h||!h.startsWith("file:")||e!=2)return u.includes(c);let g=O.parse(h).fsPath;return i&&!Ae(no.default.resolve(i,"../.."),g)?!1:u.includes(c)}}))}getFolderConfigFile(e){let{folders:t}=this,i=t.find(r=>Ae(r,e,!0));return i?no.default.join(i,`.vim/${Er}`):void 0}getConfigFile(e){return e==0?null:e==1?this.userConfigFile:this.workspaceConfigFile}get folders(){let e=[],{_folderConfigurations:t}=this;for(let i of t.keys())e.push(no.default.resolve(i,"../.."));return e}get configuration(){return this._configuration}getWorkspaceConfigUri(e){let t;return e||(t=this.workspaceConfigFile?O.file(this.workspaceConfigFile):void 0),!t&&this._proxy&&typeof this._proxy.getWorkspaceConfig=="function"&&(t=this._proxy.getWorkspaceConfig(e),t&&ii(this.userConfigFile,t.fsPath)&&(t=void 0)),t}getConfiguration(e,t){let i,r;if(t){let{defaults:a,user:l}=this._configuration,[u,c]=this.getFolderConfiguration(t);r=u,i=new Mb(a,l,c)}else r=this.workspaceConfigFile?O.file(this.workspaceConfigFile):void 0,i=this._configuration;let o=Object.freeze(NT(i.getValue(null),e)),s={has(a){return typeof NT(o,a)<"u"},get:(a,l)=>{let u=NT(o,a);return u==null?l:u},update:(a,l,u=!1)=>{let c=e?`${e}.${a}`:a,h=u?1:2,d=h==1?this.user.clone():this.workspace.clone();if(l===void 0?d.removeValue(c):d.setValue(c,l),r||(r=this.getWorkspaceConfigUri(t)),r&&!ii(this.workspaceConfigFile,r.fsPath)&&(Rc.info(`Change folder configuration ${t?"by "+t:""} to:`,r.fsPath),this.workspaceConfigFile=r.fsPath),this.changeConfiguration(h,d,h==2?this.workspaceConfigFile:this.userConfigFile),!u&&!r){global.__TEST__||console.error(`Unable to locate workspace configuration ${t?"for "+t:""}, workspace folder not resolved.`),Rc.error("Unable to locate workspace configuration",t);return}let g=u?O.parse(this.userConfigFile):r;this._proxy&&!global.__TEST__&&(l===void 0?this._proxy.$removeConfigurationOption(h,c,{resource:g}):this._proxy.$updateConfigurationOption(h,c,l,{resource:g})),!u&&r&&this.addFolderFile(r.fsPath,!1)},inspect:a=>{a=e?`${e}.${a}`:a;let l=this._configuration.inspect(a);return{key:a,defaultValue:l.default,globalValue:l.user,workspaceValue:l.workspace}}};return Object.defineProperty(s,"has",{enumerable:!1}),Object.defineProperty(s,"get",{enumerable:!1}),Object.defineProperty(s,"update",{enumerable:!1}),Object.defineProperty(s,"inspect",{enumerable:!1}),typeof o=="object"&&I0(s,o,!1),bH(s)}getFolderConfiguration(e){let t=O.parse(e),i;t.scheme!="file"?i=this.cwd:i=t.fsPath;for(let[r,o]of this.foldConfigurations){let s=no.default.resolve(r,"../..");if(Ae(s,i,!0))return[O.file(r),o]}return[void 0,new dn]}resolveFolderConfigution(e){let t=O.parse(e);if(t.scheme!="file")return;let i=no.default.dirname(t.fsPath),r=this.getFolderConfigFile(i);if(r)return r;let o=Dc(".vim",i);if(!o)return;let s=no.default.join(o,Er);if(!!this.addFolderFile(s,!1))return s}setFolderConfiguration(e){let t=O.parse(e);if(t.scheme!="file")return;let i=t.fsPath;for(let[r,o]of this.foldConfigurations){let s=no.default.resolve(r,"../..");if(Ae(s,i,!0)){this.workspaceConfigFile!=r&&(this.workspaceConfigFile=r,Rc.info("Change folder configuration to:",r),this.changeConfiguration(2,o,r));break}}}static parse(e){let t=new dn(e.defaults.contents),i=new dn(e.user.contents),r=new dn(e.workspace.contents);return new Mb(t,i,r,new dn)}reset(){this._errorItems=[],this._folderConfigurations.clear();let e=this.parseContentFromFile(this.userConfigFile),t={defaults:OT(),user:e,workspace:{contents:{}}};this._configuration=Xo.parse(t),this._onChange.fire({affectsConfiguration:()=>!0})}dispose(){this._folderConfigurations.clear(),this._onError.dispose(),this._onChange.dispose(),Z(this.disposables)}}});var _g,pY,qT,Fbe,Nb,mY=_(()=>{"use strict";_g=C(require("fs"));Eg();pY=C(require("os")),qT=C(require("path"));we();z();Je();Fbe=q()("configuration-shape"),Nb=class{constructor(e){this.resolver=e}modifyConfiguration(e,t,i){if(!e||e.scheme!=="file")return;Fbe.info("modify configuration file:",e.fsPath);let r=e.fsPath,o=qT.default.dirname(r),s={tabSize:2,insertSpaces:!0};_g.default.existsSync(o)||_g.default.mkdirSync(o,{recursive:!0});let a=_g.default.readFileSync(r,{encoding:"utf8",flag:"a+"});a=a||"{}";let l=rY(a,[t],i,{formattingOptions:s});a=oY(a,l),_g.default.writeFileSync(r,a,"utf8")}getWorkspaceConfig(e){let t;if(e){if(typeof this.resolver.getWorkspaceFolder=="function"){let i=this.resolver.getWorkspaceFolder(e);i&&(t=O.parse(i.uri).fsPath)}}else t=this.resolver.root;if(t&&!ii(t,pY.default.homedir()))return O.file(qT.default.join(t,".vim",Er))}$updateConfigurationOption(e,t,i,r){this.modifyConfiguration(r==null?void 0:r.resource,t,i)}$removeConfigurationOption(e,t,i){this.modifyConfiguration(i==null?void 0:i.resource,t)}}});var YT,bY,WT,yY,Ibe,Bb,vY=_(()=>{"use strict";YT=C(Rn()),bY=C(require("os")),WT=C(require("path")),yY=C(H());z();Ibe=q()("core-autocmds"),Bb=class{constructor(e,t){this.contentProvider=e;this.watchers=t;this._dynAutocmd=!1;this.autocmdMaxId=0;this.autocmds=new Map;this.disposables=[];this.contentProvider.onDidProviderChange(()=>{this.setupDynamicAutocmd()},null,this.disposables),this.watchers.onDidOptionChange(()=>{this.setupDynamicAutocmd()},null,this.disposables)}attach(e,t){this.nvim=e,this.env=t}async doAutocmd(e,t){let i=this.autocmds.get(e);if(i){let r=Array.isArray(i.event)?i.event.join(","):i.event;Ibe.debug(`invoke ${i.request?"request":"notify"} autocmd:`,r),await Promise.resolve(i.callback.apply(i.thisArg,t))}}registerAutocmd(e){this.autocmdMaxId+=1;let t=this.autocmdMaxId;return this.autocmds.set(t,e),this.setupDynamicAutocmd(),yY.Disposable.create(()=>{this.autocmds.delete(t),this.setupDynamicAutocmd()})}setupDynamicAutocmd(e=!1){if(!e&&!this._dynAutocmd)return;this._dynAutocmd=!0;let t=this.contentProvider.schemes,i=[];for(let o of t)i.push(`autocmd BufReadCmd,FileReadCmd,SourceCmd ${o}:/* call coc#rpc#request('CocAutocmd', ['BufReadCmd','${o}', expand('')])`);for(let[o,s]of this.autocmds.entries()){let a=s.arglist&&s.arglist.length?", "+s.arglist.join(", "):"",l=Array.isArray(s.event)?s.event.join(","):s.event,u=s.pattern!=null?s.pattern:"*";/\buser\b/i.test(l)&&(u=""),i.push(`autocmd ${l} ${u} call coc#rpc#${s.request?"request":"notify"}('doAutocmd', [${o}${a}])`)}for(let o of this.watchers.options)i.push(`autocmd OptionSet ${o} call coc#rpc#notify('OptionSet',[expand(''), v:option_old, v:option_new])`);let r=` -augroup coc_dynamic_autocmd - autocmd! - ${i.join(` - `)} -augroup end`;if(this.nvim.hasFunction("nvim_exec"))this.nvim.exec(r,!1);else{let o=WT.default.join(process.env.TMPDIR||bY.default.tmpdir(),`coc.nvim-${process.pid}.vim`);YT.default.mkdirSync(o,{recursive:!0});let s=WT.default.join(o,`coc-${process.pid}.vim`);YT.default.writeFileSync(s,r,"utf8");let a=`source ${s}`;this.env.isCygwin&&Wo.isWindows&&(a=`execute "source" . substitute(system('cygpath ${s.replace(/\\/g,"/")}'), '\\n', '', 'g')`),this.nvim.command(a)}}dispose(){this.nvim.command("augroup coc_dynamic_autocmd| autocmd!|augroup end",!0),Z(this.disposables)}}});var Cl,Hb,wY=_(()=>{"use strict";Cl=C(H());we();le();z();Hb=class{constructor(e){this.documents=e;this.disposables=[];this.providers=new Map;this._onDidProviderChange=new Cl.Emitter;this.onDidProviderChange=this._onDidProviderChange.event}attach(e){this.nvim=e,E.on("BufReadCmd",this.onBufReadCmd,this,this.disposables)}get schemes(){return Array.from(this.providers.keys())}async onBufReadCmd(e,t){let i=this.providers.get(e);if(!i)return;let r=new Cl.CancellationTokenSource,o=await Promise.resolve(i.provideTextDocumentContent(O.parse(t),r.token)),s=await this.nvim.buffer;await s.setLines(o.split(/\r?\n/),{start:0,end:-1,strictIndexing:!1}),process.nextTick(()=>{E.fire("BufCreate",[s.id])})}registerTextDocumentContentProvider(e,t){this.providers.set(e,t),this._onDidProviderChange.fire();let i=[];return t.onDidChange&&t.onDidChange(async r=>{let{buffer:o}=this.documents.getDocument(r.toString()),s=new Cl.CancellationTokenSource,a=await Promise.resolve(t.provideTextDocumentContent(r,s.token));await o.setLines(a.split(/\r?\n/),{start:0,end:-1,strictIndexing:!1})},null,i),Cl.Disposable.create(()=>{this.providers.delete(e),Z(i),this._onDidProviderChange.fire()})}dispose(){Z(this.disposables),this._onDidProviderChange.dispose(),this.providers.clear()}}});var CY=m((xFe,qb)=>{"use strict";qb.exports=Mbe;qb.exports.format=DY;qb.exports.parse=xY;var jbe=/\B(?=(\d{3})+(?!\d))/g,Abe=/(?:\.0*|(\.[^0]+)0+)$/,na={b:1,kb:1<<10,mb:1<<20,gb:1<<30,tb:Math.pow(1024,4),pb:Math.pow(1024,5)},Obe=/^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;function Mbe(n,e){return typeof n=="string"?xY(n):typeof n=="number"?DY(n,e):null}function DY(n,e){if(!Number.isFinite(n))return null;var t=Math.abs(n),i=e&&e.thousandsSeparator||"",r=e&&e.unitSeparator||"",o=e&&e.decimalPlaces!==void 0?e.decimalPlaces:2,s=Boolean(e&&e.fixedDecimals),a=e&&e.unit||"";(!a||!na[a.toLowerCase()])&&(t>=na.pb?a="PB":t>=na.tb?a="TB":t>=na.gb?a="GB":t>=na.mb?a="MB":t>=na.kb?a="KB":a="B");var l=n/na[a.toLowerCase()],u=l.toFixed(o);return s||(u=u.replace(Abe,"$1")),i&&(u=u.replace(jbe,i)),u+r+a}function xY(n){if(typeof n=="number"&&!isNaN(n))return n;if(typeof n!="string")return null;var e=Obe.exec(n),t,i="b";return e?(t=parseFloat(e[1]),i=e[4].toLowerCase()):(t=parseInt(n,10),i="b"),Math.floor(na[i]*t)}});var Lg=m((CFe,RY)=>{var ro=-1,Ir=1,gn=0;function Rg(n,e,t,i){if(n===e)return n?[[gn,n]]:[];if(t!=null){var r=Ybe(n,e,t);if(r)return r}var o=JT(n,e),s=n.substring(0,o);n=n.substring(o),e=e.substring(o),o=$T(n,e);var a=n.substring(n.length-o);n=n.substring(0,n.length-o),e=e.substring(0,e.length-o);var l=Nbe(n,e);return s&&l.unshift([gn,s]),a&&l.push([gn,a]),TY(l,i),l}function Nbe(n,e){var t;if(!n)return[[Ir,e]];if(!e)return[[ro,n]];var i=n.length>e.length?n:e,r=n.length>e.length?e:n,o=i.indexOf(r);if(o!==-1)return t=[[Ir,i.substring(0,o)],[gn,r],[Ir,i.substring(o+r.length)]],n.length>e.length&&(t[0][0]=t[2][0]=ro),t;if(r.length===1)return[[ro,n],[Ir,e]];var s=Hbe(n,e);if(s){var a=s[0],l=s[1],u=s[2],c=s[3],h=s[4],d=Rg(a,u),g=Rg(l,c);return d.concat([[gn,h]],g)}return Bbe(n,e)}function Bbe(n,e){for(var t=n.length,i=e.length,r=Math.ceil((t+i)/2),o=r,s=2*r,a=new Array(s),l=new Array(s),u=0;ut)g+=2;else if(S>i)d+=2;else if(h){var F=o+c-v;if(F>=0&&F=L)return SY(n,e,D,S)}}}for(var j=-b+f;j<=b-p;j+=2){var F=o+j,L;j===-b||j!==b&&l[F-1]t)p+=2;else if(W>i)f+=2;else if(!h){var w=o+c-j;if(w>=0&&w=L)return SY(n,e,D,S)}}}}return[[ro,n],[Ir,e]]}function SY(n,e,t,i){var r=n.substring(0,t),o=e.substring(0,i),s=n.substring(t),a=e.substring(i),l=Rg(r,o),u=Rg(s,a);return l.concat(u)}function JT(n,e){if(!n||!e||n.charAt(0)!==e.charAt(0))return 0;for(var t=0,i=Math.min(n.length,e.length),r=i,o=0;te.length?n:e,i=n.length>e.length?e:n;if(t.length<4||i.length*2=g.length?[D,S,F,L,w]:null}var o=r(t,i,Math.ceil(t.length/4)),s=r(t,i,Math.ceil(t.length/2)),a;if(!o&&!s)return null;s?o?a=o[4].length>s[4].length?o:s:a=s:a=o;var l,u,c,h;n.length>e.length?(l=a[0],u=a[1],c=a[2],h=a[3]):(c=a[0],h=a[1],l=a[2],u=a[3]);var d=a[4];return[l,u,c,h,d]}function TY(n,e){n.push([gn,""]);for(var t=0,i=0,r=0,o="",s="",a;t=0&&_Y(n[l][1])){var u=n[l][1].slice(-1);if(n[l][1]=n[l][1].slice(0,-1),o=u+o,s=u+s,!n[l][1]){n.splice(l,1),t--;var c=l-1;n[c]&&n[c][0]===Ir&&(r++,s=n[c][1]+s,c--),n[c]&&n[c][0]===ro&&(i++,o=n[c][1]+o,c--),l=c}}if(PY(n[t][1])){var u=n[t][1].charAt(0);n[t][1]=n[t][1].slice(1),o+=u,s+=u}}if(t0||s.length>0){o.length>0&&s.length>0&&(a=JT(s,o),a!==0&&(l>=0?n[l][1]+=s.substring(0,a):(n.splice(0,0,[gn,s.substring(0,a)]),t++),s=s.substring(a),o=o.substring(a)),a=$T(s,o),a!==0&&(n[t][1]=s.substring(s.length-a)+n[t][1],s=s.substring(0,s.length-a),o=o.substring(0,o.length-a)));var h=r+i;o.length===0&&s.length===0?(n.splice(t-h,h),t=t-h):o.length===0?(n.splice(t-h,h,[Ir,s]),t=t-h+1):s.length===0?(n.splice(t-h,h,[ro,o]),t=t-h+1):(n.splice(t-h,h,[ro,o],[Ir,s]),t=t-h+2)}t!==0&&n[t-1][0]===gn?(n[t-1][1]+=n[t][1],n.splice(t,1)):t++,r=0,i=0,o="",s="";break}}n[n.length-1][1]===""&&n.pop();var d=!1;for(t=1;t=55296&&n<=56319}function EY(n){return n>=56320&&n<=57343}function PY(n){return EY(n.charCodeAt(0))}function _Y(n){return kY(n.charCodeAt(n.length-1))}function qbe(n){for(var e=[],t=0;t0&&e.push(n[t]);return e}function ZT(n,e,t,i){return _Y(n)||PY(i)?null:qbe([[gn,n],[ro,e],[Ir,t],[gn,i]])}function Ybe(n,e,t){var i=typeof t=="number"?{index:t,length:0}:t.oldRange,r=typeof t=="number"?null:t.newRange,o=n.length,s=e.length;if(i.length===0&&(r===null||r.length===0)){var a=i.index,l=n.slice(0,a),u=n.slice(a),c=r?r.index:null;e:{var h=a+s-o;if(c!==null&&c!==h||h<0||h>s)break e;var d=e.slice(0,h),g=e.slice(h);if(g!==u)break e;var f=Math.min(a,h),p=l.slice(0,f),b=d.slice(0,f);if(p!==b)break e;var v=l.slice(f),w=d.slice(f);return ZT(p,v,w,u)}e:{if(c!==null&&c!==a)break e;var D=a,d=e.slice(0,D),g=e.slice(D);if(d!==l)break e;var S=Math.min(o-D,s-D),F=u.slice(u.length-S),L=g.slice(g.length-S);if(F!==L)break e;var v=u.slice(0,u.length-S),w=g.slice(0,g.length-S);return ZT(l,v,w,F)}}if(i.length>0&&r&&r.length===0){e:{var p=n.slice(0,i.index),F=n.slice(i.index+i.length),f=p.length,S=F.length;if(sr&&s.length){let l=0;for(let u=0;u=b&&v!==p&&(v+=1);let w=0;for(let F=0;F0?h.join(` -`)+` -`:"";if(!(d.length===0&&a===r-c))return un.replace(Ne.create(a,0,r-c,0),d)}var Wb,kFe,XT=_(()=>{"use strict";Wb=C(Lg());Qr();Pe();kFe=q()("util-diff")});function ra(n){let{newText:e}=n,t=Zb(n.range),i=t.end.line-t.start.line;return e.split(/\r?\n/).length-i-1}function Zb(n){let e=n.start,t=n.end;return e.line>t.line||e.line===t.line&&e.character>t.character?{start:t,end:e}:n}function Fg(n,e){if(n.length<=1)return n;let t=n.length/2|0,i=n.slice(0,t),r=n.slice(t);Fg(i,e),Fg(r,e);let o=0,s=0,a=0;for(;o0&&i.character==0,o;for(let s=0;s0){let h=t[t.length-1];h.newText=l,o=void 0;continue}o=void 0}l.includes("\r")&&(l=l.replace(/\r\n/g,` -`));let c=De(u.end,i);if(c>0&&(u.end={line:i.line,character:i.character}),n.getText(u)!==l){if(c===0&&r&&!Ct(u)&&l.endsWith(` -`)){l=l.slice(0,-1);let h=n.lines[i.line-1];u.end=er.Position.create(i.line-1,h.length)}else l.length==0&&(o=u.start);t.push({range:u,newText:l})}}return Fg(t,(s,a)=>{let l=s.range.start.line-a.range.start.line;return l===0?s.range.start.character-a.range.start.character:l})}function NY(n,e){var s,a;if(e.length==1){let{start:l,end:u}=e[0].range,{lines:c}=n,h=(s=c[l.line])!=null?s:"",d=(a=c[u.line])!=null?a:"",g=h.substring(0,l.character)+e[0].newText+d.substring(u.character);return u.line>=c.length&&n.eol?g==""?[...c.slice(0,l.line)]:(g.endsWith(` -`)&&(g=g.slice(0,-1)),[...c.slice(0,l.line),...g.split(` -`)]):[...c.slice(0,l.line),...g.split(` -`),...c.slice(u.line+1)]}let t=n.getText(),i=0,r=[];for(let l of e){let u=n.offsetAt(l.range.start);if(ui&&r.push(t.substring(i,u)),l.newText.length&&r.push(l.newText),i=n.offsetAt(l.range.end)}r.push(t.substring(i));let o=r.join("");if(o!==t)return DH(o,n.eol)}function BY(n,e){return e.map(t=>{var c,h;let{start:i,end:r}=t.range,o=(c=n[i.line])!=null?c:"",s=Q(o.slice(0,i.character)),a=r.line==i.line?o:(h=n[r.line])!=null?h:"",l=Q(a.slice(0,r.character)),{newText:u}=t;return[u.length>0?u.split(` -`):[],i.line,s,r.line,l]})}function Jb(n,e){let{range:t,newText:i}=e;if(De(t.end,n)<=0){let r=i.split(` -`),o=r.length-(t.end.line-t.start.line)-1,s=n.character;if(t.end.line==n.line){let a=r[r.length-1].length;r.length>1?s=a+s-t.end.character:s=t.start.character+a+s-t.end.character}return{line:o,character:s-n.character}}return{line:0,character:0}}function $b(n,e){let{line:t,character:i}=n,{range:r,newText:o}=e,{end:s}=r,a=o.split(` -`),l=a.length-(s.line-r.start.line)-1,u=r.end.line-n.line;if(u>0)return{line:t,character:i};if(u<0)return{line:t+l,character:i};if(a.length>1){let h=a[a.length-1].length;return{line:t+l,character:h+i-s.character}}let c=r.start.character-r.end.character;return{line:t+l,character:c+o.length+i}}function Xb(n,e){let t=er.Position.create(n.line,n.character),i=!1;for(let r=e.length-1;r>=0;r--){let o=e[r];if(i){t.line+=ra(o);continue}De(o.range.end,t)>0||(o.range.end.line==t.line?t=$b(t,o):(i=!0,t.line+=ra(o)))}return t}function UT(n,e){let t=0;for(let i of e){let r=Zb(i.range);De(r.end,n)<=0&&(t+=ra(i))}return t}function HY(n,e,t){var c,h;let i=n[0].range.start,r=n[n.length-1].range.end,o=e.length-r.line,s=((c=e[r.line])!=null?c:"").length-r.character,a=t.length-o,l=((h=t[a])!=null?h:"").length-s,u=Wbe(i,er.Position.create(a,l),t);return er.TextEdit.replace(er.Range.create(i,r),u)}function Wbe(n,e,t){var r,o;if(n.line===e.line)return((r=t[n.line])!=null?r:"").slice(n.character,e.character);let i=[];for(let s=n.line;s<=e.line;s++){let a=(o=t[s])!=null?o:"";s===n.line?i.push(a.slice(n.character)):s===e.line?i.push(a.slice(0,e.character)):i.push(a)}return i.join(` -`)}var er,jr=_(()=>{"use strict";er=C(H());yt();Pe()});var GT,OFe,tr,jg,qY=_(()=>{"use strict";GT=C(H());z();Ec();OFe=q()("model-chars"),tr=class{constructor(e,t){this.start=e,this.end=t||e}static fromKeywordOption(e){let t=e.split(","),i=[];i.push(new tr(65,90)),i.push(new tr(97,122));for(let r of t)if(r=="@")i.push(new tr(256,65535));else if(r=="@-@")i.push(new tr(64));else if(/^\d+-\d+$/.test(r)){let o=r.match(/^(\d+)-(\d+)$/);i.push(new tr(Number(o[1]),Number(o[2])))}else if(/^\d+$/.test(r))i.push(new tr(Number(r)));else{let o=r.charCodeAt(0);i.some(s=>s.contains(o))||i.push(new tr(o))}return i}contains(e){return e>=this.start&&e<=this.end}},jg=class{constructor(e){this.ranges=[];e&&(this.ranges=tr.fromKeywordOption(e))}addKeyword(e){let t=e.charCodeAt(0),{ranges:i}=this;i.some(r=>r.contains(t))||i.push(new tr(t))}clone(){let e=new jg;return e.ranges=this.ranges.slice(),e}setKeywordOption(e){this.ranges=tr.fromKeywordOption(e)}async matchLines(e,t=2,i){let r=new Set,o=Date.now();for(let s of e){if(s.length===0)continue;let a="";Date.now()-o>15&&(await zr(),o=Date.now());for(let l of s){if(i&&i.isCancellationRequested)return;let u=l.codePointAt(0);this.isKeywordCode(u)?a=a+l:a.length>0&&(a.length>=t&&a.length<48&&r.add(a),a="")}a.length>=t&&a.length<48&&r.add(a)}return r}isKeywordCode(e){return e>255?!0:e<33?!1:this.ranges.some(t=>t.contains(e))}isKeywordChar(e){let{ranges:t}=this;if(/\s/.test(e))return!1;let i=e.charCodeAt(0);return i<33?!1:t.some(r=>r.contains(i))}isKeyword(e){for(let t=0,i=e.length;tr){let p=l.length,b=!1;for(;a>e.line+1;){let v=i[a-1].length;if(p-v1){let v=l.substring(g,p);o.set(v,p/c)}f=b}g=h-d,f=!1;for(let p=g;p1){let v=p==h-1?p+1:p,w=l.substring(g,v),D=o.get(w)||0,S=h-p+(v-g);S!==d&&o.set(w,Math.max(D,S/d))}f=b}return o}}});var QT,KT,YY=_(()=>{"use strict";QT=C(H()),KT=class{constructor(e,t,i){this._line=e,this._text=t,this._isLastLine=i}get lineNumber(){return this._line}get text(){return this._text}get range(){return QT.Range.create(this._line,0,this._line,this._text.length)}get rangeIncludingLineBreak(){return this._isLastLine?this.range:QT.Range.create(this._line,0,this._line+1,0)}get firstNonWhitespaceCharacterIndex(){return/^(\s*)/.exec(this._text)[1].length}get isEmptyOrWhitespace(){return this.firstNonWhitespaceCharacterIndex===this._text.length}}});function Zbe(n,e){let t=[],i=0;for(let r of n)t.push(i),i+=r.length+1;return e&&t.push(i),t}var Ub,Ag,WY=_(()=>{"use strict";Ub=C(H());YY();Ag=class{constructor(e,t,i,r,o,s){this.uri=e;this.languageId=t;this.version=i;this.lines=r;this.bufnr=o;this.eol=s}get content(){return this._content||(this._content=this.lines.join(` -`)+(this.eol?` -`:"")),this._content}get length(){if(!this._content){let e=this.lines.reduce((t,i)=>t+i.length+1,0);return this.eol?e:e-1}return this._content.length}get end(){let e=this.lineCount-1;return this.eol?Ub.Position.create(e,0):Ub.Position.create(e,this.lines[e].length)}get lineCount(){return this.lines.length+(this.eol?1:0)}getText(e){var t;if(e){let{start:i,end:r}=e;return i.line===r.line?i.character===r.character?"":((t=this.lines[i.line])!=null?t:"").substring(i.character,r.character):this.content.substring(this.offsetAt(e.start),this.offsetAt(e.end))}return this.content}lineAt(e){var i;let t=Ub.Position.is(e)?e.line:e;if(typeof t!="number"||t<0||t>=this.lineCount||Math.floor(t)!==t)throw new Error("Illegal value for `line`");return new KT(t,(i=this.lines[t])!=null?i:"",t===this.lineCount-1)}positionAt(e){e=Math.max(Math.min(e,this.content.length),0);let t=this.getLineOffsets(),i=0,r=t.length;if(r===0)return{line:0,character:e};for(;ie?r=s:i=s+1}let o=i-1;return{line:o,character:e-t[o]}}offsetAt(e){let t=this.getLineOffsets();if(e.line>=t.length)return this.content.length;if(e.line<0)return 0;let i=t[e.line],r=e.line+1{"use strict";VT=C(Ei()),ir=C(H());we();le();XT();z();Jt();yt();Pe();jr();qY();WY();nIe=q()("model-document"),Gb=class{constructor(e,t,i,r){this.buffer=e;this.env=t;this.nvim=i;this.isIgnored=!1;this.eol=!0;this._disposed=!1;this._attached=!1;this._previewwindow=!1;this._winid=-1;this.disposables=[];this.lines=[];this._onDocumentChange=new ir.Emitter;this.onDocumentChange=this._onDocumentChange.event;this.fireContentChanges=(0,VT.default)(()=>{this._fireContentChanges()},global.__TEST__?20:150),this.fetchContent=(0,VT.default)(()=>{this._fetchContent()},100),this.init(r)}get content(){return this.syncLines.join(` -`)+(this.eol?` -`:"")}get attached(){return this._attached}get textDocument(){return this._textDocument}get syncLines(){return this._textDocument.lines}get version(){return this._textDocument.version}get bufnr(){return this.buffer.id}get bufname(){return this._bufname}get filetype(){return this._filetype}get uri(){return this._uri}get isCommandLine(){return this.uri&&this.uri.endsWith("%5BCommand%20Line%5D")}get enabled(){return this.getVar("enabled",!0)}get languageId(){let{_filetype:e}=this;return e.includes(".")?e.match(/(.*?)\./)[1]:e}get changedtick(){return this._changedtick}convertFiletype(e){switch(e){case"javascript.jsx":return"javascriptreact";case"typescript.jsx":case"typescript.tsx":return"typescriptreact";case"tex":return"latex";default:{let t=this.env.filetypeMap;return String(t[e]||e)}}}get schema(){return O.parse(this.uri).scheme}get lineCount(){return this.lines.length}get winid(){return this._winid}get indentkeys(){return this._indentkeys}get previewwindow(){return this._previewwindow}init(e){let t=this.buftype=e.buftype;this._indentkeys=e.indentkeys,this._bufname=e.bufname,this._previewwindow=!!e.previewwindow,this._winid=e.winid,this.variables=e.variables||{},this._changedtick=e.changedtick,this.eol=e.eol==1,this._uri=tb(e.fullpath,this.bufnr,t,this.env.isCygwin),Array.isArray(e.lines)&&(this.lines=e.lines,this._noFetch=!0,this._attached=!0,this.attach()),this._filetype=this.convertFiletype(e.filetype),this.setIskeyword(e.iskeyword),this.createTextDocument(1,this.lines)}attach(){if(this.env.isVim)return;let e=this.lines;this.buffer.attach(!0).then(t=>{t||zT(this.bufnr)},t=>{zT(this.bufnr)}),this.buffer.listen("lines",(t,i,r,o,s)=>{if(!(t.id!==this.bufnr||!this._attached||i==null)&&i>this._changedtick){if(this._changedtick=i,e=[...e.slice(0,r),...s,...o==-1?[]:e.slice(o)],e.length==0&&(e=[""]),this.lines=e,Lc(t.id),E.pumvisible)return;this.fireContentChanges()}},this.disposables),this.buffer.listen("detach",()=>{zT(this.bufnr)},this.disposables)}get dirty(){return this.lines!==this.syncLines}get hasChanged(){return this.dirty?!Fe(this.lines,this.syncLines):!1}_fireContentChanges(e){var s;if(this.lines===this.syncLines)return;let t=this._textDocument,i=[];if(!e){let{cursor:a,insertMode:l}=E,u;if(a&&a.bufnr==this.bufnr){let c=(s=this.lines[a.lnum-1])!=null?s:"";u=ir.Position.create(a.lnum-1,Ui(c,a.col-1))}e=IY(t.lines,this.lines,u,l)}let r;e?(r=t.getText(e.range),i.push({range:e.range,text:e.newText,rangeLength:r.length})):r="";let o=this.createTextDocument(this.version+(e?1:0),this.lines);this._onDocumentChange.fire(Object.freeze({bufnr:this.bufnr,original:r,originalLines:t.lines,textDocument:{version:o.version,uri:this.uri},contentChanges:i}))}async applyEdits(e,t=!1,i=!1){var b,v;if(Array.isArray(arguments[1])&&(e=arguments[1]),!this._attached||e.length===0)return;this._forceSync();let r=this.textDocument;if(e=MY(r,e),e.length===0)return;let o=NY(r,e);if(!o)return;let s=r.lines,a=LY(s,o,e[0].range.start.line);if(a.start===a.end&&a.replacement.length==0)return;let l=a.start===a.end&&a.start===s.length+(this.eol?0:1),u=s.slice(a.start,a.end),c=[];this.nvim.hasFunction("nvim_buf_set_text")&&e.length<200&&a.start!==a.end&&e[e.length-1].range.end.line=0;){let u=o[a-1];if(!u||!r.isKeywordChar(u))break;a=a-1}for(;l<=o.length;){let u=o[l];if(!u||!r.isKeywordChar(u))break;l=l+1}return ir.Range.create(e.line,a,e.line,l)}createTextDocument(e,t){let{uri:i,languageId:r,eol:o}=this;return this._textDocument=new Ag(i,r,e,t,this.bufnr,o)}async _fetchContent(e){if(!this.env.isVim||!this._attached)return;let{nvim:t,bufnr:i,changedtick:r}=this,o=await t.call("coc#util#get_buf_lines",[i,r]);this._noFetch=!0,o?(this._changedtick=o.changedtick,this.lines=o.lines,Lc(this.bufnr),e?this._forceSync():this.fireContentChanges()):e&&this._forceSync()}changeLine(e,t,i){if(this.lines[e-1]===void 0)return;let o=this.lines.slice();o[e-1]=t,this.lines=o,Lc(this.bufnr),this._changedtick=i}async patchChange(e){if(!!this._attached)if(this.env.isVim)if(e){let t=await this.nvim.call("coc#util#get_changeinfo",[]);if(t.bufnr!==this.bufnr)return;if(t.changedtick0&&!d&&l==e&&s.push(ir.Range.create(o.positionAt(u-l.length),o.positionAt(u))),d||(l="")}return s}fixStartcol(e,t){let i=this.getline(e.line);if(!i)return null;let{character:r}=e,o=i.slice(0,r),s=Q(o),{chars:a}=this;for(let l=o.length-1;l>=0;l--){let u=o[l];if(u==" "||!a.isKeywordChar(u)&&!t.includes(u))break;s=s-Q(u)}return s}addHighlights(e,t,i,r={}){let{start:o,end:s}=i;if(!Ct(i))for(let a=o.line;a<=s.line;a++){let l=this.getline(a,!1),u=a==o.line?Ze(l,o.character):0,c=a==s.line?Ze(l,s.character):global.Buffer.byteLength(l);u>=c||e.push(Object.assign({hlGroup:t,lnum:a,colStart:u,colEnd:c},r))}}getline(e,t=!0){return t?this.lines[e]||"":this.syncLines[e]||""}getLines(e,t){return this.lines.slice(e!=null?e:0,t!=null?t:this.lines.length)}getDocumentContent(){let e=this.lines.join(` -`);return this.eol?e+` -`:e}getVar(e,t){let i=this.variables[`coc_${e}`];return i===void 0?t:i}getPosition(e,t){let i=this.getline(e-1);if(!i||t==0)return{line:e-1,character:0};let r=et(i,0,t-1);return{line:e-1,character:r.length}}getEndOffset(e,t,i){let r=0,o=this.lines.length;for(let s=e-1;s{"use strict";JY=C(CY()),ek=C(require("fs")),tk=C(require("os")),Sl=C(require("path")),fn=C(H());we();le();ZY();z();Je();Pe();Qb=q()("core-documents"),Kb=class{constructor(e,t){this.configurations=e;this.workspaceFolder=t;this._initialized=!1;this._attached=!1;this._currentResolve=!1;this.disposables=[];this.creating=new Map;this.buffers=new Map;this.winids=new Set;this.resolves=[];this._onDidOpenTextDocument=new fn.Emitter;this._onDidCloseDocument=new fn.Emitter;this._onDidChangeDocument=new fn.Emitter;this._onDidSaveDocument=new fn.Emitter;this._onWillSaveDocument=new fn.Emitter;this.onDidOpenTextDocument=this._onDidOpenTextDocument.event;this.onDidCloseDocument=this._onDidCloseDocument.event;this.onDidChangeDocument=this._onDidChangeDocument.event;this.onDidSaveTextDocument=this._onDidSaveDocument.event;this.onWillSaveTextDocument=this._onWillSaveDocument.event;this._cwd=process.cwd()}async attach(e,t){if(this._attached)return;this.nvim=e,this._env=t,this._attached=!0;let r=this.configurations.getConfiguration("coc.preferences").get("maxFileSize","10MB");this.maxFileSize=JY.default.parse(r),e.setVar("coc_max_filesize",this.maxFileSize,!0);let{bufnrs:o,winid:s,bufnr:a,winids:l}=await this.nvim.call("coc#util#all_state");this.winids=new Set(l),this._bufnr=a,await Promise.all(o.map(c=>this.createDocument(c))),E.on("BufDetach",this.onBufDetach,this,this.disposables),E.on("VimLeavePre",()=>{this.resolveCurrent(void 0)},null,this.disposables),E.on("WinEnter",c=>{this.winids.add(c)},null,this.disposables),E.on("BufWinEnter",(c,h)=>{this.winids.add(h)},null,this.disposables),E.on("DirChanged",c=>{this._cwd=c},null,this.disposables),E.on("CursorHold",async()=>{let{bufnrs:c,winids:h}=await this.nvim.call("coc#util#all_state");for(let d of this.buffers.keys())c.includes(d)||E.fire("BufUnload",[d]);for(let d of this.winids)h.includes(d)||E.fire("WinClosed",[d]);this.winids=new Set(h)},null,this.disposables);let u=c=>{this._bufnr=c,this.createDocument(c)};E.on("CursorMoved",u,null,this.disposables),E.on("CursorMovedI",u,null,this.disposables),E.on("BufUnload",this.onBufUnload,this,this.disposables),E.on("BufEnter",this.onBufEnter,this,this.disposables),E.on("BufCreate",this.onBufCreate,this,this.disposables),E.on("TermOpen",this.onBufCreate,this,this.disposables),E.on("BufWritePost",this.onBufWritePost,this,this.disposables),E.on("BufWritePre",this.onBufWritePre,this,this.disposables),E.on("FileType",this.onFileTypeChange,this,this.disposables),E.fire("BufEnter",[a]),E.fire("BufWinEnter",[a,s]),E.on("BufEnter",c=>{this.createDocument(c)},null,this.disposables),E.on("CursorHold",(c,h,d)=>{let g=this.getDocument(c);g&&g.onCursorHold(d)},null,this.disposables),this._env.isVim?["TextChangedP","TextChangedI","TextChanged"].forEach(c=>{E.on(c,(h,d)=>{let g=this.buffers.get(h);g!=null&&g.attached&&g.onTextChange(c,d)},null,this.disposables)}):E.on("CompleteDone",async()=>{let c=await E.race(["TextChangedI","TextChanged","MenuPopupChanged"],100);if(c&&(c.name==="TextChangedI"||c.name==="TextChanged")){let h=this.buffers.get(E.bufnr);h!=null&&h.attached&&h._forceSync()}},null,this.disposables),this._initialized=!0}get bufnr(){return this._bufnr}get root(){return this._root}get cwd(){return this._cwd}get documents(){return Array.from(this.buffers.values()).filter(e=>e.attached&&!e.isCommandLine)}get bufnrs(){return Array.from(this.buffers.keys())}detach(){if(!!this._attached){this._attached=!1;for(let e of this.buffers.keys())this.onBufUnload(e);Z(this.disposables)}}get textDocuments(){let e=[];for(let t of this.buffers.values())t.attached&&e.push(t.textDocument);return e}getDocument(e){if(typeof e=="number")return this.buffers.get(e);let t=Wo.isWindows||Wo.isMacintosh;e=O.parse(e).toString();for(let i of this.buffers.values())if(i.uri===e||t&&i.uri.toLowerCase()===e.toLowerCase())return i;return null}expand(e){if(e.startsWith("~")&&(e=tk.default.homedir()+e.slice(1)),e.includes("$")){let t=this.getDocument(this.bufnr),i=t?O.parse(t.uri).fsPath:"";e=e.replace(/\$\{(.*?)\}/g,(r,o)=>{if(o.startsWith("env:")){let s=o.split(":")[1];return s?process.env[s]:""}switch(o){case"workspace":case"workspaceRoot":case"workspaceFolder":return this._root;case"workspaceFolderBasename":return Sl.default.dirname(this._root);case"cwd":return this._cwd;case"file":return i;case"fileDirname":return i?Sl.default.dirname(i):"";case"fileExtname":return i?Sl.default.extname(i):"";case"fileBasename":return i?Sl.default.basename(i):"";case"fileBasenameNoExtension":{let s=i?Sl.default.basename(i):"";return s?s.slice(0,s.length-Sl.default.extname(s).length):""}default:return r}}),e=e.replace(/\$[\w]+/g,r=>r=="$HOME"?tk.default.homedir():process.env[r.slice(1)]||r)}return e}get document(){return this._currentResolve?new Promise(e=>{this.resolves.push(e)}):(this._currentResolve=!0,new Promise((e,t)=>{this.nvim.eval('coc#util#get_bufoptions(bufnr("%"))').then(i=>{let r;i!=null&&(this.creating.delete(i.bufnr),r=this._createDocument(i)),this.resolveCurrent(r),e(r),this._currentResolve=!1},t)}))}resolveCurrent(e){if(this.resolves.length>0)for(;this.resolves.length;){let t=this.resolves.pop();t&&t(e)}}get uri(){let{bufnr:e}=this;if(e){let t=this.getDocument(e);if(t)return t.uri}return null}get filetypes(){let e=new Set;for(let t of this.documents)e.add(t.filetype);return e}get languageIds(){let e=new Set;for(let t of this.documents)e.add(t.languageId);return e}async getFormatOptions(e){let t;e&&(t=this.getDocument(e));let i=t?t.bufnr:0,r=await this.nvim.call("coc#util#get_format_opts",[i]),o={tabSize:r.tabsize,insertSpaces:r.expandtab==1};return o.insertFinalNewline=r.insertFinalNewline==1,r.trimTrailingWhitespace&&(o.trimTrailingWhitespace=!0),r.trimFinalNewlines&&(o.trimFinalNewlines=!0),o}async createDocument(e){let t=this.buffers.get(e);if(t)return t;if(this.creating.has(e))return await this.creating.get(e);let i=new Promise(r=>{this.nvim.call("coc#util#get_bufoptions",[e]).then(o=>{if(!this.creating.has(e)){r(void 0);return}if(this.creating.delete(e),!o){r(void 0);return}t=this._createDocument(o),r(t)},()=>{this.creating.delete(e),r(void 0)})});return this.creating.set(e,i),await i}async onBufCreate(e){this.onBufUnload(e),await this.createDocument(e)}_createDocument(e){let{bufnr:t}=e;if(this.buffers.has(t))return this.buffers.get(t);let i=this.nvim.createBuffer(t),r=new Gb(i,this._env,this.nvim,e);if(this.buffers.set(t,r),r.attached){if(r.schema=="file"){let o=this.configurations.resolveFolderConfigution(r.uri),s=this.workspaceFolder.resolveRoot(r,this._cwd,this._initialized,this.expand.bind(this));t==this._bufnr&&(o&&this.configurations.setFolderConfiguration(r.uri),s&&(this._root=s))}this._onDidOpenTextDocument.fire(r.textDocument),r.onDocumentChange(o=>this._onDidChangeDocument.fire(o))}return Qb.debug("buffer created",t,r.attached,r.uri),r}onBufEnter(e){this._bufnr=e;let t=this.buffers.get(e);if(t){this.configurations.setFolderConfiguration(t.uri);let i=this.workspaceFolder.getWorkspaceFolder(O.parse(t.uri));i&&(this._root=O.parse(i.uri).fsPath)}}onBufUnload(e){this.creating.delete(e),this.onBufDetach(e,!1)}async onBufDetach(e,t=!0){this.detachBuffer(e),t&&await this.nvim.call("bufloaded",[e])&&await this.createDocument(e)}detachBuffer(e){let t=this.buffers.get(e);!t||(Qb.debug("document detach",e,t.uri),this._onDidCloseDocument.fire(t.textDocument),this.buffers.delete(e),t.detach())}async onBufWritePost(e,t){let i=this.buffers.get(e);i&&(i.changedtick!=t&&await i.patchChange(),this._onDidSaveDocument.fire(i.textDocument))}async onBufWritePre(e,t,i){let r=this.buffers.get(e);if(!r||!r.attached||r.bufname!=t&&(this.detachBuffer(e),r=await this.createDocument(e),!r.attached))return;r.changedtick!=i?await r.synchronize():await r.patchChange();let o=!0,s=[],a={document:r.textDocument,reason:fn.TextDocumentSaveReason.Manual,waitUntil:u=>{o?s.push(u):(Qb.error("Can't call waitUntil in async manner:",Error().stack),this.nvim.echoError("waitUntil can't be used in async manner, check log for details"))}};this._onWillSaveDocument.fire(a),o=!1;let l=s.length;if(l){let c=await new Promise(h=>{let g=this.configurations.getConfiguration("coc.preferences").get("willSaveHandlerTimeout",500),f=setTimeout(()=>{this.nvim.outWriteLine(`Will save handler timeout after ${g}ms`),h(void 0)},g),p=0,b=!1;for(let v of s){let w=D=>{b||(b=!0,clearTimeout(f),h(D))};v.then(D=>{if(Array.isArray(D)&&D.length&&fn.TextEdit.is(D[0]))return w(D);p=p+1,p==l&&w(void 0)},D=>{Qb.error("Error on will save handler:",D),p=p+1,p==l&&w(void 0)})}});c&&await r.applyEdits(c,!1,this.bufnr===r.bufnr)}}onFileTypeChange(e,t){let i=this.getDocument(t);!i||i.convertFiletype(e)==i.filetype||(this._onDidCloseDocument.fire(i.textDocument),i.setFiletype(e),this._onDidOpenTextDocument.fire(i.textDocument))}async getQuickfixList(e){let t={},i=e.reduce((r,o)=>{let s=O.parse(o.uri);return s.scheme=="file"&&!r.includes(s.fsPath)&&!this.getDocument(o.uri)&&r.push(s.fsPath),r},[]);return await Promise.all(i.map(r=>new Promise(o=>{ek.default.readFile(r,"utf8",(s,a)=>{if(s)return o(void 0);t[r]=a.split(/\r?\n/),o(void 0)})}))),await Promise.all(e.map(r=>{let{uri:o,range:s}=r,{fsPath:a}=O.parse(o),l,u=t[a];return u&&(l=u[s.start.line]),this.getQuickfixItem(r,l)}))}async getQuickfixItem(e,t,i="",r){fn.LocationLink.is(e)&&(e=fn.Location.create(e.targetUri,e.targetRange));let o=this.getDocument(e.uri),{uri:s,range:a}=e,{start:l,end:u}=a,c=O.parse(s);!t&&c.scheme=="file"&&(t=await this.getLine(s,l.line));let h=l.line==u.line?t:await this.getLine(s,u.line),d={uri:s,filename:c.scheme=="file"?c.fsPath:s,lnum:l.line+1,end_lnum:u.line+1,col:t?Ze(t,l.character)+1:l.character+1,end_col:h?Ze(h,u.character)+1:u.character+1,text:t||"",range:a};return r&&(d.module=r),i&&(d.type=i),o&&(d.bufnr=o.bufnr),d}async getLine(e,t){let i=this.getDocument(e);if(i&&i.attached)return i.getline(t)||"";if(!e.startsWith("file:"))return"";let r=O.parse(e).fsPath;return ek.default.existsSync(r)?await M2(r,t):""}async readFile(e){let t=this.getDocument(e);if(t)return await t.patchChange(),t.content;let i=O.parse(e);return i.scheme!="file"?"":(await this.nvim.call("readfile",[i.fsPath])).join(` -`)+` -`}reset(){this.creating.clear();for(let e of this.buffers.keys())this.onBufUnload(e);this.buffers.clear(),this._root=process.cwd()}dispose(){for(let e of this.buffers.keys())this.onBufUnload(e);this._attached=!1,this.buffers.clear(),Z(this.disposables)}}});function Og(){return XY.default.randomBytes(16)}var XY,ik=_(()=>{XY=C(require("crypto"))});function Jbe(n,e){var t=e||0,i=UY;return[i[n[t++]],i[n[t++]],i[n[t++]],i[n[t++]],"-",i[n[t++]],i[n[t++]],"-",i[n[t++]],i[n[t++]],"-",i[n[t++]],i[n[t++]],"-",i[n[t++]],i[n[t++]],i[n[t++]],i[n[t++]],i[n[t++]],i[n[t++]]].join("")}var UY,Mg,zb,nk=_(()=>{UY=[];for(Mg=0;Mg<256;++Mg)UY[Mg]=(Mg+256).toString(16).substr(1);zb=Jbe});function $be(n,e,t){var i=e&&t||0,r=e||[];n=n||{};var o=n.node||GY,s=n.clockseq!==void 0?n.clockseq:rk;if(o==null||s==null){var a=n.random||(n.rng||Og)();o==null&&(o=GY=[a[0]|1,a[1],a[2],a[3],a[4],a[5]]),s==null&&(s=rk=(a[6]<<8|a[7])&16383)}var l=n.msecs!==void 0?n.msecs:new Date().getTime(),u=n.nsecs!==void 0?n.nsecs:sk+1,c=l-ok+(u-sk)/1e4;if(c<0&&n.clockseq===void 0&&(s=s+1&16383),(c<0||l>ok)&&n.nsecs===void 0&&(u=0),u>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");ok=l,sk=u,rk=s,l+=122192928e5;var h=((l&268435455)*1e4+u)%4294967296;r[i++]=h>>>24&255,r[i++]=h>>>16&255,r[i++]=h>>>8&255,r[i++]=h&255;var d=l/4294967296*1e4&268435455;r[i++]=d>>>8&255,r[i++]=d&255,r[i++]=d>>>24&15|16,r[i++]=d>>>16&255,r[i++]=s>>>8|128,r[i++]=s&255;for(var g=0;g<6;++g)r[i+g]=o[g];return e||zb(r)}var GY,rk,ok,sk,Uo,QY=_(()=>{ik();nk();ok=0,sk=0;Uo=$be});function Xbe(n,e,t){var i=e&&t||0;typeof n=="string"&&(e=n==="binary"?new Array(16):null,n=null),n=n||{};var r=n.random||(n.rng||Og)();if(r[6]=r[6]&15|64,r[8]=r[8]&63|128,e)for(var o=0;o<16;++o)e[i+o]=r[o];return e||zb(r)}var re,KY=_(()=>{ik();nk();re=Xbe});var Oe=_(()=>{QY();KY()});var Ri,oa=_(()=>{"use strict";bc();Pe();Ri=class{constructor(){this.lines=[];this._highlights=[]}addLine(e,t){if(e.includes(` -`)){for(let i of e.split(/\r?\n/))this.addLine(i,t);return}if(t&&this._highlights.push({lnum:this.lines.length,colStart:e.match(/^\s*/)[0].length,colEnd:Q(e),hlGroup:t}),e.includes("\x1B")){let i=mc(e);for(let r of i.highlights){let{span:o,hlGroup:s}=r;o[0]!=o[1]&&this._highlights.push({lnum:this.lines.length,colStart:o[0],colEnd:o[1],hlGroup:s})}this.lines.push(i.line)}else this.lines.push(e)}addLines(e){this.lines.push(...e)}addTexts(e){let t=this.lines.length,i="";for(let r of e){let o=Q(i);r.hlGroup&&this._highlights.push({lnum:t,colStart:o,colEnd:o+Q(r.text),hlGroup:r.hlGroup}),i+=r.text}this.lines.push(i)}addText(e,t){let{lines:i}=this,r=i[i.length-1]||"";if(e.includes(` -`)){let o=e.split(` -`);this.addText(o[0],t);for(let s of o.slice(1))this.addLine(s,t);return}if(t){let o=Q(r);this._highlights.push({lnum:i.length?i.length-1:0,colStart:o,colEnd:o+Q(e),hlGroup:t})}i.length?i[i.length-1]=`${r}${e}`:i.push(e)}get length(){return this.lines.length}getline(e){return this.lines[e]||""}get highlights(){return this._highlights}get content(){return this.lines.join(` -`)}render(e,t=0,i=-1){e.setLines(this.lines,{start:t,end:i,strictIndexing:!1},!0);for(let r of this._highlights)e.addHighlight({hlGroup:r.hlGroup,colStart:r.colStart,colEnd:r.colEnd==null?-1:r.colEnd,line:t+r.lnum,srcId:-1})}}});function Gbe(n,e){var i,r;let t=new Map;for(let o of n){let s=(i=Ig(o))!=null?i:null,a=s&&(r=e[s].label)!=null?r:null,l=t.get(a);l?l.push(o):t.set(a,[o])}return t}var Ng,Vb,BIe,Ube,ey,zY=_(()=>{"use strict";Ng=C(Lg()),Vb=C(require("path"));Qr();we();le();z();Je();jr();oa();BIe=q()("mdoe-editInspect"),Ube=0,ey=class{constructor(e,t){this.nvim=e;this.keymaps=t;this.disposables=[];this.items=[];this.renameMap=new Map;E.on("BufUnload",i=>{i==this.bufnr&&this.dispose()},null,this.disposables)}addFile(e,t,i){this.items.push({index:t.length,filepath:e,lnum:i})}async show(e){var c,h;let{nvim:t}=this,i=Ube++;t.pauseNotification(),t.command(`tabe +setl\\ buftype=nofile CocWorkspaceEdit${i}`,!0),t.command("setl bufhidden=wipe nolist",!0),t.command("setl nobuflisted wrap undolevels=-1 filetype=cocedits noswapfile",!0),await t.resumeNotification(!0);let r=await t.buffer,o=await t.call("getcwd");this.bufnr=r.id;let s=d=>{let g=O.parse(d).fsPath;return Ae(o,g,!0)?Vb.default.relative(o,g):g},a=d=>Vb.default.isAbsolute(d)?d:Vb.default.join(o,d),l=new Ri,u=Gbe((c=e.edit.documentChanges)!=null?c:[],(h=e.edit.changeAnnotations)!=null?h:{});for(let[d,g]of u.entries()){d&&(l.addLine(d,"MoreMsg"),l.addLine(""));for(let f of g)if(Ws.is(f)){let p=e.changes[f.textDocument.uri],b=s(f.textDocument.uri);l.addTexts([{text:"Change",hlGroup:"Title"},{text:" "},{text:b,hlGroup:"Directory"},{text:`:${p.lnum}`,hlGroup:"LineNr"}]),this.addFile(b,l,p.lnum),l.addLine(""),this.addChangedLines(l,p,b,p.lnum),l.addLine("")}else if(Zs.is(f)||qo.is(f)){let p=qo.is(f)?"Delete":"Create",b=s(f.uri);l.addTexts([{text:p,hlGroup:"Title"},{text:" "},{text:b,hlGroup:"Directory"}]),this.addFile(b,l),l.addLine("")}else if(Js.is(f)){let p=s(f.oldUri),b=s(f.newUri);l.addTexts([{text:"Rename",hlGroup:"Title"},{text:" "},{text:p,hlGroup:"Directory"},{text:"->",hlGroup:"Comment"},{text:b,hlGroup:"Directory"}]),this.renameMap.set(p,b),this.addFile(b,l),l.addLine("")}}t.pauseNotification(),l.render(r),r.setOption("modifiable",!1,!0),await t.resumeNotification(!0),this.disposables.push(this.keymaps.registerLocalKeymap("n","",async()=>{var v;let d=await t.call("line","."),g=await t.call("col","."),f;for(let w=this.items.length-1;w>=0;w--){let D=this.items[w];if(d>=D.index){f=D;break}}if(!f)return;let p=O.file(a(f.filepath)).toString(),b=this.renameMap.has(f.filepath)?this.renameMap.get(f.filepath):f.filepath;if(await t.call("coc#util#open_file",["tab drop",a(b)]),typeof f.lnum=="number"){let D=((v=e.edit.documentChanges)!=null?v:[]).find(F=>Ws.is(F)&&F.textDocument.uri==p),S=f.lnum;if(D){let F=Fg(D.edits,(j,W)=>{let B=j.range.start.line-W.range.start.line;return B===0?j.range.start.character-W.range.start.character:B});S=Xb(Vt.create(S-1,0),F).line+1}await t.call("cursor",[S,g])}t.redrawVim()},!0)),this.disposables.push(this.keymaps.registerLocalKeymap("n","",async()=>{t.command("bwipeout!",!0)},!0))}addChangedLines(e,t,i,r){let o=(0,Ng.default)(t.oldLines.join(` -`),t.newLines.join(` -`));for(let s=0;s0&&e.addText(h)}r+=l.split(` -`).length-1}else a[0]==Ng.default.DELETE?(r+=a[1].split(` -`).length-1,e.addText(a[1],"DiffDelete")):a[0]==Ng.default.INSERT&&e.addText(a[1],"DiffAdd")}}dispose(){Z(this.disposables)}}});function ak(n){return n?new Error(`Illegal argument: ${n}`):new Error("Illegal argument")}function lk(n){return new Error(`File ${n} already exists`)}function ty(n){return new Error(`File ${n} not exists`)}function VY(n){return new Error(`${n} should not be called in an asynchronize manner`)}function iy(n){return new Error(`Change of ${n} not supported`)}var uk=_(()=>{"use strict"});function zbe(n,e,t){let i=Ar.default.join(n,e);if(typeof t!="string"){let r=t.baseUri.fsPath;if(!Ae(r,i))return!1;let o=Ar.default.relative(r,i);return(0,ck.default)(o,t.pattern,{dot:!0})}return(0,ck.default)(e,t,{dot:!0})}function ny(n){return O.parse(n).fsPath}var ct,eW,ck,ry,Ar,tW,St,Kbe,oy,iW=_(()=>{"use strict";ct=C(Rn()),eW=C(gb()),ck=C(Vn()),ry=C(require("os")),Ar=C(require("path")),tW=require("util");Oe();St=C(H());we();le();zY();uk();Je();Pe();jr();Tb();Kbe=q()("core-files"),oy=class{constructor(e,t,i,r){this.documents=e;this.configurations=t;this.workspaceFolderControl=i;this.keymaps=r;this.operationTimeout=500;this._onDidCreateFiles=new St.Emitter;this._onDidRenameFiles=new St.Emitter;this._onDidDeleteFiles=new St.Emitter;this._onWillCreateFiles=new St.Emitter;this._onWillRenameFiles=new St.Emitter;this._onWillDeleteFiles=new St.Emitter;this.onDidCreateFiles=this._onDidCreateFiles.event;this.onDidRenameFiles=this._onDidRenameFiles.event;this.onDidDeleteFiles=this._onDidDeleteFiles.event;this.onWillCreateFiles=this._onWillCreateFiles.event;this.onWillRenameFiles=this._onWillRenameFiles.event;this.onWillDeleteFiles=this._onWillDeleteFiles.event}attach(e,t,i){this.nvim=e,this.env=t,this.window=i}async openTextDocument(e){e=typeof e=="string"?O.file(e):e;let t=this.documents.getDocument(e.toString());if(t)return await this.jumpTo(e.toString(),null,"drop"),t;let i=e.scheme;if(i=="file"){if(!ct.default.existsSync(e.fsPath))throw ty(e.fsPath);ct.default.accessSync(e.fsPath,ct.default.constants.R_OK)}return i=="untitled"?(await this.nvim.call("coc#util#open_file",["tab drop",e.path]),await this.documents.document):await this.loadResource(e.toString())}async jumpTo(e,t,i){let r=this.configurations.getConfiguration("coc.preferences"),o=i||r.get("jumpCommand","edit"),{nvim:s}=this,a=this.documents.getDocument(e),l=a?a.bufnr:-1;if(l!=-1&&o=="edit"){if(s.pauseNotification(),s.command("silent! normal! m'",!0),s.command(`buffer ${l}`,!0),s.command("if &filetype ==# '' | filetype detect | endif",!0),t){let u=a.getline(t.line),c=Q(u.slice(0,t.character))+1;s.call("cursor",[t.line+1,c],!0)}await s.resumeNotification(!0)}else{let{fsPath:u,scheme:c}=O.parse(e),h=t==null?null:[t.line,t.character];if(c=="file"){let d=yg(Ar.default.normalize(u));await this.nvim.call("coc#util#jump",[o,d,h])}else ry.default.platform()=="win32"&&(e=e.replace(/\/?/,"?")),await this.nvim.call("coc#util#jump",[o,e,h])}}async openResource(e){let{nvim:t}=this,i=O.parse(e);if(/^https?/.test(i.scheme)){await t.call("coc#ui#open_url",e);return}let r=await t.getOption("wildignore");await t.setOption("wildignore",""),await this.jumpTo(e),await t.setOption("wildignore",r)}async loadResource(e){let t=this.documents.getDocument(e);if(t)return t;let r=this.configurations.getConfiguration("workspace").get("openResourceCommand","tab drop"),o=O.parse(e),s=o.scheme==="file"?o.fsPath:e,a;if(r){let l=await this.nvim.call("win_getid");a=await this.nvim.call("coc#util#open_file",[r,s]),await this.nvim.call("win_gotoid",[l])}else a=(await this.nvim.call("coc#ui#open_files",[[s]]))[0];return await this.documents.createDocument(a)}async loadResources(e){let{documents:t}=this,i=e.map(o=>{let s=O.parse(o);return s.scheme=="file"?s.fsPath:o}),r=await this.nvim.call("coc#ui#open_files",[i]);return await Promise.all(r.map(o=>t.createDocument(o)))}async createFile(e,t={},i){let{nvim:r}=this,o=ct.default.existsSync(e);if(o&&!t.overwrite&&!t.ignoreIfExists)throw lk(e);if(!o||t.overwrite){let s=new St.CancellationTokenSource;await this.fireWaitUntilEvent(this._onWillCreateFiles,{files:[O.file(e)],token:s.token},i),s.cancel();let a=Ar.default.dirname(e);if(!ct.default.existsSync(a)){let c,h=a;for(;![".","/",Ar.default.parse(a).root].includes(h);){if(ct.default.existsSync(Ar.default.dirname(h))){c=h;break}h=Ar.default.dirname(h)}await ct.default.mkdirp(a),i&&i.push(async()=>{ct.default.existsSync(c)&&await ct.default.remove(c)})}ct.default.writeFileSync(e,"","utf8"),i&&i.push(async()=>{ct.default.existsSync(e)&&await ct.default.unlink(e)});let u=(await this.loadResource(e)).bufnr;i&&i.push(()=>(E.fire("BufUnload",[u]),r.command(`silent! bd! ${u}`))),this._onDidCreateFiles.fire({files:[O.file(e)]})}}async deleteFile(e,t={},i){let{ignoreIfNotExists:r,recursive:o}=t,s=await Ht(e),a=s&&s.isDirectory();if(!s&&!r)throw ty(e);if(s==null)return;let l=O.file(e);if(await this.fireWaitUntilEvent(this._onWillDeleteFiles,{files:[l]},i),!a){let u=await this.nvim.call("bufnr",[e]);u&&(E.fire("BufUnload",[u]),await this.nvim.command(`silent! bwipeout ${u}`),i&&i.push(()=>this.loadResource(l.toString())))}if(a&&o){let u=Ar.default.join(ry.default.tmpdir(),"coc-"+re());await ct.default.mkdir(u),await ct.default.copy(e,u,{recursive:!0}),await ct.default.remove(e),i&&i.push(async()=>{await ct.default.mkdir(e),await ct.default.copy(u,e,{recursive:!0}),await ct.default.remove(u)})}else if(a)await ct.default.rmdir(e),i&&i.push(()=>ct.default.mkdir(e));else{let u=Ar.default.join(ry.default.tmpdir(),"coc-"+re());await ct.default.copyFile(e,u),await ct.default.unlink(e),i&&i.push(()=>ct.default.move(u,e,{overwrite:!0}))}this._onDidDeleteFiles.fire({files:[l]})}async renameFile(e,t,i={},r){let{nvim:o}=this,{overwrite:s,ignoreIfExists:a}=i;if(t===e)return;let l=ct.default.existsSync(t);if(l&&a&&!s)return;if(l&&!s)throw lk(t);let u=await Ht(e),c=u&&u.isDirectory()?0:await o.call("bufloaded",[e]);if(!c&&!u)throw ty(e);let h={newUri:O.parse(t),oldUri:O.parse(e)};if(i.skipEvent||await this.fireWaitUntilEvent(this._onWillRenameFiles,{files:[h]},r),c){let d=await o.call("coc#ui#rename_file",[e,t,u!=null]);await this.documents.onBufCreate(d)}else{if(u!=null&&u.isDirectory())for(let d of this.documents.documents){let g=O.parse(d.uri);if(g.scheme==="file"&&Ae(e,g.fsPath,!1)){let f=g.fsPath.replace(e,t),p=await o.call("coc#ui#rename_file",[g.fsPath,f,!1]);await this.documents.onBufCreate(p)}}ct.default.renameSync(e,t)}r&&r.push(()=>this.renameFile(t,e,{skipEvent:!0})),i.skipEvent||this._onDidRenameFiles.fire({files:[h]})}async renameCurrent(){let{nvim:e}=this,t=await e.call("expand",["%:p"]),i=await e.callAsync("coc#util#with_callback",["input",["New path: ",t,"file"]]);i=i?i.trim():null,!(i===t||!i)&&(t.toLowerCase()!=i.toLowerCase()&&ct.default.existsSync(i)&&!await Sb(this.nvim,`${i} exists, overwrite?`)||await this.renameFile(t,i,{overwrite:!0}))}get currentUri(){let e=this.documents.getDocument(this.documents.bufnr);return e?e.uri:null}async applyEdit(e,t){let i=OY(e),r=[],o=!1;try{let{changeAnnotations:s}=e,{currentUri:a}=this,l=s?AY(i,s):[],u={},c=[];for(let h of l){let d=s[h];d.needsConfirmation=!1,await this.window.showMenuPicker(["Yes","No"],{position:"center",title:"Confirm edits",content:d.label+(d.description?" "+d.description:"")})!==0&&c.push(h)}if(i=i.filter(h=>!c.includes(Ig(h))),!i.length)return!0;o=i.every(h=>St.TextDocumentEdit.is(h)&&h.textDocument.uri===a),this.validateChanges(i);for(let h of i)if(St.TextDocumentEdit.is(h)){let{textDocument:d,edits:g}=h,{uri:f}=d,p=await this.loadResource(f),b=await p.applyEdits(g,!1,f===a);if(b){let v=p.version,{newText:w,range:D}=b;u[f]={uri:f,lnum:D.start.line+1,newLines:p.getLines(D.start.line,D.end.line),oldLines:w.endsWith(` -`)?w.slice(0,-1).split(` -`):w.split(` -`)},r.push(async()=>{let S=this.documents.getDocument(f);!S||!S.attached||S.version!==v||(await S.applyEdits([b]),d.version=S.version)})}}else St.CreateFile.is(h)?await this.createFile(ny(h.uri),h.options,r):St.DeleteFile.is(h)?await this.deleteFile(ny(h.uri),h.options,r):St.RenameFile.is(h)&&await this.renameFile(ny(h.oldUri),ny(h.newUri),h.options,r);if(r.length===0)return!0;t||(this.editState={edit:{documentChanges:i,changeAnnotations:e.changeAnnotations},changes:u,recovers:r,applied:!0}),this.nvim.redrawVim()}catch(s){return Kbe.error("Error on applyEdits:",e,s),await this.undoChanges(r),t||this.window.showErrorMessage(`Error on applyEdits: ${s}`),!1}return t||o||this.window.showInformationMessage("Use ':wa' to save changes or ':CocCommand workspace.inspectEdit' to inspect."),!0}async undoChanges(e){for(;e.length>0;)await e.pop()()}async inspectEdit(){if(!this.editState){this.window.showWarningMessage("No workspace edit to inspect");return}await new ey(this.nvim,this.keymaps).show(this.editState)}async undoWorkspaceEdit(){let{editState:e}=this;if(!e||!e.applied){this.window.showWarningMessage("No workspace edit to undo");return}e.applied=!1,await this.undoChanges(e.recovers)}async redoWorkspaceEdit(){let{editState:e}=this;if(!e||e.applied){this.window.showWarningMessage("No workspace edit to redo");return}this.editState=void 0,await this.applyEdit(e.edit)}validateChanges(e){let{documents:t}=this;for(let i of e)if(St.TextDocumentEdit.is(i)){let{uri:r,version:o}=i.textDocument,s=t.getDocument(r);if(typeof o=="number"&&o>0){if(!s)throw new Error(`File ${r} not loaded`);if(s.version!=o)throw new Error(`${r} changed before apply edit`)}else if(!s&&!vg(r))throw iy(O.parse(r).scheme)}else if(St.CreateFile.is(i)||St.DeleteFile.is(i)){if(!vg(i.uri))throw iy(O.parse(i.uri).scheme)}else if(St.RenameFile.is(i)&&(!vg(i.oldUri)||!vg(i.newUri)))throw iy(O.parse(i.oldUri).scheme)}async findFiles(e,t,i,r){let o=this.workspaceFolderControl.workspaceFolders;if((r==null?void 0:r.isCancellationRequested)||!o.length||i===0)return[];i=i!=null?i:1/0;let s=o.map(u=>O.parse(u.uri).fsPath);if(typeof e!="string"){let u=e.baseUri.fsPath;s=s.filter(c=>Ae(u,c,!0))}let a=typeof e=="string"?e:e.pattern,l=[];for(let u of s){if(l.length>=i)break;let c=await(0,tW.promisify)(eW.default)(a,{dot:!0,cwd:u,nodir:!0,absolute:!1});if(r!=null&&r.isCancellationRequested)return[];for(let h of c)if(!(t&&zbe(u,h,t))&&(l.push(O.file(Ar.default.join(u,h))),l.length===i))break}return l}async fireWaitUntilEvent(e,t,i){let r=!0,o=[];e.fire(Ba(ge({},t),{waitUntil:s=>{if(!r)throw VY("waitUntil");let a=new Promise(u=>{setTimeout(u,this.operationTimeout)}),l=Promise.race([s,a]).then(u=>{if(u&&St.WorkspaceEdit.is(u))return this.applyEdit(u,!0)});o.push(l)}})),r=!1,await Promise.all(o)}}});function hk(n,e){for(let t of e)if(n.includes(t))return!0;return!1}function nW(n,e,t=0){let i=-1;for(let r=t;r{e(i)?t[0].push(i):t[1].push(i)}),t}function sa(n,e){if(!e)return n.filter((i,r)=>n.indexOf(i)===r);let t=Object.create(null);return n.filter(i=>{let r=e(i);return t[r]?!1:(t[r]=!0,!0)})}var Go=_(()=>{"use strict"});var aW=m((rje,sW)=>{var dk=4294967296,oW=[];for(Fc=0;Fc<256;Fc++)oW[Fc]=(Fc>15?"":"0")+Fc.toString(16);var Fc,Bg=sW.exports=function(n,e){n instanceof Buffer?(this.buffer=n,this.offset=e||0):Object.prototype.toString.call(n)=="[object Uint8Array]"?(this.buffer=new Buffer(n),this.offset=e||0):(this.buffer=this.buffer||new Buffer(8),this.offset=0,this.setValue.apply(this,arguments))};Bg.MAX_INT=Math.pow(2,53);Bg.MIN_INT=-Math.pow(2,53);Bg.prototype={constructor:Bg,_2scomp:function(){for(var n=this.buffer,e=this.offset,t=1,i=e+7;i>=e;i--){var r=(n[i]^255)+t;n[i]=r&255,t=r>>8}},setValue:function(n,e){var t=!1;if(arguments.length==1)if(typeof n=="number"){if(t=n<0,n=Math.abs(n),e=n%dk,n=n/dk,n>dk)throw new RangeError(n+" is outside Int64 range");n=n|0}else if(typeof n=="string")n=(n+"").replace(/^0x/,""),e=n.substr(-8),n=n.length>8?n.substr(0,n.length-8):"",n=parseInt(n,16),e=parseInt(e,16);else throw new Error(n+" must be a Number or String");for(var i=this.buffer,r=this.offset,o=7;o>=0;o--)i[r+o]=e&255,e=o==4?n:e>>>8;t&&this._2scomp()},toNumber:function(n){for(var e=this.buffer,t=this.offset,i=e[t]&128,r=0,o=1,s=7,a=1;s>=0;s--,a*=256){var l=e[t+s];i&&(l=(l^255)+o,o=l>>8,l=l&255),r+=l*a}return!n&&r>=Bg.MAX_INT?i?-1/0:1/0:i?-r:r},valueOf:function(){return this.toNumber(!1)},toString:function(n){return this.valueOf().toString(n||10)},toOctetString:function(n){for(var e=new Array(8),t=this.buffer,i=this.offset,r=0;r<8;r++)e[r]=oW[t[i+r]];return e.join(n||"")},toBuffer:function(n){if(n&&this.offset===0)return this.buffer;var e=new Buffer(8);return this.buffer.copy(e,0,this.offset,this.offset+8),e},copy:function(n,e){this.buffer.copy(n,e||0,this.offset,this.offset+8)},compare:function(n){if((this.buffer[this.offset]&128)!=(n.buffer[n.offset]&128))return n.buffer[n.offset]-this.buffer[this.offset];for(var e=0;e<8;e++)if(this.buffer[this.offset+e]!==n.buffer[n.offset+e])return this.buffer[this.offset+e]-n.buffer[n.offset+e];return 0},equals:function(n){return this.compare(n)===0},inspect:function(){return"[Int64 value:"+this+" octets:"+this.toOctetString(" ")+"]"}}});var yW=m(qg=>{var uW=require("events").EventEmitter,Vbe=require("util"),eye=require("os"),oje=require("assert"),Hg=aW(),aa=eye.endianness()=="BE";function cW(n){return Math.pow(2,Math.ceil(Math.log(n)/Math.LN2))}function di(n){this.buf=Buffer.alloc(cW(n||8192)),this.readOffset=0,this.writeOffset=0}qg.Accumulator=di;di.prototype.writeAvail=function(){return this.buf.length-this.writeOffset};di.prototype.readAvail=function(){return this.writeOffset-this.readOffset};di.prototype.reserve=function(n){if(!(n0&&(this.buf.copy(this.buf,0,this.readOffset,this.writeOffset),this.writeOffset-=this.readOffset,this.readOffset=0),!(n0)this.assertReadableSize(n);else if(n<0&&this.readOffset+n<0)throw new Error("advance with negative offset "+n+" would seek off the start of the buffer");this.readOffset+=n};di.prototype.writeByte=function(n){this.reserve(1),this.buf.writeInt8(n,this.writeOffset),++this.writeOffset};di.prototype.writeInt=function(n,e){switch(this.reserve(e),e){case 1:this.buf.writeInt8(n,this.writeOffset);break;case 2:aa?this.buf.writeInt16BE(n,this.writeOffset):this.buf.writeInt16LE(n,this.writeOffset);break;case 4:aa?this.buf.writeInt32BE(n,this.writeOffset):this.buf.writeInt32LE(n,this.writeOffset);break;default:throw new Error("unsupported integer size "+e)}this.writeOffset+=e};di.prototype.writeDouble=function(n){this.reserve(8),aa?this.buf.writeDoubleBE(n,this.writeOffset):this.buf.writeDoubleLE(n,this.writeOffset),this.writeOffset+=8};var fk=0,pk=1,mk=2,bk=3,yk=4,cy=5,uy=6,hW=7,dW=8,gW=9,fW=10,pW=11,tye=12,gk=0,lW=1,iye=127,nye=32767,rye=2147483647;function pn(){uW.call(this),this.buf=new di,this.state=gk}Vbe.inherits(pn,uW);qg.BunserBuf=pn;pn.prototype.append=function(n,e){if(e)return this.buf.append(n),this.process(e);try{this.buf.append(n)}catch(t){this.emit("error",t);return}this.processLater()};pn.prototype.processLater=function(){var n=this;process.nextTick(function(){try{n.process(!1)}catch(e){n.emit("error",e)}})};pn.prototype.process=function(n){if(this.state==gk){if(this.buf.readAvail()<2)return;if(this.expectCode(0),this.expectCode(1),this.pduLen=this.decodeInt(!0),this.pduLen===!1){this.buf.readAdvance(-2);return}this.buf.reserve(this.pduLen),this.state=lW}if(this.state==lW){if(this.buf.readAvail()0&&this.processLater()};pn.prototype.raise=function(n){throw new Error(n+", in Buffer of length "+this.buf.buf.length+" ("+this.buf.readAvail()+" readable) at offset "+this.buf.readOffset+" buffer: "+JSON.stringify(this.buf.buf.slice(this.buf.readOffset,this.buf.readOffset+32).toJSON()))};pn.prototype.expectCode=function(n){var e=this.buf.readInt(1);e!=n&&this.raise("expected bser opcode "+n+" but got "+e)};pn.prototype.decodeAny=function(){var n=this.buf.peekInt(1);switch(n){case bk:case yk:case cy:case uy:return this.decodeInt();case hW:return this.buf.readAdvance(1),this.buf.readDouble();case dW:return this.buf.readAdvance(1),!0;case gW:return this.buf.readAdvance(1),!1;case fW:return this.buf.readAdvance(1),null;case mk:return this.decodeString();case fk:return this.decodeArray();case pk:return this.decodeObject();case pW:return this.decodeTemplate();default:this.raise("unhandled bser opcode "+n)}};pn.prototype.decodeArray=function(){this.expectCode(fk);for(var n=this.decodeInt(),e=[],t=0;t"u")throw Error("no bser found in string and no error raised!?");return t}qg.loadFromBuffer=oye;function mW(n){for(var e=Buffer.alloc(n.length),t=0;t"u"&&r--}ay(n,r);for(var t=0;t"u")){ly(n,o);try{ly(n,s)}catch(c){throw new Error(c.message+" (while serializing object property with name `"+o+"')")}}}return;default:throw new Error("cannot serialize type "+typeof e+" to BSER")}}function sye(n){var e=new di;e.writeByte(0),e.writeByte(1),e.writeByte(cy),e.writeInt(0,4),ly(e,n);var t=e.writeOffset,i=t-7;return e.writeOffset=3,e.writeInt(i,4),e.writeOffset=t,e.buf.slice(0,t)}qg.dumpToBuffer=sye});var TW=m((aje,SW)=>{"use strict";var aye=require("net"),xW=require("events").EventEmitter,lye=require("util"),uye=require("child_process"),CW=yW(),vW=["subscription","log"];function Qo(n){var e=this;xW.call(this),this.watchmanBinaryPath="watchman",n&&n.watchmanBinaryPath&&(this.watchmanBinaryPath=n.watchmanBinaryPath.trim()),this.commands=[]}lye.inherits(Qo,xW);SW.exports.Client=Qo;Qo.prototype.sendNextCommand=function(){this.currentCommand||(this.currentCommand=this.commands.shift(),this.currentCommand&&this.socket.write(CW.dumpToBuffer(this.currentCommand.cmd)))};Qo.prototype.cancelCommands=function(n){var e=new Error(n),t=this.commands;this.commands=[],this.currentCommand&&(t.unshift(this.currentCommand),this.currentCommand=null),t.forEach(function(i){i.cb(e)})};Qo.prototype.connect=function(){var n=this;function e(l){n.bunser=new CW.BunserBuf,n.bunser.on("value",function(u){for(var c=!1,h=0;h=0:!1}Qo.prototype._synthesizeCapabilityCheck=function(n,e,t){n.capabilities={};var i=n.version;return e.forEach(function(r){n.capabilities[r]=DW(i,r)}),t.forEach(function(r){var o=DW(i,r);n.capabilities[r]=o,o||(n.error="client required capability `"+r+"` is not supported by this server")}),n};Qo.prototype.capabilityCheck=function(n,e){var t=n.optional||[],i=n.required||[],r=this;this.command(["version",{optional:t,required:i}],function(o,s){if(o){e(o);return}if(!("capabilities"in s)&&(s=r._synthesizeCapabilityCheck(s,t,i),s.error)){o=new Error(s.error),o.watchmanResponse=s,e(o);return}e(null,s)})};Qo.prototype.end=function(){this.cancelCommands("The client was ended"),this.socket&&(this.socket.end(),this.socket=null),this.bunser=null}});function dye(n){return!(n=="/"||n=="/tmp"||n=="/private/tmp"||Ae(n,vk.default.homedir(),!0)||dy.default.parse(n).base==n||n.startsWith("/tmp/")||n.startsWith("/private/tmp/")||Ae(vk.default.tmpdir(),n,!0))}var kW,EW,vk,dy,hy,hye,la,wk=_(()=>{"use strict";kW=C(TW()),EW=C(Vn()),vk=C(require("os")),dy=C(require("path"));Oe();Je();hy=q()("core-watchman"),hye=["relative_root","cmd-watch-project","wildmatch","field-new"],la=class{constructor(e,t){this.channel=t;this._disposed=!1;this.client=new kW.default.Client({watchmanBinaryPath:e}),this.client.setMaxListeners(300)}checkCapability(){let{client:e}=this;return new Promise((t,i)=>{e.capabilityCheck({optional:[],required:hye},(r,o)=>{if(r)return t(!1);let{capabilities:s}=o;for(let a of Object.keys(s))if(!s[a])return t(!1);t(!0)})})}async watchProject(e){let t=await this.command(["watch-project",e]),{watch:i,warning:r,relative_path:o}=t;return i?(r&&hy.warn(r),this.watch=i,this.relative_path=o,hy.info(`watchman watching project: ${e}`),this.appendOutput(`watchman watching project: ${e}`),!0):!1}command(e){return new Promise((t,i)=>{this.client.command(e,(r,o)=>{if(r)return i(r);t(o)})})}async subscribe(e,t){let{watch:i,relative_path:r}=this;if(!i)throw new Error("watchman not watching");let{clock:o}=await this.command(["clock",i]),s=Uo(),a={expression:["allof",["match","**/*","wholename"]],fields:["name","size","new","exists","type","mtime_ms","ctime_ms"],since:o},l=i;r&&(a.relative_root=r,l=dy.default.join(i,r));let{subscribe:u}=await this.command(["subscribe",i,s,a]);return this.appendOutput(`subscribing "${e}" in ${l}`),this.client.on("subscription",c=>{if(!c||c.subscription!=s)return;let{files:h}=c;if(!h||(h=h.filter(g=>g.type=="f"&&(0,EW.default)(g.name,e,{dot:!0})),!h.length))return;let d=Object.assign({},c);this.relative_path&&(d.root=dy.default.resolve(c.root,this.relative_path)),this.appendOutput(`file change detected: ${JSON.stringify(d,null,2)}`),t(d)}),{dispose:()=>{this.unsubscribe(u)},subscribe:u}}unsubscribe(e){if(this._disposed)return Promise.resolve();let{watch:t}=this;if(!!t)return this.appendOutput(`unsubscribe "${e}" in: ${t}`),this.command(["unsubscribe",t,e]).catch(i=>{var r;(r=i.message)!=null&&r.includes("The client was ended")&&hy.error(i)})}dispose(){this._disposed||(this._disposed=!0,this.client&&(this.client.removeAllListeners(),this.client.end(),this.client=void 0))}appendOutput(e,t="Info"){this.channel&&this.channel.appendLine(`[${t} - ${new Date().toLocaleTimeString()}] ${e}`)}static async createClient(e,t,i){if(!dye(t))return null;let r;try{if(r=new la(e,i),!await r.checkCapability())throw new Error("required capabilities do not exist.");if(!await r.watchProject(t))throw new Error("unable to watch");return r}catch(o){return r&&r.dispose(),hy.error("Error on watchman create",o),null}}}});var PW,Ic,jc,wje,Yg,Wg,_W,RW=_(()=>{"use strict";PW=C(Vn()),Ic=C(require("path")),jc=C(H());we();z();Go();wk();wje=q()("filesystem-watcher"),Yg=class{constructor(e,t){this.workspaceFolder=e;this.watchmanPath=t;this.clientsMap=new Map;this.disposables=[];this.creating=new Set;this._onDidCreateClient=new jc.Emitter;this.onDidCreateClient=this._onDidCreateClient.event}attach(e){this.channel=e;let t=i=>{let r=O.parse(i.uri).fsPath;this.creating.has(r)||(this.creating.add(r),this.createClient(r).finally(()=>{this.creating.delete(r)}))};this.workspaceFolder.workspaceFolders.forEach(i=>{t(i)}),this.workspaceFolder.onDidChangeWorkspaceFolders(i=>{i.added.forEach(r=>{t(r)}),i.removed.forEach(r=>{let o=O.parse(r.uri).fsPath,s=this.clientsMap.get(o);s&&(this.clientsMap.delete(o),s.dispose())})},null,this.disposables)}waitClient(e){return this.clientsMap.has(e)?Promise.resolve():new Promise(t=>{let i=this.onDidCreateClient(r=>{r==e&&(i.dispose(),t())})})}async createClient(e){if(!(this.watchmanPath==null||this.clientsMap.has(e)))try{let t=await la.createClient(this.watchmanPath,e,this.channel);if(!t)return;this.clientsMap.set(e,t);for(let i of Yg.watchers)i.listen(t);this._onDidCreateClient.fire(e)}catch(t){this.channel&&this.channel.appendLine("Error on create watchman client:"+t)}}createFileSystemWatcher(e,t,i,r){let o=new _W(e,t,i,r);for(let s of this.clientsMap.values())o.listen(s);return Yg.watchers.add(o),o}dispose(){this._onDidCreateClient.dispose();for(let e of this.clientsMap.values())e&&e.dispose();this.clientsMap.clear(),Yg.watchers.clear(),Z(this.disposables)}},Wg=Yg;Wg.watchers=new Set;_W=class{constructor(e,t,i,r){this.globPattern=e;this.ignoreCreateEvents=t;this.ignoreChangeEvents=i;this.ignoreDeleteEvents=r;this._onDidCreate=new jc.Emitter;this._onDidChange=new jc.Emitter;this._onDidDelete=new jc.Emitter;this._onDidRename=new jc.Emitter;this.disposables=[];this._disposed=!1;this.onDidCreate=this._onDidCreate.event;this.onDidChange=this._onDidChange.event;this.onDidDelete=this._onDidDelete.event;this.onDidRename=this._onDidRename.event}listen(e){let{globPattern:t,ignoreCreateEvents:i,ignoreChangeEvents:r,ignoreDeleteEvents:o}=this,s=a=>{let{root:l,files:u}=a;u=u.filter(c=>c.type=="f"&&(0,PW.default)(c.name,t,{dot:!0}));for(let c of u){let h=O.file(Ic.default.join(l,c.name));c.exists?c.new===!0?i||this._onDidCreate.fire(h):r||this._onDidChange.fire(h):o||this._onDidDelete.fire(h)}if(u.length==2&&!u[0].exists&&u[1].exists){let c=u[0],h=u[1];c.size==h.size&&this._onDidRename.fire({oldUri:O.file(Ic.default.join(l,c.name)),newUri:O.file(Ic.default.join(l,h.name))})}if(u.length>=2){let[c,h]=sy(u,d=>d.exists===!1);if(c.length==h.length)for(let d of c){let g=h.find(f=>f.size==d.size&&f.mtime_ms==d.mtime_ms);g&&this._onDidRename.fire({oldUri:O.file(Ic.default.join(l,d.name)),newUri:O.file(Ic.default.join(l,g.name))})}}};e.subscribe(t,s).then(a=>{if(this.subscribe=a.subscribe,this._disposed)return a.dispose();this.disposables.push(a)}).logError()}dispose(){this._disposed=!0,Wg.watchers.delete(this),this._onDidRename.dispose(),this._onDidCreate.dispose(),this._onDidChange.dispose(),Z(this.disposables)}}});var Zg=m((xje,LW)=>{var gye="2.0.0",fye=Number.MAX_SAFE_INTEGER||9007199254740991,pye=16;LW.exports={SEMVER_SPEC_VERSION:gye,MAX_LENGTH:256,MAX_SAFE_INTEGER:fye,MAX_SAFE_COMPONENT_LENGTH:pye}});var Jg=m((Cje,FW)=>{var mye=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...n)=>console.error("SEMVER",...n):()=>{};FW.exports=mye});var Tl=m((ua,IW)=>{var{MAX_SAFE_COMPONENT_LENGTH:Dk}=Zg(),bye=Jg();ua=IW.exports={};var yye=ua.re=[],te=ua.src=[],ie=ua.t={},vye=0,xe=(n,e,t)=>{let i=vye++;bye(n,i,e),ie[n]=i,te[i]=e,yye[i]=new RegExp(e,t?"g":void 0)};xe("NUMERICIDENTIFIER","0|[1-9]\\d*");xe("NUMERICIDENTIFIERLOOSE","[0-9]+");xe("NONNUMERICIDENTIFIER","\\d*[a-zA-Z-][a-zA-Z0-9-]*");xe("MAINVERSION",`(${te[ie.NUMERICIDENTIFIER]})\\.(${te[ie.NUMERICIDENTIFIER]})\\.(${te[ie.NUMERICIDENTIFIER]})`);xe("MAINVERSIONLOOSE",`(${te[ie.NUMERICIDENTIFIERLOOSE]})\\.(${te[ie.NUMERICIDENTIFIERLOOSE]})\\.(${te[ie.NUMERICIDENTIFIERLOOSE]})`);xe("PRERELEASEIDENTIFIER",`(?:${te[ie.NUMERICIDENTIFIER]}|${te[ie.NONNUMERICIDENTIFIER]})`);xe("PRERELEASEIDENTIFIERLOOSE",`(?:${te[ie.NUMERICIDENTIFIERLOOSE]}|${te[ie.NONNUMERICIDENTIFIER]})`);xe("PRERELEASE",`(?:-(${te[ie.PRERELEASEIDENTIFIER]}(?:\\.${te[ie.PRERELEASEIDENTIFIER]})*))`);xe("PRERELEASELOOSE",`(?:-?(${te[ie.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${te[ie.PRERELEASEIDENTIFIERLOOSE]})*))`);xe("BUILDIDENTIFIER","[0-9A-Za-z-]+");xe("BUILD",`(?:\\+(${te[ie.BUILDIDENTIFIER]}(?:\\.${te[ie.BUILDIDENTIFIER]})*))`);xe("FULLPLAIN",`v?${te[ie.MAINVERSION]}${te[ie.PRERELEASE]}?${te[ie.BUILD]}?`);xe("FULL",`^${te[ie.FULLPLAIN]}$`);xe("LOOSEPLAIN",`[v=\\s]*${te[ie.MAINVERSIONLOOSE]}${te[ie.PRERELEASELOOSE]}?${te[ie.BUILD]}?`);xe("LOOSE",`^${te[ie.LOOSEPLAIN]}$`);xe("GTLT","((?:<|>)?=?)");xe("XRANGEIDENTIFIERLOOSE",`${te[ie.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);xe("XRANGEIDENTIFIER",`${te[ie.NUMERICIDENTIFIER]}|x|X|\\*`);xe("XRANGEPLAIN",`[v=\\s]*(${te[ie.XRANGEIDENTIFIER]})(?:\\.(${te[ie.XRANGEIDENTIFIER]})(?:\\.(${te[ie.XRANGEIDENTIFIER]})(?:${te[ie.PRERELEASE]})?${te[ie.BUILD]}?)?)?`);xe("XRANGEPLAINLOOSE",`[v=\\s]*(${te[ie.XRANGEIDENTIFIERLOOSE]})(?:\\.(${te[ie.XRANGEIDENTIFIERLOOSE]})(?:\\.(${te[ie.XRANGEIDENTIFIERLOOSE]})(?:${te[ie.PRERELEASELOOSE]})?${te[ie.BUILD]}?)?)?`);xe("XRANGE",`^${te[ie.GTLT]}\\s*${te[ie.XRANGEPLAIN]}$`);xe("XRANGELOOSE",`^${te[ie.GTLT]}\\s*${te[ie.XRANGEPLAINLOOSE]}$`);xe("COERCE",`(^|[^\\d])(\\d{1,${Dk}})(?:\\.(\\d{1,${Dk}}))?(?:\\.(\\d{1,${Dk}}))?(?:$|[^\\d])`);xe("COERCERTL",te[ie.COERCE],!0);xe("LONETILDE","(?:~>?)");xe("TILDETRIM",`(\\s*)${te[ie.LONETILDE]}\\s+`,!0);ua.tildeTrimReplace="$1~";xe("TILDE",`^${te[ie.LONETILDE]}${te[ie.XRANGEPLAIN]}$`);xe("TILDELOOSE",`^${te[ie.LONETILDE]}${te[ie.XRANGEPLAINLOOSE]}$`);xe("LONECARET","(?:\\^)");xe("CARETTRIM",`(\\s*)${te[ie.LONECARET]}\\s+`,!0);ua.caretTrimReplace="$1^";xe("CARET",`^${te[ie.LONECARET]}${te[ie.XRANGEPLAIN]}$`);xe("CARETLOOSE",`^${te[ie.LONECARET]}${te[ie.XRANGEPLAINLOOSE]}$`);xe("COMPARATORLOOSE",`^${te[ie.GTLT]}\\s*(${te[ie.LOOSEPLAIN]})$|^$`);xe("COMPARATOR",`^${te[ie.GTLT]}\\s*(${te[ie.FULLPLAIN]})$|^$`);xe("COMPARATORTRIM",`(\\s*)${te[ie.GTLT]}\\s*(${te[ie.LOOSEPLAIN]}|${te[ie.XRANGEPLAIN]})`,!0);ua.comparatorTrimReplace="$1$2$3";xe("HYPHENRANGE",`^\\s*(${te[ie.XRANGEPLAIN]})\\s+-\\s+(${te[ie.XRANGEPLAIN]})\\s*$`);xe("HYPHENRANGELOOSE",`^\\s*(${te[ie.XRANGEPLAINLOOSE]})\\s+-\\s+(${te[ie.XRANGEPLAINLOOSE]})\\s*$`);xe("STAR","(<|>)?=?\\s*\\*");xe("GTE0","^\\s*>=\\s*0\\.0\\.0\\s*$");xe("GTE0PRE","^\\s*>=\\s*0\\.0\\.0-0\\s*$")});var $g=m((Sje,jW)=>{var wye=["includePrerelease","loose","rtl"],Dye=n=>n?typeof n!="object"?{loose:!0}:wye.filter(e=>n[e]).reduce((e,t)=>(e[t]=!0,e),{}):{};jW.exports=Dye});var gy=m((Tje,MW)=>{var AW=/^[0-9]+$/,OW=(n,e)=>{let t=AW.test(n),i=AW.test(e);return t&&i&&(n=+n,e=+e),n===e?0:t&&!i?-1:i&&!t?1:nOW(e,n);MW.exports={compareIdentifiers:OW,rcompareIdentifiers:xye}});var Li=m((kje,qW)=>{var fy=Jg(),{MAX_LENGTH:NW,MAX_SAFE_INTEGER:py}=Zg(),{re:BW,t:HW}=Tl(),Cye=$g(),{compareIdentifiers:Ac}=gy(),nr=class{constructor(e,t){if(t=Cye(t),e instanceof nr){if(e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid Version: ${e}`);if(e.length>NW)throw new TypeError(`version is longer than ${NW} characters`);fy("SemVer",e,t),this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease;let i=e.trim().match(t.loose?BW[HW.LOOSE]:BW[HW.FULL]);if(!i)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+i[1],this.minor=+i[2],this.patch=+i[3],this.major>py||this.major<0)throw new TypeError("Invalid major version");if(this.minor>py||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>py||this.patch<0)throw new TypeError("Invalid patch version");i[4]?this.prerelease=i[4].split(".").map(r=>{if(/^[0-9]+$/.test(r)){let o=+r;if(o>=0&&o=0;)typeof this.prerelease[i]=="number"&&(this.prerelease[i]++,i=-2);i===-1&&this.prerelease.push(0)}t&&(Ac(this.prerelease[0],t)===0?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error(`invalid increment argument: ${e}`)}return this.format(),this.raw=this.version,this}};qW.exports=nr});var kl=m((Eje,JW)=>{var{MAX_LENGTH:Sye}=Zg(),{re:YW,t:WW}=Tl(),ZW=Li(),Tye=$g(),kye=(n,e)=>{if(e=Tye(e),n instanceof ZW)return n;if(typeof n!="string"||n.length>Sye||!(e.loose?YW[WW.LOOSE]:YW[WW.FULL]).test(n))return null;try{return new ZW(n,e)}catch{return null}};JW.exports=kye});var XW=m((Pje,$W)=>{var Eye=kl(),Pye=(n,e)=>{let t=Eye(n,e);return t?t.version:null};$W.exports=Pye});var GW=m((_je,UW)=>{var _ye=kl(),Rye=(n,e)=>{let t=_ye(n.trim().replace(/^[=v]+/,""),e);return t?t.version:null};UW.exports=Rye});var zW=m((Rje,KW)=>{var QW=Li(),Lye=(n,e,t,i)=>{typeof t=="string"&&(i=t,t=void 0);try{return new QW(n instanceof QW?n.version:n,t).inc(e,i).version}catch{return null}};KW.exports=Lye});var rr=m((Lje,e3)=>{var VW=Li(),Fye=(n,e,t)=>new VW(n,t).compare(new VW(e,t));e3.exports=Fye});var my=m((Fje,t3)=>{var Iye=rr(),jye=(n,e,t)=>Iye(n,e,t)===0;t3.exports=jye});var r3=m((Ije,n3)=>{var i3=kl(),Aye=my(),Oye=(n,e)=>{if(Aye(n,e))return null;{let t=i3(n),i=i3(e),r=t.prerelease.length||i.prerelease.length,o=r?"pre":"",s=r?"prerelease":"";for(let a in t)if((a==="major"||a==="minor"||a==="patch")&&t[a]!==i[a])return o+a;return s}};n3.exports=Oye});var s3=m((jje,o3)=>{var Mye=Li(),Nye=(n,e)=>new Mye(n,e).major;o3.exports=Nye});var l3=m((Aje,a3)=>{var Bye=Li(),Hye=(n,e)=>new Bye(n,e).minor;a3.exports=Hye});var c3=m((Oje,u3)=>{var qye=Li(),Yye=(n,e)=>new qye(n,e).patch;u3.exports=Yye});var d3=m((Mje,h3)=>{var Wye=kl(),Zye=(n,e)=>{let t=Wye(n,e);return t&&t.prerelease.length?t.prerelease:null};h3.exports=Zye});var f3=m((Nje,g3)=>{var Jye=rr(),$ye=(n,e,t)=>Jye(e,n,t);g3.exports=$ye});var m3=m((Bje,p3)=>{var Xye=rr(),Uye=(n,e)=>Xye(n,e,!0);p3.exports=Uye});var by=m((Hje,y3)=>{var b3=Li(),Gye=(n,e,t)=>{let i=new b3(n,t),r=new b3(e,t);return i.compare(r)||i.compareBuild(r)};y3.exports=Gye});var w3=m((qje,v3)=>{var Qye=by(),Kye=(n,e)=>n.sort((t,i)=>Qye(t,i,e));v3.exports=Kye});var x3=m((Yje,D3)=>{var zye=by(),Vye=(n,e)=>n.sort((t,i)=>zye(i,t,e));D3.exports=Vye});var Xg=m((Wje,C3)=>{var eve=rr(),tve=(n,e,t)=>eve(n,e,t)>0;C3.exports=tve});var yy=m((Zje,S3)=>{var ive=rr(),nve=(n,e,t)=>ive(n,e,t)<0;S3.exports=nve});var xk=m((Jje,T3)=>{var rve=rr(),ove=(n,e,t)=>rve(n,e,t)!==0;T3.exports=ove});var vy=m(($je,k3)=>{var sve=rr(),ave=(n,e,t)=>sve(n,e,t)>=0;k3.exports=ave});var wy=m((Xje,E3)=>{var lve=rr(),uve=(n,e,t)=>lve(n,e,t)<=0;E3.exports=uve});var Ck=m((Uje,P3)=>{var cve=my(),hve=xk(),dve=Xg(),gve=vy(),fve=yy(),pve=wy(),mve=(n,e,t,i)=>{switch(e){case"===":return typeof n=="object"&&(n=n.version),typeof t=="object"&&(t=t.version),n===t;case"!==":return typeof n=="object"&&(n=n.version),typeof t=="object"&&(t=t.version),n!==t;case"":case"=":case"==":return cve(n,t,i);case"!=":return hve(n,t,i);case">":return dve(n,t,i);case">=":return gve(n,t,i);case"<":return fve(n,t,i);case"<=":return pve(n,t,i);default:throw new TypeError(`Invalid operator: ${e}`)}};P3.exports=mve});var R3=m((Gje,_3)=>{var bve=Li(),yve=kl(),{re:Dy,t:xy}=Tl(),vve=(n,e)=>{if(n instanceof bve)return n;if(typeof n=="number"&&(n=String(n)),typeof n!="string")return null;e=e||{};let t=null;if(!e.rtl)t=n.match(Dy[xy.COERCE]);else{let i;for(;(i=Dy[xy.COERCERTL].exec(n))&&(!t||t.index+t[0].length!==n.length);)(!t||i.index+i[0].length!==t.index+t[0].length)&&(t=i),Dy[xy.COERCERTL].lastIndex=i.index+i[1].length+i[2].length;Dy[xy.COERCERTL].lastIndex=-1}return t===null?null:yve(`${t[2]}.${t[3]||"0"}.${t[4]||"0"}`,e)};_3.exports=vve});var F3=m((Qje,L3)=>{"use strict";L3.exports=function(n){n.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var Ug=m((Kje,I3)=>{"use strict";I3.exports=Be;Be.Node=El;Be.create=Be;function Be(n){var e=this;if(e instanceof Be||(e=new Be),e.tail=null,e.head=null,e.length=0,n&&typeof n.forEach=="function")n.forEach(function(r){e.push(r)});else if(arguments.length>0)for(var t=0,i=arguments.length;t1)t=e;else if(this.head)i=this.head.next,t=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var r=0;i!==null;r++)t=n(t,i.value,r),i=i.next;return t};Be.prototype.reduceReverse=function(n,e){var t,i=this.tail;if(arguments.length>1)t=e;else if(this.tail)i=this.tail.prev,t=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var r=this.length-1;i!==null;r--)t=n(t,i.value,r),i=i.prev;return t};Be.prototype.toArray=function(){for(var n=new Array(this.length),e=0,t=this.head;t!==null;e++)n[e]=t.value,t=t.next;return n};Be.prototype.toArrayReverse=function(){for(var n=new Array(this.length),e=0,t=this.tail;t!==null;e++)n[e]=t.value,t=t.prev;return n};Be.prototype.slice=function(n,e){e=e||this.length,e<0&&(e+=this.length),n=n||0,n<0&&(n+=this.length);var t=new Be;if(ethis.length&&(e=this.length);for(var i=0,r=this.head;r!==null&&ithis.length&&(e=this.length);for(var i=this.length,r=this.tail;r!==null&&i>e;i--)r=r.prev;for(;r!==null&&i>n;i--,r=r.prev)t.push(r.value);return t};Be.prototype.splice=function(n,e,...t){n>this.length&&(n=this.length-1),n<0&&(n=this.length+n);for(var i=0,r=this.head;r!==null&&i{"use strict";var Cve=Ug(),Pl=Symbol("max"),zo=Symbol("length"),Oc=Symbol("lengthCalculator"),Qg=Symbol("allowStale"),_l=Symbol("maxAge"),Ko=Symbol("dispose"),j3=Symbol("noDisposeOnSet"),gi=Symbol("lruList"),Or=Symbol("cache"),O3=Symbol("updateAgeOnGet"),Sk=()=>1,M3=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let t=this[Pl]=e.max||1/0,i=e.length||Sk;if(this[Oc]=typeof i!="function"?Sk:i,this[Qg]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[_l]=e.maxAge||0,this[Ko]=e.dispose,this[j3]=e.noDisposeOnSet||!1,this[O3]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[Pl]=e||1/0,Gg(this)}get max(){return this[Pl]}set allowStale(e){this[Qg]=!!e}get allowStale(){return this[Qg]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[_l]=e,Gg(this)}get maxAge(){return this[_l]}set lengthCalculator(e){typeof e!="function"&&(e=Sk),e!==this[Oc]&&(this[Oc]=e,this[zo]=0,this[gi].forEach(t=>{t.length=this[Oc](t.value,t.key),this[zo]+=t.length})),Gg(this)}get lengthCalculator(){return this[Oc]}get length(){return this[zo]}get itemCount(){return this[gi].length}rforEach(e,t){t=t||this;for(let i=this[gi].tail;i!==null;){let r=i.prev;A3(this,e,i,t),i=r}}forEach(e,t){t=t||this;for(let i=this[gi].head;i!==null;){let r=i.next;A3(this,e,i,t),i=r}}keys(){return this[gi].toArray().map(e=>e.key)}values(){return this[gi].toArray().map(e=>e.value)}reset(){this[Ko]&&this[gi]&&this[gi].length&&this[gi].forEach(e=>this[Ko](e.key,e.value)),this[Or]=new Map,this[gi]=new Cve,this[zo]=0}dump(){return this[gi].map(e=>Cy(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[gi]}set(e,t,i){if(i=i||this[_l],i&&typeof i!="number")throw new TypeError("maxAge must be a number");let r=i?Date.now():0,o=this[Oc](t,e);if(this[Or].has(e)){if(o>this[Pl])return Mc(this,this[Or].get(e)),!1;let l=this[Or].get(e).value;return this[Ko]&&(this[j3]||this[Ko](e,l.value)),l.now=r,l.maxAge=i,l.value=t,this[zo]+=o-l.length,l.length=o,this.get(e),Gg(this),!0}let s=new N3(e,t,o,r,i);return s.length>this[Pl]?(this[Ko]&&this[Ko](e,t),!1):(this[zo]+=s.length,this[gi].unshift(s),this[Or].set(e,this[gi].head),Gg(this),!0)}has(e){if(!this[Or].has(e))return!1;let t=this[Or].get(e).value;return!Cy(this,t)}get(e){return Tk(this,e,!0)}peek(e){return Tk(this,e,!1)}pop(){let e=this[gi].tail;return e?(Mc(this,e),e.value):null}del(e){Mc(this,this[Or].get(e))}load(e){this.reset();let t=Date.now();for(let i=e.length-1;i>=0;i--){let r=e[i],o=r.e||0;if(o===0)this.set(r.k,r.v);else{let s=o-t;s>0&&this.set(r.k,r.v,s)}}}prune(){this[Or].forEach((e,t)=>Tk(this,t,!1))}},Tk=(n,e,t)=>{let i=n[Or].get(e);if(i){let r=i.value;if(Cy(n,r)){if(Mc(n,i),!n[Qg])return}else t&&(n[O3]&&(i.value.now=Date.now()),n[gi].unshiftNode(i));return r.value}},Cy=(n,e)=>{if(!e||!e.maxAge&&!n[_l])return!1;let t=Date.now()-e.now;return e.maxAge?t>e.maxAge:n[_l]&&t>n[_l]},Gg=n=>{if(n[zo]>n[Pl])for(let e=n[gi].tail;n[zo]>n[Pl]&&e!==null;){let t=e.prev;Mc(n,e),e=t}},Mc=(n,e)=>{if(e){let t=e.value;n[Ko]&&n[Ko](t.key,t.value),n[zo]-=t.length,n[Or].delete(t.key),n[gi].removeNode(e)}},N3=class{constructor(e,t,i,r,o){this.key=e,this.value=t,this.length=i,this.now=r,this.maxAge=o||0}},A3=(n,e,t,i)=>{let r=t.value;Cy(n,r)&&(Mc(n,t),n[Qg]||(r=void 0)),r&&e.call(i,r.value,r.key,n)};B3.exports=M3});var or=m((Vje,Z3)=>{var Nc=class{constructor(e,t){if(t=Tve(t),e instanceof Nc)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new Nc(e.raw,t);if(e instanceof kk)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split("||").map(i=>this.parseRange(i.trim())).filter(i=>i.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${e}`);if(this.set.length>1){let i=this.set[0];if(this.set=this.set.filter(r=>!Y3(r[0])),this.set.length===0)this.set=[i];else if(this.set.length>1){for(let r of this.set)if(r.length===1&&Rve(r[0])){this.set=[r];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){e=e.trim();let i=`parseRange:${Object.keys(this.options).join(",")}:${e}`,r=q3.get(i);if(r)return r;let o=this.options.loose,s=o?mn[Qi.HYPHENRANGELOOSE]:mn[Qi.HYPHENRANGE];e=e.replace(s,Hve(this.options.includePrerelease)),Rt("hyphen replace",e),e=e.replace(mn[Qi.COMPARATORTRIM],Eve),Rt("comparator trim",e),e=e.replace(mn[Qi.TILDETRIM],Pve),e=e.replace(mn[Qi.CARETTRIM],_ve),e=e.split(/\s+/).join(" ");let a=e.split(" ").map(h=>Lve(h,this.options)).join(" ").split(/\s+/).map(h=>Bve(h,this.options));o&&(a=a.filter(h=>(Rt("loose invalid filter",h,this.options),!!h.match(mn[Qi.COMPARATORLOOSE])))),Rt("range list",a);let l=new Map,u=a.map(h=>new kk(h,this.options));for(let h of u){if(Y3(h))return[h];l.set(h.value,h)}l.size>1&&l.has("")&&l.delete("");let c=[...l.values()];return q3.set(i,c),c}intersects(e,t){if(!(e instanceof Nc))throw new TypeError("a Range is required");return this.set.some(i=>W3(i,t)&&e.set.some(r=>W3(r,t)&&i.every(o=>r.every(s=>o.intersects(s,t)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new kve(e,this.options)}catch{return!1}for(let t=0;tn.value==="<0.0.0-0",Rve=n=>n.value==="",W3=(n,e)=>{let t=!0,i=n.slice(),r=i.pop();for(;t&&i.length;)t=i.every(o=>r.intersects(o,e)),r=i.pop();return t},Lve=(n,e)=>(Rt("comp",n,e),n=jve(n,e),Rt("caret",n),n=Fve(n,e),Rt("tildes",n),n=Ove(n,e),Rt("xrange",n),n=Nve(n,e),Rt("stars",n),n),Ki=n=>!n||n.toLowerCase()==="x"||n==="*",Fve=(n,e)=>n.trim().split(/\s+/).map(t=>Ive(t,e)).join(" "),Ive=(n,e)=>{let t=e.loose?mn[Qi.TILDELOOSE]:mn[Qi.TILDE];return n.replace(t,(i,r,o,s,a)=>{Rt("tilde",n,i,r,o,s,a);let l;return Ki(r)?l="":Ki(o)?l=`>=${r}.0.0 <${+r+1}.0.0-0`:Ki(s)?l=`>=${r}.${o}.0 <${r}.${+o+1}.0-0`:a?(Rt("replaceTilde pr",a),l=`>=${r}.${o}.${s}-${a} <${r}.${+o+1}.0-0`):l=`>=${r}.${o}.${s} <${r}.${+o+1}.0-0`,Rt("tilde return",l),l})},jve=(n,e)=>n.trim().split(/\s+/).map(t=>Ave(t,e)).join(" "),Ave=(n,e)=>{Rt("caret",n,e);let t=e.loose?mn[Qi.CARETLOOSE]:mn[Qi.CARET],i=e.includePrerelease?"-0":"";return n.replace(t,(r,o,s,a,l)=>{Rt("caret",n,r,o,s,a,l);let u;return Ki(o)?u="":Ki(s)?u=`>=${o}.0.0${i} <${+o+1}.0.0-0`:Ki(a)?o==="0"?u=`>=${o}.${s}.0${i} <${o}.${+s+1}.0-0`:u=`>=${o}.${s}.0${i} <${+o+1}.0.0-0`:l?(Rt("replaceCaret pr",l),o==="0"?s==="0"?u=`>=${o}.${s}.${a}-${l} <${o}.${s}.${+a+1}-0`:u=`>=${o}.${s}.${a}-${l} <${o}.${+s+1}.0-0`:u=`>=${o}.${s}.${a}-${l} <${+o+1}.0.0-0`):(Rt("no pr"),o==="0"?s==="0"?u=`>=${o}.${s}.${a}${i} <${o}.${s}.${+a+1}-0`:u=`>=${o}.${s}.${a}${i} <${o}.${+s+1}.0-0`:u=`>=${o}.${s}.${a} <${+o+1}.0.0-0`),Rt("caret return",u),u})},Ove=(n,e)=>(Rt("replaceXRanges",n,e),n.split(/\s+/).map(t=>Mve(t,e)).join(" ")),Mve=(n,e)=>{n=n.trim();let t=e.loose?mn[Qi.XRANGELOOSE]:mn[Qi.XRANGE];return n.replace(t,(i,r,o,s,a,l)=>{Rt("xRange",n,i,r,o,s,a,l);let u=Ki(o),c=u||Ki(s),h=c||Ki(a),d=h;return r==="="&&d&&(r=""),l=e.includePrerelease?"-0":"",u?r===">"||r==="<"?i="<0.0.0-0":i="*":r&&d?(c&&(s=0),a=0,r===">"?(r=">=",c?(o=+o+1,s=0,a=0):(s=+s+1,a=0)):r==="<="&&(r="<",c?o=+o+1:s=+s+1),r==="<"&&(l="-0"),i=`${r+o}.${s}.${a}${l}`):c?i=`>=${o}.0.0${l} <${+o+1}.0.0-0`:h&&(i=`>=${o}.${s}.0${l} <${o}.${+s+1}.0-0`),Rt("xRange return",i),i})},Nve=(n,e)=>(Rt("replaceStars",n,e),n.trim().replace(mn[Qi.STAR],"")),Bve=(n,e)=>(Rt("replaceGTE0",n,e),n.trim().replace(mn[e.includePrerelease?Qi.GTE0PRE:Qi.GTE0],"")),Hve=n=>(e,t,i,r,o,s,a,l,u,c,h,d,g)=>(Ki(i)?t="":Ki(r)?t=`>=${i}.0.0${n?"-0":""}`:Ki(o)?t=`>=${i}.${r}.0${n?"-0":""}`:s?t=`>=${t}`:t=`>=${t}${n?"-0":""}`,Ki(u)?l="":Ki(c)?l=`<${+u+1}.0.0-0`:Ki(h)?l=`<${u}.${+c+1}.0-0`:d?l=`<=${u}.${c}.${h}-${d}`:n?l=`<${u}.${c}.${+h+1}-0`:l=`<=${l}`,`${t} ${l}`.trim()),qve=(n,e,t)=>{for(let i=0;i0){let r=n[i].semver;if(r.major===e.major&&r.minor===e.minor&&r.patch===e.patch)return!0}return!1}return!0}});var Kg=m((e1e,G3)=>{var zg=Symbol("SemVer ANY"),Vg=class{static get ANY(){return zg}constructor(e,t){if(t=Yve(t),e instanceof Vg){if(e.loose===!!t.loose)return e;e=e.value}Pk("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===zg?this.value="":this.value=this.operator+this.semver.version,Pk("comp",this)}parse(e){let t=this.options.loose?J3[$3.COMPARATORLOOSE]:J3[$3.COMPARATOR],i=e.match(t);if(!i)throw new TypeError(`Invalid comparator: ${e}`);this.operator=i[1]!==void 0?i[1]:"",this.operator==="="&&(this.operator=""),i[2]?this.semver=new X3(i[2],this.options.loose):this.semver=zg}toString(){return this.value}test(e){if(Pk("Comparator.test",e,this.options.loose),this.semver===zg||e===zg)return!0;if(typeof e=="string")try{e=new X3(e,this.options)}catch{return!1}return Ek(e,this.operator,this.semver,this.options)}intersects(e,t){if(!(e instanceof Vg))throw new TypeError("a Comparator is required");if((!t||typeof t!="object")&&(t={loose:!!t,includePrerelease:!1}),this.operator==="")return this.value===""?!0:new U3(e.value,t).test(this.value);if(e.operator==="")return e.value===""?!0:new U3(this.value,t).test(e.semver);let i=(this.operator===">="||this.operator===">")&&(e.operator===">="||e.operator===">"),r=(this.operator==="<="||this.operator==="<")&&(e.operator==="<="||e.operator==="<"),o=this.semver.version===e.semver.version,s=(this.operator===">="||this.operator==="<=")&&(e.operator===">="||e.operator==="<="),a=Ek(this.semver,"<",e.semver,t)&&(this.operator===">="||this.operator===">")&&(e.operator==="<="||e.operator==="<"),l=Ek(this.semver,">",e.semver,t)&&(this.operator==="<="||this.operator==="<")&&(e.operator===">="||e.operator===">");return i||r||o&&s||a||l}};G3.exports=Vg;var Yve=$g(),{re:J3,t:$3}=Tl(),Ek=Ck(),Pk=Jg(),X3=Li(),U3=or()});var ef=m((t1e,Q3)=>{var Wve=or(),Zve=(n,e,t)=>{try{e=new Wve(e,t)}catch{return!1}return e.test(n)};Q3.exports=Zve});var z3=m((i1e,K3)=>{var Jve=or(),$ve=(n,e)=>new Jve(n,e).set.map(t=>t.map(i=>i.value).join(" ").trim().split(" "));K3.exports=$ve});var eZ=m((n1e,V3)=>{var Xve=Li(),Uve=or(),Gve=(n,e,t)=>{let i=null,r=null,o=null;try{o=new Uve(e,t)}catch{return null}return n.forEach(s=>{o.test(s)&&(!i||r.compare(s)===-1)&&(i=s,r=new Xve(i,t))}),i};V3.exports=Gve});var iZ=m((r1e,tZ)=>{var Qve=Li(),Kve=or(),zve=(n,e,t)=>{let i=null,r=null,o=null;try{o=new Kve(e,t)}catch{return null}return n.forEach(s=>{o.test(s)&&(!i||r.compare(s)===1)&&(i=s,r=new Qve(i,t))}),i};tZ.exports=zve});var oZ=m((o1e,rZ)=>{var _k=Li(),Vve=or(),nZ=Xg(),ewe=(n,e)=>{n=new Vve(n,e);let t=new _k("0.0.0");if(n.test(t)||(t=new _k("0.0.0-0"),n.test(t)))return t;t=null;for(let i=0;i{let a=new _k(s.semver.version);switch(s.operator){case">":a.prerelease.length===0?a.patch++:a.prerelease.push(0),a.raw=a.format();case"":case">=":(!o||nZ(a,o))&&(o=a);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${s.operator}`)}}),o&&(!t||nZ(t,o))&&(t=o)}return t&&n.test(t)?t:null};rZ.exports=ewe});var aZ=m((s1e,sZ)=>{var twe=or(),iwe=(n,e)=>{try{return new twe(n,e).range||"*"}catch{return null}};sZ.exports=iwe});var Sy=m((a1e,hZ)=>{var nwe=Li(),cZ=Kg(),{ANY:rwe}=cZ,owe=or(),swe=ef(),lZ=Xg(),uZ=yy(),awe=wy(),lwe=vy(),uwe=(n,e,t,i)=>{n=new nwe(n,i),e=new owe(e,i);let r,o,s,a,l;switch(t){case">":r=lZ,o=awe,s=uZ,a=">",l=">=";break;case"<":r=uZ,o=lwe,s=lZ,a="<",l="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(swe(n,e,i))return!1;for(let u=0;u{g.semver===rwe&&(g=new cZ(">=0.0.0")),h=h||g,d=d||g,r(g.semver,h.semver,i)?h=g:s(g.semver,d.semver,i)&&(d=g)}),h.operator===a||h.operator===l||(!d.operator||d.operator===a)&&o(n,d.semver))return!1;if(d.operator===l&&s(n,d.semver))return!1}return!0};hZ.exports=uwe});var gZ=m((l1e,dZ)=>{var cwe=Sy(),hwe=(n,e,t)=>cwe(n,e,">",t);dZ.exports=hwe});var pZ=m((u1e,fZ)=>{var dwe=Sy(),gwe=(n,e,t)=>dwe(n,e,"<",t);fZ.exports=gwe});var yZ=m((c1e,bZ)=>{var mZ=or(),fwe=(n,e,t)=>(n=new mZ(n,t),e=new mZ(e,t),n.intersects(e));bZ.exports=fwe});var wZ=m((h1e,vZ)=>{var pwe=ef(),mwe=rr();vZ.exports=(n,e,t)=>{let i=[],r=null,o=null,s=n.sort((c,h)=>mwe(c,h,t));for(let c of s)pwe(c,e,t)?(o=c,r||(r=c)):(o&&i.push([r,o]),o=null,r=null);r&&i.push([r,null]);let a=[];for(let[c,h]of i)c===h?a.push(c):!h&&c===s[0]?a.push("*"):h?c===s[0]?a.push(`<=${h}`):a.push(`${c} - ${h}`):a.push(`>=${c}`);let l=a.join(" || "),u=typeof e.raw=="string"?e.raw:String(e);return l.length{var DZ=or(),Ty=Kg(),{ANY:Rk}=Ty,tf=ef(),Lk=rr(),bwe=(n,e,t={})=>{if(n===e)return!0;n=new DZ(n,t),e=new DZ(e,t);let i=!1;e:for(let r of n.set){for(let o of e.set){let s=ywe(r,o,t);if(i=i||s!==null,s)continue e}if(i)return!1}return!0},ywe=(n,e,t)=>{if(n===e)return!0;if(n.length===1&&n[0].semver===Rk){if(e.length===1&&e[0].semver===Rk)return!0;t.includePrerelease?n=[new Ty(">=0.0.0-0")]:n=[new Ty(">=0.0.0")]}if(e.length===1&&e[0].semver===Rk){if(t.includePrerelease)return!0;e=[new Ty(">=0.0.0")]}let i=new Set,r,o;for(let g of n)g.operator===">"||g.operator===">="?r=xZ(r,g,t):g.operator==="<"||g.operator==="<="?o=CZ(o,g,t):i.add(g.semver);if(i.size>1)return null;let s;if(r&&o){if(s=Lk(r.semver,o.semver,t),s>0)return null;if(s===0&&(r.operator!==">="||o.operator!=="<="))return null}for(let g of i){if(r&&!tf(g,String(r),t)||o&&!tf(g,String(o),t))return null;for(let f of e)if(!tf(g,String(f),t))return!1;return!0}let a,l,u,c,h=o&&!t.includePrerelease&&o.semver.prerelease.length?o.semver:!1,d=r&&!t.includePrerelease&&r.semver.prerelease.length?r.semver:!1;h&&h.prerelease.length===1&&o.operator==="<"&&h.prerelease[0]===0&&(h=!1);for(let g of e){if(c=c||g.operator===">"||g.operator===">=",u=u||g.operator==="<"||g.operator==="<=",r){if(d&&g.semver.prerelease&&g.semver.prerelease.length&&g.semver.major===d.major&&g.semver.minor===d.minor&&g.semver.patch===d.patch&&(d=!1),g.operator===">"||g.operator===">="){if(a=xZ(r,g,t),a===g&&a!==r)return!1}else if(r.operator===">="&&!tf(r.semver,String(g),t))return!1}if(o){if(h&&g.semver.prerelease&&g.semver.prerelease.length&&g.semver.major===h.major&&g.semver.minor===h.minor&&g.semver.patch===h.patch&&(h=!1),g.operator==="<"||g.operator==="<="){if(l=CZ(o,g,t),l===g&&l!==o)return!1}else if(o.operator==="<="&&!tf(o.semver,String(g),t))return!1}if(!g.operator&&(o||r)&&s!==0)return!1}return!(r&&u&&!o&&s!==0||o&&c&&!r&&s!==0||d||h)},xZ=(n,e,t)=>{if(!n)return e;let i=Lk(n.semver,e.semver,t);return i>0?n:i<0||e.operator===">"&&n.operator===">="?e:n},CZ=(n,e,t)=>{if(!n)return e;let i=Lk(n.semver,e.semver,t);return i<0?n:i>0||e.operator==="<"&&n.operator==="<="?e:n};SZ.exports=bwe});var nf=m((g1e,kZ)=>{var Fk=Tl();kZ.exports={re:Fk.re,src:Fk.src,tokens:Fk.t,SEMVER_SPEC_VERSION:Zg().SEMVER_SPEC_VERSION,SemVer:Li(),compareIdentifiers:gy().compareIdentifiers,rcompareIdentifiers:gy().rcompareIdentifiers,parse:kl(),valid:XW(),clean:GW(),inc:zW(),diff:r3(),major:s3(),minor:l3(),patch:c3(),prerelease:d3(),compare:rr(),rcompare:f3(),compareLoose:m3(),compareBuild:by(),sort:w3(),rsort:x3(),gt:Xg(),lt:yy(),eq:my(),neq:xk(),gte:vy(),lte:wy(),cmp:Ck(),coerce:R3(),Comparator:Kg(),Range:or(),satisfies:ef(),toComparators:z3(),maxSatisfying:eZ(),minSatisfying:iZ(),minVersion:oZ(),validRange:aZ(),outside:Sy(),gtr:gZ(),ltr:pZ(),intersects:yZ(),simplifyRange:wZ(),subset:TZ()}});var Bc,EZ,Ik,m1e,ky,PZ=_(()=>{"use strict";Bc=C(require("path")),EZ=C(require("fs"));z();Je();Ik=C(dg()),m1e=q()("model-resolver"),ky=class{get nodeFolder(){return sg("npm")?this._npmFolder?Promise.resolve(this._npmFolder):Vr("npm --loglevel silent root -g",{},3e3).then(e=>(this._npmFolder=(0,Ik.default)(e).trim(),this._npmFolder)):Promise.resolve("")}get yarnFolder(){return sg("yarnpkg")?this._yarnFolder?Promise.resolve(this._yarnFolder):Vr("yarnpkg global dir",{},3e3).then(e=>{let t=Bc.default.join((0,Ik.default)(e).trim(),"node_modules"),i=EZ.default.existsSync(t);return i&&(this._yarnFolder=t),i?t:""}):Promise.resolve("")}async resolveModule(e){let t=await this.nodeFolder,i=await this.yarnFolder;if(i){let r=await Ht(Bc.default.join(i,e,"package.json"));if(r&&r.isFile())return Bc.default.join(i,e)}if(t){let r=await Ht(Bc.default.join(t,e,"package.json"));if(r&&r.isFile())return Bc.default.join(t,e)}return null}}});function FZ(n,e){if(!e.startsWith("nvim-")&&!e.startsWith("patch-"))throw new Error("Feature param could only starts with nvim and patch");if(!n.isVim&&e.startsWith("patch-")||n.isVim&&e.startsWith("nvim-"))return!1;if(n.isVim){let[t,i,r,o]=n.version.match(/^(\d)(\d{2})(\d+)$/),s=`${i}.${parseInt(r,10)}.${parseInt(o,10)}`;return Ak.default.gte(s,e.slice(6))}return Ak.default.gte(n.version,e.slice(5))}function IZ(n=""){return jk.has(n)?jk.get(n):(Ey=Ey+1,jk.set(n,Ey),Ey)}function jZ(n){let t=n.getConfiguration("coc.preferences").get("watchmanPath","watchman");try{return LZ.default.sync(t)}catch{return null}}async function AZ(n,e,t){let i=await n.call("expand","%:p");i=rf.default.normalize(i);let r=i&&rf.default.isAbsolute(i);if(r&&!Ae(e,i,!0))return Dc(t,rf.default.dirname(i));let o=Dc(t,e);return o&&o!=RZ.default.homedir()?o:r?Dc(t,rf.default.dirname(i)):null}function OZ(n){return vwe.resolveModule(n)}function Ok(n,e,t){if(Array.isArray(n)){let i=0;for(let r of n){let o=Ok(r,e,t);if(o===10)return o;o>i&&(i=o)}return i}else{if(typeof n=="string")return n==="*"?5:n===t?10:0;if(n){let i=O.parse(e),{language:r,pattern:o,scheme:s}=n,a=0;if(s)if(s===i.scheme)a=5;else if(s==="*")a=3;else return 0;if(r)if(r===t)a=10;else if(r==="*")a=Math.max(a,5);else return 0;if(o){let l=Xi||sc,u=l?o.toLowerCase():o,c=l?i.fsPath.toLowerCase():i.fsPath;if(u===c||(0,_Z.default)(c,u,{dot:!0}))a=5;else return 0}return a}else return 0}}var _Z,RZ,rf,Ak,LZ,Ey,vwe,jk,MZ=_(()=>{"use strict";_Z=C(Vn()),RZ=C(require("os")),rf=C(require("path")),Ak=C(nf());we();LZ=C(rg());PZ();Je();ac();Ey=2e3,vwe=new ky,jk=new Map});var Py,wwe,_y,NZ=_(()=>{"use strict";Oe();Py=C(H());z();wwe=q()("core-keymaps"),_y=class{constructor(e){this.documents=e;this.keymaps=new Map}attach(e){this.nvim=e}async doKeymap(e,t="",i){let r=this.keymaps.get(e);if(!r)return wwe.error(`keymap for ${e} not found`),i&&this.nvim.command(`silent! unmap ${i.startsWith("{")&&i.endsWith("}")?`<${i.slice(1,-1)}>`:i}`,!0),t;let[o,s]=r,a=await Promise.resolve(o());return s&&await this.nvim.command(`silent! call repeat#set("\\(coc-${e})", -1)`),a!=null?a:t}registerKeymap(e,t,i,r={}){if(!t)throw new Error(`Invalid key ${t} of registerKeymap`);if(this.keymaps.has(t))throw new Error(`${t} already exists.`);r=Object.assign({sync:!0,cancel:!0,silent:!0,repeat:!1},r);let{nvim:o}=this;this.keymaps.set(t,[i,!!r.repeat]);let s=r.sync?"request":"notify",a=r.silent?"":"";for(let l of e)if(l=="i")o.command(`inoremap ${a} (coc-${t}) coc#_insert_key('${s}', '${t}', ${r.cancel?1:0})`,!0);else{let u=L0(l);o.command(`${l}noremap ${a} (coc-${t}) :${u}call coc#rpc#${s}('doKeymap', ['${t}'])`,!0)}return Py.Disposable.create(()=>{this.keymaps.delete(t);for(let l of e)o.command(`${l}unmap (coc-${t})`,!0)})}registerExprKeymap(e,t,i,r=!1){let o=`${e}${global.Buffer.from(t).toString("base64")}${r?"1":"0"}`,{nvim:s}=this;return this.keymaps.set(o,[i,!1]),e=="i"?s.command(`inoremap ${r?"":""} ${t} coc#_insert_key('request', '${o}')`,!0):s.command(`${e}noremap ${r?"":""} ${t} coc#rpc#request('doKeymap', ['${o}'])`,!0),Py.Disposable.create(()=>{this.keymaps.delete(o),s.command(`${e}unmap ${r?"":""} ${t}`,!0)})}registerLocalKeymap(e,t,i,r=!1){let o=Uo(),{nvim:s}=this,a=this.documents.bufnr;this.keymaps.set(o,[i,!1]);let l=r?"notify":"request",u=L0(e),c=t.startsWith("<")&&t.endsWith(">")?`{${t.slice(1,-1)}}`:t;if(this.nvim.hasFunction("nvim_buf_set_keymap")&&!global.hasOwnProperty("__TEST__"))s.call("nvim_buf_set_keymap",[0,e,t,`:${u}call coc#rpc#${l}('doKeymap', ['${o}', '', '${c}'])`,{silent:!0,nowait:!0}],!0);else{let h=`${e}noremap ${t} :${u}call coc#rpc#${l}('doKeymap', ['${o}', '', '${c}'])`;s.command(h,!0)}return Py.Disposable.create(()=>{this.keymaps.delete(o),s.call("coc#compat#buf_del_keymap",[a,e,t],!0)})}}});var k1e,Ry,BZ=_(()=>{"use strict";z();k1e=q()("core-locations"),Ry=class{constructor(e,t,i){this.configurations=e;this.documents=t;this.contentProvider=i;this.disposables=[]}attach(e,t){this.nvim=e,this.env=t}async showLocations(e){let{documents:t,nvim:i,env:r,configurations:o}=this,s=await t.getQuickfixList(e);if(o.getConfiguration("coc.preferences").get("useQuickfixForLocations",!1)){let l=await i.getVar("coc_quickfix_open_command");typeof l!="string"&&(l=s.length<10?`copen ${s.length}`:"copen"),i.pauseNotification(),i.call("setqflist",[s],!0),i.command(l,!0),i.resumeNotification(!1,!0)}else await i.setVar("coc_jump_locations",s),r.locationlist?i.command("CocList --normal --auto-preview location",!0):i.call("coc#util#do_autocmd",["CocLocationsChange"],!0)}dispose(){Z(this.disposables)}}});var Hc,L1e,Ly,HZ=_(()=>{"use strict";le();Hc=C(H());z();L1e=q()("core-watchers"),Ly=class{constructor(){this.watchedOptions=new Set;this.disposables=[];this._onDidRuntimePathChange=new Hc.Emitter;this._onDidOptionChange=new Hc.Emitter;this.onDidRuntimePathChange=this._onDidRuntimePathChange.event;this.onDidOptionChange=this._onDidOptionChange.event}get options(){return Array.from(this.watchedOptions)}attach(e,t){this.nvim=e,this.env=t,this.watchOption("runtimepath",(i,r)=>{let o=i.split(","),a=r.split(",").filter(l=>!o.includes(l));a.length>0&&this._onDidRuntimePathChange.fire(a),this.env.runtimepath=r},this.disposables)}watchOption(e,t,i){let r=this.watchedOptions.has(e);r||(this.watchedOptions.add(e),this._onDidOptionChange.fire());let o=E.on("OptionSet",async(s,a,l)=>{s==e&&t&&await Promise.resolve(t(a,l))});i&&i.push(Hc.Disposable.create(()=>{o.dispose(),!r&&(this.watchedOptions.delete(e),this._onDidOptionChange.fire())}))}watchGlobal(e,t,i){let{nvim:r}=this;r.call("coc#_watch",e,!0);let o=E.on("GlobalChange",async(s,a,l)=>{s==e&&await Promise.resolve(t(a,l))});i&&i.push(Hc.Disposable.create(()=>{o.dispose(),r.call("coc#_unwatch",e,!0)}))}dispose(){Z(this.disposables),this._onDidOptionChange.dispose(),this._onDidRuntimePathChange.dispose()}}});var of,qZ,Fy,YZ=_(()=>{"use strict";of=C(H());le();ke();qZ=q()("core-editors"),Fy=class{constructor(e){this.documents=e;this.disposables=[];this.editors=new Map;this._onDidChangeActiveTextEditor=new of.Emitter;this._onDidChangeVisibleTextEditors=new of.Emitter;this.onDidChangeActiveTextEditor=this._onDidChangeActiveTextEditor.event;this.onDidChangeVisibleTextEditors=this._onDidChangeVisibleTextEditors.event}get activeTextEditor(){return this.editors.get(this.winid)}get visibleTextEditors(){return Array.from(this.editors.values())}onChange(e){let t=`${e.winid}-${e.document.bufnr}-${e.document.uri}`;t!=this.previousId&&(this.previousId=t,this._onDidChangeActiveTextEditor.fire(e))}async attach(e){this.nvim=e;let{documents:t}=this,i=t.getDocument(t.bufnr);i&&i.winid>0&&(this.winid=i.winid,await this.createTextEditor(this.winid)),E.on("WinEnter",r=>{this.winid=r;let o=this.editors.get(r);o&&this.onChange(o)},null,this.disposables),E.on("CursorHold",async()=>{let[r,o,s]=await e.eval("[win_getid(),&buftype,coc#window#is_float(win_getid())]"),a=!1;!s&&["","acwrite"].includes(o)&&!this.editors.has(r)&&await this.createTextEditor(r)&&(a=!0),a&&this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors)},null,this.disposables),E.on("WinClosed",r=>{this.editors.has(r)&&(this.editors.delete(r),this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors))},null,this.disposables),E.on("BufWinEnter",async(r,o)=>{this.winid=o,await this.createTextEditor(o,!0)},null,this.disposables)}async createTextEditor(e,t=!1){let{documents:i,nvim:r}=this,o=await r.call("coc#util#get_editoroption",[e]);if(!o)return!1;let s=!1;if(t)for(let l of this.editors.keys())o.winids.includes(l)||(s=!0,this.editors.delete(l));let a=i.getDocument(o.bufnr);if(a){let l=this.fromOptions(o,a);return this.editors.set(e,l),e==this.winid&&this.onChange(l),this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors),qZ.debug("editor created winid & bufnr & tabnr: ",e,o.bufnr,o.tabpagenr),!0}else s&&this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors);return qZ.error(`document not found for window: ${e}`),!1}fromOptions(e,t){let{visibleRanges:i}=e,r=k.getTabId(e.tabpagenr);return{get tabpagenr(){return k.getTabNumber(r)},winid:e.winid,winnr:e.winnr,document:t,visibleRanges:i.map(o=>of.Range.create(o[0]-1,0,o[1],0)),options:{tabSize:e.tabSize,insertSpaces:!!e.insertSpaces}}}}});function sf(n){if(!(!n||!af.default.isAbsolute(n)))return{name:af.default.basename(n),uri:O.file(n).toString()}}var af,WZ,Iy,ZZ=_(()=>{"use strict";af=C(require("path")),WZ=C(H());we();Fr();Go();Je();Iy=class{constructor(e){this.configurations=e;this._onDidChangeWorkspaceFolders=new WZ.Emitter;this.onDidChangeWorkspaceFolders=this._onDidChangeWorkspaceFolders.event;this.rootPatterns=new Map;this._workspaceFolders=[]}setWorkspaceFolders(e){if(!e||!Array.isArray(e))return;let t=e.map(i=>sf(i));this._workspaceFolders=t.filter(i=>i!=null)}getWorkspaceFolder(e){if(e.scheme!=="file")return;let t=Array.from(this._workspaceFolders).map(o=>O.parse(o.uri).fsPath);t.sort((o,s)=>s.length-o.length);let i=e.fsPath,r=t.find(o=>Ae(o,i,!0));return sf(r)}getRelativePath(e,t){let i,r="";if(typeof e=="string"?(i=O.file(e),r=e):typeof e<"u"&&(i=e,r=e.fsPath),!i)return r;let o=this.getWorkspaceFolder(i);if(!o)return r;typeof t>"u"&&this._workspaceFolders&&(t=this._workspaceFolders.length>1);let s=af.default.relative(O.parse(o.uri).fsPath,i.fsPath);return s=s==""?i.fsPath:s,t&&o.name&&(s=`${o.name}/${s}`),s}get workspaceFolders(){return this._workspaceFolders}addRootPattern(e,t){let i=this.rootPatterns.get(e)||[];for(let r of t)i.includes(r)||i.push(r);this.rootPatterns.set(e,i)}resolveRoot(e,t,i,r){if(e.buftype!==""||e.schema!=="file"||!e.enabled)return null;let o=[0,1,2],s=O.parse(e.uri),a=af.default.dirname(s.fsPath),l=this.configurations.getConfiguration("workspace",e.uri),u=l.get("ignoredFiletypes",[]),c=l.get("bottomUpFiletypes",[]),h=l.get("workspaceFolderCheckCwd",!0),d=l.get("ignoredFolders",[]),g=l.get("workspaceFolderFallbackCwd",!0);if(u!=null&&u.includes(e.filetype))return null;let f=this.getWorkspaceFolder(O.parse(e.uri));if(f)return O.parse(f.uri).fsPath;d=Array.isArray(d)?d.filter(b=>b&&b.length>0).map(b=>r(b)):[];let p=null;for(let b of o){let v=this.getRootPatterns(e,b);if(v&&v.length){let w=c.includes("*")||c.includes(e.filetype),D=mb(a,v,t,w,h,d);if(D){p=D;break}}}return g&&!p&&!d.includes(t)&&Ae(t,a,!0)&&(p=t),p&&this.addWorkspaceFolder(p,i),p}addWorkspaceFolder(e,t){let i=sf(e);if(!!i)return this._workspaceFolders.findIndex(r=>r.uri==i.uri)==-1&&(this._workspaceFolders.push(i),t&&this._onDidChangeWorkspaceFolders.fire({added:[i],removed:[]})),i}renameWorkspaceFolder(e,t){let i=sf(t);if(!i)return;let r=this._workspaceFolders.findIndex(s=>O.parse(s.uri).fsPath==e);if(r==-1)return;let o=this.workspaceFolders[r];this._workspaceFolders.splice(r,1,i),this._onDidChangeWorkspaceFolders.fire({removed:[o],added:[i]})}removeWorkspaceFolder(e){let t=sf(e);if(!t)return;let i=this._workspaceFolders.findIndex(r=>r.uri==t.uri);i!=-1&&(this._workspaceFolders.splice(i,1),this._onDidChangeWorkspaceFolders.fire({removed:[t],added:[]}))}getRootPatterns(e,t){let{uri:i}=e;return t==0?e.getVar("root_patterns",[])||[]:t==1?this.getServerRootPatterns(e.languageId):this.configurations.getConfiguration("coc.preferences",i).get("rootPatterns",[".git",".hg",".projections.json"]).slice()}reset(){this.rootPatterns.clear(),this._workspaceFolders=[]}getServerRootPatterns(e){let t=this.configurations.getConfiguration().get("languageserver",{}),i=[];for(let r of Object.keys(t)){let o=t[r],{filetypes:s,rootPatterns:a}=o;Array.isArray(s)&&a&&s.includes(e)&&i.push(...a)}return i=i.concat(this.rootPatterns.get(e)||[]),i.length?sa(i):[]}}});var jy,JZ=_(()=>{"use strict";le();z();jy=class{constructor(e,t){this._create=e;this.disposables=[];this.itemsMap=new Map;let{disposables:i}=this;for(let r of t.documents)this.create(r);t.onDidOpenTextDocument(r=>{this.create(t.getDocument(r.bufnr))},null,i),t.onDidChangeDocument(r=>{this.onChange(r)},null,i),t.onDidCloseDocument(r=>{this.delete(r.bufnr)},null,i),E.on("LinesChanged",r=>{let o=this.itemsMap.get(r);o&&typeof o.item.onTextChange=="function"&&o.item.onTextChange()},null,i)}get items(){return Array.from(this.itemsMap.values()).map(e=>e.item)}getItem(e){var i;if(typeof e=="number")return(i=this.itemsMap.get(e))==null?void 0:i.item;let t=Array.from(this.itemsMap.values()).find(r=>r.uri==e);return t?t.item:void 0}create(e){if(!e)return;let t=this.itemsMap.get(e.bufnr);t&&t.item.dispose();let i=this._create(e);i&&this.itemsMap.set(e.bufnr,{uri:e.uri,item:i})}onChange(e){let t=this.itemsMap.get(e.bufnr);t&&typeof t.item.onChange=="function"&&t.item.onChange(e)}delete(e){let t=this.itemsMap.get(e);t&&(t.item.dispose(),this.itemsMap.delete(e))}reset(){for(let e of this.itemsMap.values())e.item.dispose();this.itemsMap.clear()}dispose(){Z(this.disposables);for(let e of this.itemsMap.values())e.item.dispose();this._create=void 0,this.itemsMap.clear()}}});var An,Mk,qc,Nk=_(()=>{"use strict";An=C(Rn()),Mk=C(require("path")),qc=class{constructor(e){this.filepath=e}fetch(e){let t=this.load();if(!e)return t;let i=e.split(".");for(let r of i){if(typeof t[r]>"u")return;t=t[r]}return t}exists(e){let t=this.load(),i=e.split(".");for(let r of i){if(typeof t[r]>"u")return!1;t=t[r]}return!0}delete(e){let t=this.load(),i=t,r=e.split("."),o=r.length;for(let s=0;s"u");s++){if(s==o-1){delete t[r[s]],An.default.writeFileSync(this.filepath,JSON.stringify(i,null,2),"utf8");break}t=t[r[s]]}}push(e,t){let i=this.load()||{},r=i,o=e.split("."),s=o.length;if(r==null){let a=Mk.default.dirname(this.filepath);An.default.mkdirpSync(a),r=i}for(let a=0;a"u"&&(r[l]={}),r=r[l]}}load(){let e=Mk.default.dirname(this.filepath),t=An.default.statSync(e);if(!t||!t.isDirectory())return An.default.mkdirpSync(e),An.default.writeFileSync(this.filepath,"{}","utf8"),{};try{let i=An.default.readFileSync(this.filepath,"utf8");return JSON.parse(i.trim())}catch{return An.default.writeFileSync(this.filepath,"{}","utf8"),{}}}clear(){let e=An.default.statSync(this.filepath);!e||!e.isFile()||An.default.writeFileSync(this.filepath,"{}","utf8")}destroy(){An.default.existsSync(this.filepath)&&An.default.unlinkSync(this.filepath)}}});var Bk,ca,oo,lf=_(()=>{"use strict";Bk=C(require("path")),ca=C(Rn());Je();Go();oo=class{constructor(e,t,i=5e3){this.maximum=i;this.file=Bk.default.join(t||process.env.COC_DATA_HOME,e);let r=Bk.default.dirname(this.file);ca.default.mkdirpSync(r)}async load(){try{let e=await ia(this.file,0,this.maximum);return e.length>this.maximum&&await bb(this.file,e.join(` -`)),e[e.length-1]==""&&(e=e.slice(0,-1)),sa(e)}catch{return[]}}loadSync(){if(!ca.default.existsSync(this.file))return[];try{let e=ca.default.readFileSync(this.file,"utf8");return e=e.trim(),e.length?e.trim().split(` -`):[]}catch{return[]}}async add(e){let t;try{t=ca.default.readFileSync(this.file),t[0]===239&&t[1]===187&&t[2]===191&&(t=t.slice(3)),t=Buffer.concat([Buffer.from(e,"utf8"),new Uint8Array([10]),t])}catch{t=Buffer.concat([Buffer.from(e,"utf8"),new Uint8Array([10])])}await ca.default.writeFile(this.file,t,"utf8")}async remove(e){let t=await this.load(),i=t.length;t=t.filter(r=>r!=e),t.length!=i&&await ca.default.writeFile(this.file,t.join(` -`),"utf8")}async clean(){try{await ca.default.unlink(this.file)}catch{}}}});var Ay,Oy,$Z=_(()=>{"use strict";Ay=C(H());le();z();Oy=class{constructor(e,t){this.nvim=e;this.id=t;this.disposables=[];this._onExit=new Ay.Emitter;this._onStderr=new Ay.Emitter;this._onStdout=new Ay.Emitter;this.onExit=this._onExit.event;this.onStdout=this._onStdout.event;this.onStderr=this._onStderr.event;E.on("TaskExit",(i,r)=>{i==this.id&&this._onExit.fire(r)},null,this.disposables),E.on("TaskStderr",(i,r)=>{i==this.id&&this._onStderr.fire(r)},null,this.disposables),E.on("TaskStdout",(i,r)=>{i==this.id&&this._onStdout.fire(r)},null,this.disposables)}async start(e){let{nvim:t}=this;return await t.call("coc#task#start",[this.id,e])}async stop(){let{nvim:e}=this;await e.call("coc#task#stop",[this.id])}get running(){let{nvim:e}=this;return e.call("coc#task#running",[this.id])}dispose(){let{nvim:e}=this;e.call("coc#task#stop",[this.id],!0),this._onStdout.dispose(),this._onStderr.dispose(),this._onExit.dispose(),Z(this.disposables)}}});var GZ,Hk,ha,XZ,UZ,Dwe,QZ,y,V=_(()=>{"use strict";GZ=C(Rn()),Hk=C(require("os")),ha=C(require("path"));we();kT();fY();mY();vY();wb();wY();$Y();iW();RW();MZ();NZ();BZ();Tb();HZ();YZ();ZZ();le();JZ();Nk();lf();$Z();z();XZ=30,UZ=q()("workspace"),Dwe=["showMessage","runTerminalCommand","openTerminal","showQuickpick","menuPick","openLocalConfig","showPrompt","createStatusBarItem","createOutputChannel","showOutputChannel","requestInput","echoLines","getCursorPosition","moveTo","getOffset","getSelectedRange","selectRange","createTerminal"],QZ=class{constructor(){this.version=kb;let e=ha.default.normalize(process.env.COC_VIMCONFIG)||ha.default.join(Hk.default.homedir(),".vim"),t=ha.default.join(e,Er);this.configurations=new Xo(t,new Nb(this)),this.workspaceFolderControl=new Iy(this.configurations);let i=this.documentsManager=new Kb(this.configurations,this.workspaceFolderControl);this.contentProvider=new Hb(i),this.watchers=new Ly,this.autocmds=new Bb(this.contentProvider,this.watchers),this.keymaps=new _y(i),this.locations=new Ry(this.configurations,i,this.contentProvider),this.files=new oy(i,this.configurations,this.workspaceFolderControl,this.keymaps),this.editors=new Fy(i),this.onDidRuntimePathChange=this.watchers.onDidRuntimePathChange,this.onDidChangeWorkspaceFolders=this.workspaceFolderControl.onDidChangeWorkspaceFolders,this.onDidChangeConfiguration=this.configurations.onDidChange,this.onDidOpenTextDocument=i.onDidOpenTextDocument,this.onDidChangeTextDocument=i.onDidChangeDocument,this.onDidCloseTextDocument=i.onDidCloseDocument,this.onDidSaveTextDocument=i.onDidSaveTextDocument,this.onWillSaveTextDocument=i.onWillSaveTextDocument,this.onDidCreateFiles=this.files.onDidCreateFiles,this.onDidRenameFiles=this.files.onDidRenameFiles,this.onDidDeleteFiles=this.files.onDidDeleteFiles,this.onWillCreateFiles=this.files.onWillCreateFiles,this.onWillRenameFiles=this.files.onWillRenameFiles,this.onWillDeleteFiles=this.files.onWillDeleteFiles;let r=global.__TEST__?null:this.getWatchmanPath();this.fileSystemWatchers=new Wg(this.workspaceFolderControl,r)}async init(e){let{nvim:t}=this;for(let o of Dwe)Object.defineProperty(this,o,{get:()=>(...s)=>{let a=` -`+Error().stack.split(` -`).slice(2,4).join(` -`);return UZ.warn(`workspace.${o} is deprecated, please use window.${o} instead.`,a),e[o].apply(e,s)}});for(let o of["onDidOpenTerminal","onDidCloseTerminal"])Object.defineProperty(this,o,{get:()=>{let s=` -`+Error().stack.split(` -`).slice(2,4).join(` -`);return UZ.warn(`workspace.${o} is deprecated, please use window.${o} instead.`,s),e[o]}});let i=this._env=await t.call("coc#util#vim_info");e.init(i),this._env.apiversion!=XZ&&t.echoError(`API version ${this._env.apiversion} is not ${XZ}, please build coc.nvim by 'yarn install' after pull source code.`),this.workspaceFolderControl.setWorkspaceFolders(this._env.workspaceFolders),this.configurations.updateUserConfig(this._env.config),this.files.attach(t,i,e),this.contentProvider.attach(t),this.keymaps.attach(t),this.autocmds.attach(t,i),this.locations.attach(t,i),this.watchers.attach(t,i),await this.attach(),await this.editors.attach(t);let r=$o.create("watchman",t);this.fileSystemWatchers.attach(r)}get cwd(){return this.documentsManager.cwd}get env(){return this._env}get root(){return this.documentsManager.root||this.cwd}get rootPath(){return this.root}get bufnr(){return this.documentsManager.bufnr}get insertMode(){return E.insertMode}get floatSupported(){return this.env.floating||this.env.textprop}get uri(){return this.documentsManager.uri}get workspaceFolder(){return this.workspaceFolders[0]}get textDocuments(){return this.documentsManager.textDocuments}get documents(){return this.documentsManager.documents}get document(){return this.documentsManager.document}get workspaceFolders(){return this.workspaceFolderControl.workspaceFolders}get folderPaths(){return this.workspaceFolders.map(e=>O.parse(e.uri).fsPath)}get channelNames(){return $o.names}get pluginRoot(){return ha.default.dirname(__dirname)}get isVim(){return this._env.isVim}get isNvim(){return!this._env.isVim}get completeOpt(){return this._env.completeOpt}get filetypes(){return this.documentsManager.filetypes}get languageIds(){return this.documentsManager.languageIds}createNameSpace(e){return IZ(e)}getConfigFile(e){return this.configurations.getConfigFile(e)}has(e){return FZ(this.env,e)}registerAutocmd(e){return this.autocmds.registerAutocmd(e)}watchOption(e,t,i){this.watchers.watchOption(e,t,i)}watchGlobal(e,t,i){this.watchers.watchGlobal(e,t||function(){},i)}match(e,t){return Ok(e,t.uri,t.languageId)}createFileSystemWatcher(e,t,i,r){return this.fileSystemWatchers.createFileSystemWatcher(e,t,i,r)}getWatchmanPath(){return jZ(this.configurations)}getConfiguration(e,t){return this.configurations.getConfiguration(e,t)}getDocument(e){return this.documentsManager.getDocument(e)}isAttached(e){let t=this.documentsManager.getDocument(e);return t!=null&&t.attached}getAttachedDocument(e){let t=this.getDocument(e);if(!t)throw new Error(`Buffer ${e} not created.`);if(!t.attached)throw new Error(`Buffer ${e} not attached, try :CocCommand document.checkBuffer`);return t}getQuickfixItem(e,t,i="",r){return this.documentsManager.getQuickfixItem(e,t,i,r)}createMru(e){return new oo(e)}async getQuickfixList(e){return this.documentsManager.getQuickfixList(e)}async showLocations(e){await this.locations.showLocations(e)}getLine(e,t){return this.documentsManager.getLine(e,t)}getWorkspaceFolder(e){return this.workspaceFolderControl.getWorkspaceFolder(O.parse(e))}readFile(e){return this.documentsManager.readFile(e)}async getCurrentState(){let e=await this.document,t=await Cb(this.nvim);return{document:e.textDocument,position:t}}async getFormatOptions(e){return this.documentsManager.getFormatOptions(e)}resolveModule(e){return OZ(e)}async runCommand(e,t,i){return t=t||this.cwd,Vr(e,{cwd:t},i)}expand(e){return this.documentsManager.expand(e)}async callAsync(e,t){return this.isNvim?await this.nvim.call(e,t):await this.nvim.callAsync("coc#util#with_callback",[e,t])}registerTextDocumentContentProvider(e,t){return this.contentProvider.registerTextDocumentContentProvider(e,t)}registerKeymap(e,t,i,r={}){return this.keymaps.registerKeymap(e,t,i,r)}registerExprKeymap(e,t,i,r=!1){return this.keymaps.registerExprKeymap(e,t,i,r)}registerLocalKeymap(e,t,i,r=!1){return this.keymaps.registerLocalKeymap(e,t,i,r)}createTask(e){return new Oy(this.nvim,e)}createDatabase(e){let t;global.hasOwnProperty("__TEST__")?(t=ha.default.join(Hk.default.tmpdir(),`coc-${process.pid}`),GZ.default.mkdirpSync(t)):t=ha.default.dirname(this.env.extensionRoot);let i=ha.default.join(t,e+".json");return new qc(i)}registerBufferSync(e){return new jy(e,this.documentsManager)}async attach(){await this.documentsManager.attach(this.nvim,this._env)}jumpTo(e,t,i){return this.files.jumpTo(e,t,i)}findUp(e){return AZ(this.nvim,this.cwd,e)}applyEdit(e){return this.files.applyEdit(e)}createFile(e,t={}){return this.files.createFile(e,t)}loadFile(e){return this.files.loadResource(e)}async loadFiles(e){return this.files.loadResources(e)}async renameFile(e,t,i={}){await this.files.renameFile(e,t,i)}async deleteFile(e,t={}){await this.files.deleteFile(e,t)}async renameCurrent(){await this.files.renameCurrent()}async openResource(e){await this.files.openResource(e)}openTextDocument(e){return this.files.openTextDocument(e)}getRelativePath(e,t){return this.workspaceFolderControl.getRelativePath(e,t)}async findFiles(e,t,i,r){return this.files.findFiles(e,t,i,r)}detach(){this.documentsManager.detach()}reset(){this.configurations.reset(),this.workspaceFolderControl.reset(),this.documentsManager.reset()}dispose(){this.watchers.dispose(),this.autocmds.dispose(),this.contentProvider.dispose(),this.documentsManager.dispose(),this.configurations.dispose()}},y=new QZ});function qk(n,e){let{range:t,uri:i}=e;n.find(r=>r.uri==i&&Fe(r.range,t))==null&&n.push(e)}var Yc,xwe,pe,Tt=_(()=>{"use strict";Yc=C(H());V();Jt();xwe=q()("provider-manager"),pe=class{constructor(){this.providers=new Set}hasProvider(e){return this.getProvider(e)!=null}getProvider(e){let t=0,i;for(let r of this.providers){let{selector:o,priority:s}=r,a=y.match(o,e);a!=0&&(typeof s=="number"&&(a=s),!(ai.id==e);return t?t.provider:null}getProviders(e){let t=Array.from(this.providers);return t=t.filter(i=>y.match(i.selector,e)>0),t.sort((i,r)=>y.match(r.selector,e)-y.match(i.selector,e))}toLocations(e){let t=[];for(let i of e)if(!!i)if(Yc.Location.is(i))qk(t,i);else if(Array.isArray(i)){for(let r of i)if(Yc.Location.is(r))qk(t,r);else if(Yc.LocationLink.is(r)){let{targetUri:o,targetSelectionRange:s,targetRange:a}=r;qk(t,Yc.Location.create(o,s||a))}}else xwe.error("Bad definition",i);return t}}});var KZ,My,zZ=_(()=>{"use strict";KZ=C(H());Tt();Oe();My=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),KZ.Disposable.create(()=>{this.providers.delete(i)})}async prepareCallHierarchy(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return o.prepareCallHierarchy===null?null:await Promise.resolve(o.prepareCallHierarchy(e,t,i))}async provideCallHierarchyOutgoingCalls(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return o.provideCallHierarchyOutgoingCalls===null?null:await Promise.resolve(o.provideCallHierarchyOutgoingCalls(t,i))}async provideCallHierarchyIncomingCalls(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return o.provideCallHierarchyIncomingCalls(t,i)===null?null:await Promise.resolve(o.provideCallHierarchyIncomingCalls(t,i))}}});function eJ(n,...e){return n=Object(n),e.forEach(t=>{if(t!=null){t=Object(t);for(let i in t){let r=n[i];(r===void 0||r===VZ[i]&&!Cwe.call(n,i))&&(n[i]=t[i])}}}),n}function zi(n,e){let t={};for(let i of Object.keys(n))e.includes(i)||(t[i]=n[i]);return t}var VZ,Cwe,Vo=_(()=>{"use strict";VZ=Object.prototype,Cwe=VZ.hasOwnProperty});var Ny,nOe,By,tJ=_(()=>{"use strict";Ny=C(H());Tt();Oe();Vo();nOe=q()("codeActionManager"),By=class extends pe{register(e,t,i,r){let o={id:re(),selector:e,provider:t,kinds:r,clientId:i};return this.providers.add(o),Ny.Disposable.create(()=>{this.providers.delete(o)})}async provideCodeActions(e,t,i,r){let o=this.getProviders(e);if(!o.length)return null;if(i.only){let{only:a}=i;o=o.filter(l=>!(l.kinds&&!l.kinds.some(u=>a.includes(u))))}let s=[];return await Promise.all(o.map(a=>{let{provider:l,id:u}=a;return Promise.resolve(l.provideCodeActions(e,t,i,r)).then(c=>{if(!(!c||c.length==0))for(let h of c)if(Ny.Command.is(h)){let d={title:h.title,command:h,providerId:u};s.push(d)}else{if(i.only){if(!h.kind)continue;let g=!1;for(let f of i.only)if(h.kind.startsWith(f)){g=!0;break}if(!g)continue}s.findIndex(g=>g.title==h.title)==-1&&s.push(Object.assign({providerId:u},h))}})})),s}async resolveCodeAction(e,t){if(e.edit!=null)return e;let i=e.providerId;if(!i)throw new Error("provider id not found from codeAction");let r=this.getProviderById(i);return!r||typeof r.resolveCodeAction!="function"?e:await Promise.resolve(r.resolveCodeAction(zi(e,["providerId"]),t))||e}}});var iJ,Hy,nJ=_(()=>{"use strict";iJ=C(H());Tt();Oe();Vo();Hy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),iJ.Disposable.create(()=>{this.providers.delete(i)})}async provideCodeLenses(e,t){let i=this.getProviders(e);if(!i.length)return null;let r=await Promise.all(i.map(o=>{let{provider:s,id:a}=o;return Promise.resolve(s.provideCodeLenses(e,t)).then(l=>{if(Array.isArray(l))for(let u of l)u.source=a;return l})}));return[].concat(...r)}async resolveCodeLens(e,t){if(e.command)return e;let{source:i}=e,r=this.getProviderById(i);if(!r||typeof r.resolveCodeLens!="function")return e;let o=await Promise.resolve(r.resolveCodeLens(zi(e,["source"]),t));return Object.assign(e,o),e}}});var rJ,DOe,qy,oJ=_(()=>{"use strict";rJ=C(H());Tt();Oe();DOe=q()("definitionManager"),qy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),rJ.Disposable.create(()=>{this.providers.delete(i)})}async provideDeclaration(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return await Promise.resolve(o.provideDeclaration(e,t,i))}}});var Yy,IOe,Wy,sJ=_(()=>{"use strict";Yy=C(H());Tt();Oe();Jt();IOe=q()("definitionManager"),Wy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),Yy.Disposable.create(()=>{this.providers.delete(i)})}async getDefinitions(e,t,i){let r=this.getProviders(e);return r.length?await Promise.all(r.map(s=>{let{provider:a}=s;return Promise.resolve(a.provideDefinition(e,t,i))})):[]}async provideDefinition(e,t,i){let r=await this.getDefinitions(e,t,i);return this.toLocations(r)}async provideDefinitionLinks(e,t,i){let r=await this.getDefinitions(e,t,i),o=[];for(let s of r)if(!!Array.isArray(s))for(let a of s)Yy.LocationLink.is(a)&&o.findIndex(u=>u.targetUri==a.targetUri&&Fe(u.targetRange,a.targetRange))==-1&&o.push(a);return o}}});var aJ,Zy,lJ=_(()=>{"use strict";aJ=C(H());Tt();Oe();Zy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),aJ.Disposable.create(()=>{this.providers.delete(i)})}async provideDocumentColors(e,t){let i=this.getProvider(e);if(!i)return null;let{provider:r}=i;return await Promise.resolve(r.provideDocumentColors(e,t))}async provideColorPresentations(e,t,i){let{range:r,color:o}=e,s=this.getProvider(t);if(!s)return null;let{provider:a}=s;return await Promise.resolve(a.provideColorPresentations(o,{document:t,range:r},i))}}});var uJ,Jy,cJ=_(()=>{"use strict";uJ=C(H());Tt();Oe();Jy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),uJ.Disposable.create(()=>{this.providers.delete(i)})}async provideDocumentHighlights(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return await Promise.resolve(o.provideDocumentHighlights(e,t,i))}}});var hJ,$y,dJ=_(()=>{"use strict";hJ=C(H());Tt();Oe();$y=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),hJ.Disposable.create(()=>{this.providers.delete(i)})}async _provideDocumentLinks(e,t,i){let{provider:r,id:o}=e,s=await Promise.resolve(r.provideDocumentLinks(t,i));return!s||!s.length?[]:(s.forEach(a=>{a.data=a.data||{},a.data.source=o}),s)}async provideDocumentLinks(e,t){let i=this.getProviders(e);if(i.length==0)return[];let r=await Promise.all(i.map(o=>this._provideDocumentLinks(o,e,t)));return[].concat(...r)}async resolveDocumentLink(e,t){let{data:i}=e;if(!i||!i.source)return null;for(let r of this.providers)if(r.id==i.source){let{provider:o}=r;return e=await Promise.resolve(o.resolveDocumentLink(e,t)),e}return null}}});var gJ,Xy,fJ=_(()=>{"use strict";gJ=C(H());Tt();Oe();Xy=class extends pe{register(e,t,i){let r={id:re(),meta:i,selector:e,provider:t};return this.providers.add(r),gJ.Disposable.create(()=>{this.providers.delete(r)})}getMetaData(e){var i;let t=this.getProvider(e);return t?(i=t.provider.meta)!=null?i:{}:{}}async provideDocumentSymbols(e,t){let i=this.getProvider(e);if(!i)return null;let{provider:r}=i;return await Promise.resolve(r.provideDocumentSymbols(e,t))||[]}}});var pJ,Uy,mJ=_(()=>{"use strict";pJ=C(H());Tt();Oe();Uy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),pJ.Disposable.create(()=>{this.providers.delete(i)})}async provideFoldingRanges(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return await Promise.resolve(o.provideFoldingRanges(e,t,i))||[]}}});var bJ,Gy,yJ=_(()=>{"use strict";bJ=C(H());Tt();Oe();Gy=class extends pe{register(e,t,i=0){let r={id:re(),selector:e,priority:i,provider:t};return this.providers.add(r),bJ.Disposable.create(()=>{this.providers.delete(r)})}handles(e){return this.getProvider(e)!=null}async provideDocumentFormattingEdits(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return await Promise.resolve(o.provideDocumentFormattingEdits(e,t,i))}}});var vJ,Qy,wJ=_(()=>{"use strict";vJ=C(H());Tt();Oe();Qy=class extends pe{register(e,t,i=0){let r={id:re(),selector:e,provider:t,priority:i};return this.providers.add(r),vJ.Disposable.create(()=>{this.providers.delete(r)})}async provideDocumentRangeFormattingEdits(e,t,i,r){let o=this.getProvider(e);if(!o)return null;let{provider:s}=o;return await Promise.resolve(s.provideDocumentRangeFormattingEdits(e,t,i,r))}}});var DJ,Ky,xJ=_(()=>{"use strict";DJ=C(H());Tt();Oe();Ky=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),DJ.Disposable.create(()=>{this.providers.delete(i)})}async provideHover(e,t,i){let r=this.getProviders(e);if(r.length===0)return null;let o=[];for(let s=0,a=r.length;s{"use strict";CJ=C(H());Tt();Oe();zy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),CJ.Disposable.create(()=>{this.providers.delete(i)})}async provideReferences(e,t,i){let r=this.getProviders(e);if(!r.length)return null;let o=await Promise.all(r.map(s=>{let{provider:a}=s;return Promise.resolve(a.provideImplementation(e,t,i))}));return this.toLocations(o)}}});var TJ,oNe,Vy,kJ=_(()=>{"use strict";Oe();TJ=C(H());Tt();oNe=q()("linkedEditingManager"),Vy=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),TJ.Disposable.create(()=>{this.providers.delete(i)})}async provideLinkedEditingRanges(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return o.provideLinkedEditingRanges?await Promise.resolve(o.provideLinkedEditingRanges(e,t,i)):null}}});var EJ,dNe,ev,PJ=_(()=>{"use strict";EJ=C(H());V();dNe=q()("onTypeFormatManager"),ev=class{constructor(){this.providers=new Set}register(e,t,i){let r={triggerCharacters:i,selector:e,provider:t};return this.providers.add(r),EJ.Disposable.create(()=>{this.providers.delete(r)})}hasProvider(e){for(let t of this.providers){let{selector:i}=t;if(y.match(i,e)>0)return!0}return!1}getProvider(e,t){for(let i of this.providers){let{triggerCharacters:r,selector:o}=i;if(y.match(o,e)>0&&r.includes(t))return i.provider}return null}async onCharacterType(e,t,i,r){let o=this.getProvider(t,e);if(!o)return;let s=await y.getFormatOptions(t.uri);return await Promise.resolve(o.provideOnTypeFormattingEdits(t,i,e,s,r))}}});var _J,tv,RJ=_(()=>{"use strict";_J=C(H());Tt();Oe();tv=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),_J.Disposable.create(()=>{this.providers.delete(i)})}async provideReferences(e,t,i,r){let o=this.getProviders(e);if(!o.length)return null;let s=await Promise.all(o.map(a=>{let{provider:l}=a;return Promise.resolve(l.provideReferences(e,t,i,r))}));return this.toLocations(s)}}});var LJ,iv,FJ=_(()=>{"use strict";LJ=C(H());Tt();Oe();iv=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),LJ.Disposable.create(()=>{this.providers.delete(i)})}async provideRenameEdits(e,t,i,r){let o=this.getProvider(e);if(!o)return null;let{provider:s}=o;return await Promise.resolve(s.provideRenameEdits(e,t,i,r))}async prepareRename(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;if(o.prepareRename==null)return null;let s=await Promise.resolve(o.prepareRename(e,t,i));return s==null?!1:s}}});var IJ,nv,jJ=_(()=>{"use strict";IJ=C(H());Tt();Oe();nv=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),IJ.Disposable.create(()=>{this.providers.delete(i)})}async provideSelectionRanges(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r,s=await Promise.resolve(o.provideSelectionRanges(e,t,i));if(!s||s.length==0)return[];for(let a=0;a{"use strict";Oe();AJ=C(H());Tt();$Ne=q()("semanticTokensManager"),rv=class extends pe{constructor(){super(...arguments);this.resolvedProvider=new Map}register(e,t,i,r){let o=re(),s={id:o,selector:e,legend:i,provider:t};this.providers.add(s);let a;return typeof t.onDidChangeSemanticTokens=="function"&&(a=t.onDidChangeSemanticTokens(()=>{r()})),AJ.Disposable.create(()=>{a==null||a.dispose();for(let[l,u]of this.resolvedProvider.entries())u==o&&this.resolvedProvider.delete(l);this.providers.delete(s)})}getLegend(e){let t=this.getProvider(e);if(!!t)return this.resolvedProvider.set(e.uri,t.id),t.legend}resolveProvider(e){var i;let t=this.resolvedProvider.get(e.uri);return t?this.getProviderById(t):(i=this.getProvider(e))==null?void 0:i.provider}hasSemanticTokensEdits(e){let t=this.resolveProvider(e);return t?typeof t.provideDocumentSemanticTokensEdits=="function":!1}async provideDocumentSemanticTokens(e,t){let i=this.resolveProvider(e);return!i||typeof i.provideDocumentSemanticTokens!="function"?null:await Promise.resolve(i.provideDocumentSemanticTokens(e,t))}async provideDocumentSemanticTokensEdits(e,t,i){let r=this.resolveProvider(e);return!r||typeof r.provideDocumentSemanticTokensEdits!="function"?null:await Promise.resolve(r.provideDocumentSemanticTokensEdits(e,t,i))}}});var MJ,iBe,ov,NJ=_(()=>{"use strict";Oe();MJ=C(H());Tt();iBe=q()("semanticTokensRangeManager"),ov=class extends pe{register(e,t,i){let r={id:re(),selector:e,legend:i,provider:t};return this.providers.add(r),MJ.Disposable.create(()=>{this.providers.delete(r)})}getLegend(e){let t=this.getProvider(e);if(!!t)return t.legend}async provideDocumentRangeSemanticTokens(e,t,i){let r=this.getProvider(e);if(!r)return null;let{provider:o}=r;return o.provideDocumentRangeSemanticTokens===null?null:await Promise.resolve(o.provideDocumentRangeSemanticTokens(e,t,i))}}});var BJ,sv,HJ=_(()=>{"use strict";BJ=C(H());Tt();Oe();sv=class extends pe{register(e,t,i){let r=i.reduce((s,a)=>s.concat(a.length==1?[a]:a.split(/\s*/g)),[]),o={id:re(),selector:e,provider:t,triggerCharacters:r};return this.providers.add(o),BJ.Disposable.create(()=>{this.providers.delete(o)})}shouldTrigger(e,t){let i=this.getProvider(e);if(!i)return!1;let{triggerCharacters:r}=i;return r&&r.indexOf(t)!=-1}async provideSignatureHelp(e,t,i,r){let o=this.getProvider(e);if(!o)return null;let s=await Promise.resolve(o.provider.provideSignatureHelp(e,t,i,r));return s&&s.signatures&&s.signatures.length?s:null}}});var qJ,av,YJ=_(()=>{"use strict";qJ=C(H());Tt();Oe();av=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),qJ.Disposable.create(()=>{this.providers.delete(i)})}async provideTypeDefinition(e,t,i){let r=this.getProviders(e);if(!r.length)return null;let o=await Promise.all(r.map(s=>{let{provider:a}=s;return Promise.resolve(a.provideTypeDefinition(e,t,i))}));return this.toLocations(o)}}});var WJ,lv,ZJ=_(()=>{"use strict";Oe();WJ=C(H()),lv=class{constructor(){this.providers=new Map}register(e){let t=re();return this.providers.set(t,e),WJ.Disposable.create(()=>{this.providers.delete(t)})}async provideWorkspaceSymbols(e,t){let i=Array.from(this.providers.entries());if(!i.length)return[];let r=[];return await Promise.all(i.map(o=>{let[s,a]=o;return Promise.resolve(a.provideWorkspaceSymbols(e,t)).then(l=>{l&&r.push(...l.map(u=>Object.assign({source:s},u)))})})),r}async resolveWorkspaceSymbol(e,t){let i=this.providers.get(e.source);if(!!i)return typeof i.resolveWorkspaceSymbol!="function"?Promise.resolve(e):await Promise.resolve(i.resolveWorkspaceSymbol(e,t))}hasProvider(){return this.providers.size>0}}});var Mr,Yk,Wk,uv,JJ=_(()=>{"use strict";Mr=C(H());In();(i=>{i.Type=1,i.Parameter=2;function t(r){return r===1||r===2}i.is=t})(Yk||(Yk={}));(t=>{function n(i){return{value:i}}t.create=n;function e(i){let r=i;return _t(r)&&(r.tooltip===void 0||Ee(r.tooltip)||Mr.MarkupContent.is(r.tooltip))&&(r.location===void 0||Mr.Location.is(r.location))&&(r.command===void 0||Mr.Command.is(r.command))}t.is=e})(Wk||(Wk={}));(t=>{function n(i,r,o){let s={position:i,label:r};return o!==void 0&&(s.kind=o),s}t.create=n;function e(i){let r=i;return _t(r)&&Mr.Position.is(r.position)&&(Ee(r.label)||F0(r.label,Wk.is))&&(r.kind===void 0||Yk.is(r.kind))&&r.textEdits===void 0||F0(r.textEdits,Mr.TextEdit.is)&&(r.tooltip===void 0||Ee(r.tooltip)||Mr.MarkupContent.is(r.tooltip))&&(r.paddingLeft===void 0||Kn(r.paddingLeft))&&(r.paddingRight===void 0||Kn(r.paddingRight))}t.is=e})(uv||(uv={}))});function Swe(n,e){return De(n.position,e.position)!==0?!1:cv(n)===cv(e)}function Twe(n,e){return n.label.length===0||Array.isArray(n.label)&&n.label.every(t=>t.value.length===0)?(Zk.warn("INVALID inlay hint, empty label",n),!1):uv.is(n)?!(e&&ut(n.position,e)!==0):(Zk.warn("INVALID inlay hint",n),!1)}function cv(n){return typeof n.label=="string"?n.label:n.label.map(e=>e.value).join(" ")}var $J,Zk,hv,Jk=_(()=>{"use strict";Oe();$J=C(H());JJ();yt();Tt();Zk=q()("inlayHintManger"),hv=class extends pe{register(e,t){let i={id:re(),selector:e,provider:t};return this.providers.add(i),$J.Disposable.create(()=>{this.providers.delete(i)})}async provideInlayHints(e,t,i){let r=this.getProviders(e);if(r.length===0)return null;let o=[],s=0;return await Promise.all(r.map(a=>{let{id:l,provider:u}=a;return Promise.resolve(u.provideInlayHints(e,t,i)).then(c=>{if(!i.isCancellationRequested){for(let h of c)!Twe(h,t)||s>0&&o.findIndex(d=>Swe(d,h))!=-1||o.push(ge({providerId:l},h));s+=1}},c=>{Zk.error("Error on provideInlayHints",c)})})),o}async resolveInlayHint(e,t){let i=this.getProviderById(e.providerId);if(!i||typeof i.resolveInlayHint!="function"||e.resolved===!0)return e;let r=await Promise.resolve(i.resolveInlayHint(e,t));return t.isCancellationRequested?e:Object.assign(e,r,{resolved:!0})}}});var OBe,$k,dv,Xk=_(()=>{"use strict";Oe();OBe=q()("model-status"),$k=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],dv=class{constructor(e){this.nvim=e;this.items=new Map;this.shownIds=new Set;this._text="";this.interval=setInterval(()=>{this.setStatusText()},100)}dispose(){this.items.clear(),this.shownIds.clear(),clearInterval(this.interval)}createStatusBarItem(e=0,t=!1){let i=Uo(),r={text:"",priority:e,isProgress:t,show:()=>{this.shownIds.add(i),this.setStatusText()},hide:()=>{this.shownIds.delete(i),this.setStatusText()},dispose:()=>{this.shownIds.delete(i),this.items.delete(i),this.setStatusText()}};return this.items.set(i,r),r}getText(){if(this.shownIds.size==0)return"";let e=new Date,t=Math.floor(e.getMilliseconds()/100),i="",r=[];for(let[o,s]of this.items)this.shownIds.has(o)&&r.push(s);r.sort((o,s)=>o.priority-s.priority);for(let o of r)o.isProgress?i=`${i} ${$k[t]} ${o.text}`:i=`${i} ${o.text}`;return i}setStatusText(){let e=this.getText(),{nvim:t}=this;e!=this._text&&(this._text=e,t.pauseNotification(),this.nvim.setVar("coc_status",e,!0),this.nvim.call("coc#util#do_autocmd",["CocStatusChange"],!0),t.resumeNotification(!1,!0))}}});var XJ,BBe,uf,UJ=_(()=>{"use strict";XJ=require("events");Xk();BBe=q()("model-installBuffer"),uf=class extends XJ.EventEmitter{constructor(e=!1,t=!1,i=void 0){super();this.isUpdate=e;this.isSync=t;this.channel=i;this.statMap=new Map;this.messagesMap=new Map;this.names=[]}setExtensions(e){this.statMap.clear(),this.names=e;for(let t of e)this.statMap.set(t,0)}addMessage(e,t,i=!1){if(i&&this.channel)return;let r=this.messagesMap.get(e)||[];this.messagesMap.set(e,r.concat(t.trim().split(/\r?\n/))),this.channel&&this.channel.appendLine(`[${e}] ${t}`)}startProgress(e){for(let t of e)this.statMap.set(t,2)}finishProgress(e,t=!0){this.channel&&(t?this.channel.appendLine(`[${e}] install succeed!`):this.channel.appendLine(`[${e}] install failed!`)),this.statMap.set(e,t?3:1)}get remains(){let e=0;for(let t of this.names){let i=this.statMap.get(t);[3,1].includes(i)||(e=e+1)}return e}getLines(){let e=[];for(let t of this.names){let i=this.statMap.get(t),r="*";switch(i){case 2:{let s=new Date,a=Math.floor(s.getMilliseconds()/100);r=$k[a];break}case 1:r="\u2717";break;case 3:r="\u2713";break}let o=this.messagesMap.get(t)||[];e.push(`- ${r} ${t} ${o.length?o[o.length-1]:""}`)}return e}getMessages(e){if(e<=1)return[];let t=this.names[e-2];return t?this.messagesMap.get(t):[]}draw(e,t){let{remains:i}=this,o=[i==0?`${this.isUpdate?"Update":"Install"} finished`:`Installing, ${i} remaining...`,"",...this.getLines()];t.setLines(o,{start:0,end:-1,strictIndexing:!1},!0),i==0&&this.interval&&(clearInterval(this.interval),this.interval=null),process.env.VIM_NODE_RPC&&e.command("redraw",!0)}highlight(e){e.call("matchadd",["CocListFgCyan","^\\-\\s\\zs\\*"],!0),e.call("matchadd",["CocListFgGreen","^\\-\\s\\zs\u2713"],!0),e.call("matchadd",["CocListFgRed","^\\-\\s\\zs\u2717"],!0),e.call("matchadd",["CocListFgYellow","^-.\\{3\\}\\zs\\S\\+"],!0)}async show(e){let{isSync:t}=this;if(this.channel)return;e.pauseNotification(),e.command(t?"enew":"vs +enew",!0),e.call("bufnr",["%"],!0),e.command("setl buftype=nofile bufhidden=wipe noswapfile nobuflisted wrap undolevels=-1",!0),t||e.command("nnoremap q :q",!0),this.highlight(e);let i=await e.resumeNotification();this.bufnr=i[0][1];let r=e.createBuffer(this.bufnr);this.interval=setInterval(()=>{this.draw(e,r)},100)}dispose(){this.interval&&clearInterval(this.interval)}}});var KJ=m((Uk,QJ)=>{var gv=require("buffer"),es=gv.Buffer;function GJ(n,e){for(var t in n)e[t]=n[t]}es.from&&es.alloc&&es.allocUnsafe&&es.allocUnsafeSlow?QJ.exports=gv:(GJ(gv,Uk),Uk.Buffer=Wc);function Wc(n,e,t){return es(n,e,t)}GJ(es,Wc);Wc.from=function(n,e,t){if(typeof n=="number")throw new TypeError("Argument must not be a number");return es(n,e,t)};Wc.alloc=function(n,e,t){if(typeof n!="number")throw new TypeError("Argument must be a number");var i=es(n);return e!==void 0?typeof t=="string"?i.fill(e,t):i.fill(e):i.fill(0),i};Wc.allocUnsafe=function(n){if(typeof n!="number")throw new TypeError("Argument must be a number");return es(n)};Wc.allocUnsafeSlow=function(n){if(typeof n!="number")throw new TypeError("Argument must be a number");return gv.SlowBuffer(n)}});var n$=m((qBe,Gk)=>{"use strict";Gk.exports=Owe;Gk.exports.parse=Hwe;var zJ=require("path").basename,kwe=KJ().Buffer,Ewe=/[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g,Pwe=/%[0-9A-Fa-f]{2}/,_we=/%([0-9A-Fa-f]{2})/g,e$=/[^\x20-\x7e\xa0-\xff]/g,Rwe=/\\([\u0000-\u007f])/g,Lwe=/([\\"])/g,VJ=/;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g,Fwe=/^[\x20-\x7e\x80-\xff]+$/,Iwe=/^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/,jwe=/^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/,Awe=/^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/;function Owe(n,e){var t=e||{},i=t.type||"attachment",r=Mwe(n,t.fallback);return Nwe(new i$(i,r))}function Mwe(n,e){if(n!==void 0){var t={};if(typeof n!="string")throw new TypeError("filename must be a string");if(e===void 0&&(e=!0),typeof e!="string"&&typeof e!="boolean")throw new TypeError("fallback must be a string or boolean");if(typeof e=="string"&&e$.test(e))throw new TypeError("fallback must be ISO-8859-1 string");var i=zJ(n),r=Fwe.test(i),o=typeof e!="string"?e&&t$(i):zJ(e),s=typeof o=="string"&&o!==i;return(s||!r||Pwe.test(i))&&(t["filename*"]=i),(r||s)&&(t.filename=s?o:i),t}}function Nwe(n){var e=n.parameters,t=n.type;if(!t||typeof t!="string"||!Iwe.test(t))throw new TypeError("invalid type");var i=String(t).toLowerCase();if(e&&typeof e=="object")for(var r,o=Object.keys(e).sort(),s=0;s{var cf;r$.exports=function(){if(!cf){try{cf=Ot()("follow-redirects")}catch{}typeof cf!="function"&&(cf=function(){})}cf.apply(null,arguments)}});var eE=m((WBe,Vk)=>{var Rl=require("url"),Qk=Rl.URL,Jwe=require("http"),$we=require("https"),l$=require("stream").Writable,Xwe=require("assert"),u$=o$(),Ll=["abort","aborted","connect","error","socket","timeout"],zk=Object.create(null);Ll.forEach(function(n){zk[n]=function(e,t,i){this._redirectable.emit(n,e,t,i)}});var s$=fv("ERR_FR_REDIRECTION_FAILURE","Redirected request failed"),Uwe=fv("ERR_FR_TOO_MANY_REDIRECTS","Maximum number of redirects exceeded"),Gwe=fv("ERR_FR_MAX_BODY_LENGTH_EXCEEDED","Request body larger than maxBodyLength limit"),Qwe=fv("ERR_STREAM_WRITE_AFTER_END","write after end");function On(n,e){l$.call(this),this._sanitizeOptions(n),this._options=n,this._ended=!1,this._ending=!1,this._redirectCount=0,this._redirects=[],this._requestBodyLength=0,this._requestBodyBuffers=[],e&&this.on("response",e);var t=this;this._onNativeResponse=function(i){t._processResponse(i)},this._performRequest()}On.prototype=Object.create(l$.prototype);On.prototype.abort=function(){h$(this._currentRequest),this.emit("abort")};On.prototype.write=function(n,e,t){if(this._ending)throw new Qwe;if(!(typeof n=="string"||typeof n=="object"&&"length"in n))throw new TypeError("data should be a string, Buffer or Uint8Array");if(typeof e=="function"&&(t=e,e=null),n.length===0){t&&t();return}this._requestBodyLength+n.length<=this._options.maxBodyLength?(this._requestBodyLength+=n.length,this._requestBodyBuffers.push({data:n,encoding:e}),this._currentRequest.write(n,e,t)):(this.emit("error",new Gwe),this.abort())};On.prototype.end=function(n,e,t){if(typeof n=="function"?(t=n,n=e=null):typeof e=="function"&&(t=e,e=null),!n)this._ended=this._ending=!0,this._currentRequest.end(null,null,t);else{var i=this,r=this._currentRequest;this.write(n,e,function(){i._ended=!0,r.end(null,null,t)}),this._ending=!0}};On.prototype.setHeader=function(n,e){this._options.headers[n]=e,this._currentRequest.setHeader(n,e)};On.prototype.removeHeader=function(n){delete this._options.headers[n],this._currentRequest.removeHeader(n)};On.prototype.setTimeout=function(n,e){var t=this;function i(s){s.setTimeout(n),s.removeListener("timeout",s.destroy),s.addListener("timeout",s.destroy)}function r(s){t._timeout&&clearTimeout(t._timeout),t._timeout=setTimeout(function(){t.emit("timeout"),o()},n),i(s)}function o(){t._timeout&&(clearTimeout(t._timeout),t._timeout=null),t.removeListener("abort",o),t.removeListener("error",o),t.removeListener("response",o),e&&t.removeListener("timeout",e),t.socket||t._currentRequest.removeListener("socket",r)}return e&&this.on("timeout",e),this.socket?r(this.socket):this._currentRequest.once("socket",r),this.on("socket",i),this.on("abort",o),this.on("error",o),this.on("response",o),this};["flushHeaders","getHeader","setNoDelay","setSocketKeepAlive"].forEach(function(n){On.prototype[n]=function(e,t){return this._currentRequest[n](e,t)}});["aborted","connection","socket"].forEach(function(n){Object.defineProperty(On.prototype,n,{get:function(){return this._currentRequest[n]}})});On.prototype._sanitizeOptions=function(n){if(n.headers||(n.headers={}),n.host&&(n.hostname||(n.hostname=n.host),delete n.host),!n.pathname&&n.path){var e=n.path.indexOf("?");e<0?n.pathname=n.path:(n.pathname=n.path.substring(0,e),n.search=n.path.substring(e))}};On.prototype._performRequest=function(){var n=this._options.protocol,e=this._options.nativeProtocols[n];if(!e){this.emit("error",new TypeError("Unsupported protocol "+n));return}if(this._options.agents){var t=n.substr(0,n.length-1);this._options.agent=this._options.agents[t]}var i=this._currentRequest=e.request(this._options,this._onNativeResponse);this._currentUrl=Rl.format(this._options),i._redirectable=this;for(var r=0;r=300&&e<400){if(h$(this._currentRequest),n.destroy(),++this._redirectCount>this._options.maxRedirects){this.emit("error",new Uwe);return}((e===301||e===302)&&this._options.method==="POST"||e===303&&!/^(?:GET|HEAD)$/.test(this._options.method))&&(this._options.method="GET",this._requestBodyBuffers=[],Kk(/^content-/i,this._options.headers));var i=Kk(/^host$/i,this._options.headers),r=Rl.parse(this._currentUrl),o=i||r.host,s=/^\w+:/.test(t)?this._currentUrl:Rl.format(Object.assign(r,{host:o})),a;try{a=Rl.resolve(s,t)}catch(c){this.emit("error",new s$(c));return}u$("redirecting to",a),this._isRedirect=!0;var l=Rl.parse(a);if(Object.assign(this._options,l),(l.protocol!==r.protocol||!zwe(l.host,o))&&Kk(/^(?:authorization|cookie)$/i,this._options.headers),typeof this._options.beforeRedirect=="function"){var u={headers:n.headers};try{this._options.beforeRedirect.call(null,this._options,u)}catch(c){this.emit("error",c);return}this._sanitizeOptions(this._options)}try{this._performRequest()}catch(c){this.emit("error",new s$(c))}}else n.responseUrl=this._currentUrl,n.redirects=this._redirects,this.emit("response",n),this._requestBodyBuffers=[]};function c$(n){var e={maxRedirects:21,maxBodyLength:10485760},t={};return Object.keys(n).forEach(function(i){var r=i+":",o=t[r]=n[i],s=e[i]=Object.create(o);function a(u,c,h){if(typeof u=="string"){var d=u;try{u=a$(new Qk(d))}catch{u=Rl.parse(d)}}else Qk&&u instanceof Qk?u=a$(u):(h=c,c=u,u={protocol:r});return typeof c=="function"&&(h=c,c=null),c=Object.assign({maxRedirects:e.maxRedirects,maxBodyLength:e.maxBodyLength},u,c),c.nativeProtocols=t,Xwe.equal(c.protocol,r,"protocol mismatch"),u$("options",c),new On(c,h)}function l(u,c,h){var d=s.request(u,c,h);return d.end(),d}Object.defineProperties(s,{request:{value:a,configurable:!0,enumerable:!0,writable:!0},get:{value:l,configurable:!0,enumerable:!0,writable:!0}})}),e}function Kwe(){}function a$(n){var e={protocol:n.protocol,hostname:n.hostname.startsWith("[")?n.hostname.slice(1,-1):n.hostname,hash:n.hash,search:n.search,pathname:n.pathname,path:n.pathname+n.search,href:n.href};return n.port!==""&&(e.port=Number(n.port)),e}function Kk(n,e){var t;for(var i in e)n.test(i)&&(t=e[i],delete e[i]);return t===null||typeof t>"u"?void 0:String(t).trim()}function fv(n,e){function t(i){Error.captureStackTrace(this,this.constructor),i?(this.message=e+": "+i.message,this.cause=i):this.message=e}return t.prototype=new Error,t.prototype.constructor=t,t.prototype.name="Error ["+n+"]",t.prototype.code=n,t}function h$(n){for(var e=0;e0&&n[t]==="."&&n.endsWith(e)}Vk.exports=c$({http:Jwe,https:$we});Vk.exports.wrap=c$});var Zc=m((ZBe,g$)=>{"use strict";var d$=new Map([["C","cwd"],["f","file"],["z","gzip"],["P","preservePaths"],["U","unlink"],["strip-components","strip"],["stripComponents","strip"],["keep-newer","newer"],["keepNewer","newer"],["keep-newer-files","newer"],["keepNewerFiles","newer"],["k","keep"],["keep-existing","keep"],["keepExisting","keep"],["m","noMtime"],["no-mtime","noMtime"],["p","preserveOwner"],["L","follow"],["h","follow"]]);g$.exports=n=>n?Object.keys(n).map(e=>[d$.has(e)?d$.get(e):e,n[e]]).reduce((e,t)=>(e[t[0]]=t[1],e),Object.create(null)):{}});var Jc=m((JBe,x$)=>{"use strict";var Vwe=require("events"),f$=require("stream"),hf=Ug(),p$=require("string_decoder").StringDecoder,ts=Symbol("EOF"),df=Symbol("maybeEmitEnd"),da=Symbol("emittedEnd"),pv=Symbol("emittingEnd"),mv=Symbol("closed"),m$=Symbol("read"),tE=Symbol("flush"),b$=Symbol("flushChunk"),bn=Symbol("encoding"),is=Symbol("decoder"),bv=Symbol("flowing"),gf=Symbol("paused"),ff=Symbol("resume"),Vi=Symbol("bufferLength"),y$=Symbol("bufferPush"),iE=Symbol("bufferShift"),Fi=Symbol("objectMode"),Ii=Symbol("destroyed"),w$=global._MP_NO_ITERATOR_SYMBOLS_!=="1",eDe=w$&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),tDe=w$&&Symbol.iterator||Symbol("iterator not implemented"),v$=n=>n==="end"||n==="finish"||n==="prefinish",iDe=n=>n instanceof ArrayBuffer||typeof n=="object"&&n.constructor&&n.constructor.name==="ArrayBuffer"&&n.byteLength>=0,nDe=n=>!Buffer.isBuffer(n)&&ArrayBuffer.isView(n);x$.exports=class D$ extends f${constructor(e){super();this[bv]=!1,this[gf]=!1,this.pipes=new hf,this.buffer=new hf,this[Fi]=e&&e.objectMode||!1,this[Fi]?this[bn]=null:this[bn]=e&&e.encoding||null,this[bn]==="buffer"&&(this[bn]=null),this[is]=this[bn]?new p$(this[bn]):null,this[ts]=!1,this[da]=!1,this[pv]=!1,this[mv]=!1,this.writable=!0,this.readable=!0,this[Vi]=0,this[Ii]=!1}get bufferLength(){return this[Vi]}get encoding(){return this[bn]}set encoding(e){if(this[Fi])throw new Error("cannot set encoding in objectMode");if(this[bn]&&e!==this[bn]&&(this[is]&&this[is].lastNeed||this[Vi]))throw new Error("cannot change encoding");this[bn]!==e&&(this[is]=e?new p$(e):null,this.buffer.length&&(this.buffer=this.buffer.map(t=>this[is].write(t)))),this[bn]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Fi]}set objectMode(e){this[Fi]=this[Fi]||!!e}write(e,t,i){if(this[ts])throw new Error("write after end");return this[Ii]?(this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),!0):(typeof t=="function"&&(i=t,t="utf8"),t||(t="utf8"),!this[Fi]&&!Buffer.isBuffer(e)&&(nDe(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):iDe(e)?e=Buffer.from(e):typeof e!="string"&&(this.objectMode=!0)),!this.objectMode&&!e.length?(this[Vi]!==0&&this.emit("readable"),i&&i(),this.flowing):(typeof e=="string"&&!this[Fi]&&!(t===this[bn]&&!this[is].lastNeed)&&(e=Buffer.from(e,t)),Buffer.isBuffer(e)&&this[bn]&&(e=this[is].write(e)),this.flowing?(this[Vi]!==0&&this[tE](!0),this.emit("data",e)):this[y$](e),this[Vi]!==0&&this.emit("readable"),i&&i(),this.flowing))}read(e){if(this[Ii])return null;try{return this[Vi]===0||e===0||e>this[Vi]?null:(this[Fi]&&(e=null),this.buffer.length>1&&!this[Fi]&&(this.encoding?this.buffer=new hf([Array.from(this.buffer).join("")]):this.buffer=new hf([Buffer.concat(Array.from(this.buffer),this[Vi])])),this[m$](e||null,this.buffer.head.value))}finally{this[df]()}}[m$](e,t){return e===t.length||e===null?this[iE]():(this.buffer.head.value=t.slice(e),t=t.slice(0,e),this[Vi]-=e),this.emit("data",t),!this.buffer.length&&!this[ts]&&this.emit("drain"),t}end(e,t,i){return typeof e=="function"&&(i=e,e=null),typeof t=="function"&&(i=t,t="utf8"),e&&this.write(e,t),i&&this.once("end",i),this[ts]=!0,this.writable=!1,(this.flowing||!this[gf])&&this[df](),this}[ff](){this[Ii]||(this[gf]=!1,this[bv]=!0,this.emit("resume"),this.buffer.length?this[tE]():this[ts]?this[df]():this.emit("drain"))}resume(){return this[ff]()}pause(){this[bv]=!1,this[gf]=!0}get destroyed(){return this[Ii]}get flowing(){return this[bv]}get paused(){return this[gf]}[y$](e){return this[Fi]?this[Vi]+=1:this[Vi]+=e.length,this.buffer.push(e)}[iE](){return this.buffer.length&&(this[Fi]?this[Vi]-=1:this[Vi]-=this.buffer.head.value.length),this.buffer.shift()}[tE](e){do;while(this[b$](this[iE]()));!e&&!this.buffer.length&&!this[ts]&&this.emit("drain")}[b$](e){return e?(this.emit("data",e),this.flowing):!1}pipe(e,t){if(this[Ii])return;let i=this[da];t=t||{},e===process.stdout||e===process.stderr?t.end=!1:t.end=t.end!==!1;let r={dest:e,opts:t,ondrain:o=>this[ff]()};return this.pipes.push(r),e.on("drain",r.ondrain),this[ff](),i&&r.opts.end&&r.dest.end(),e}addListener(e,t){return this.on(e,t)}on(e,t){try{return super.on(e,t)}finally{e==="data"&&!this.pipes.length&&!this.flowing?this[ff]():v$(e)&&this[da]&&(super.emit(e),this.removeAllListeners(e))}}get emittedEnd(){return this[da]}[df](){!this[pv]&&!this[da]&&!this[Ii]&&this.buffer.length===0&&this[ts]&&(this[pv]=!0,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[mv]&&this.emit("close"),this[pv]=!1)}emit(e,t){if(e!=="error"&&e!=="close"&&e!==Ii&&this[Ii])return;if(e==="data"){if(!t)return;this.pipes.length&&this.pipes.forEach(r=>r.dest.write(t)===!1&&this.pause())}else if(e==="end"){if(this[da]===!0)return;this[da]=!0,this.readable=!1,this[is]&&(t=this[is].end(),t&&(this.pipes.forEach(r=>r.dest.write(t)),super.emit("data",t))),this.pipes.forEach(r=>{r.dest.removeListener("drain",r.ondrain),r.opts.end&&r.dest.end()})}else if(e==="close"&&(this[mv]=!0,!this[da]&&!this[Ii]))return;let i=new Array(arguments.length);if(i[0]=e,i[1]=t,arguments.length>2)for(let r=2;r{e.push(i),this[Fi]||(e.dataLength+=i.length)}),t.then(()=>e)}concat(){return this[Fi]?Promise.reject(new Error("cannot concat in objectMode")):this.collect().then(e=>this[Fi]?Promise.reject(new Error("cannot concat in objectMode")):this[bn]?e.join(""):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,t)=>{this.on(Ii,()=>t(new Error("stream destroyed"))),this.on("end",()=>e()),this.on("error",i=>t(i))})}[eDe](){return{next:()=>{let t=this.read();if(t!==null)return Promise.resolve({done:!1,value:t});if(this[ts])return Promise.resolve({done:!0});let i=null,r=null,o=u=>{this.removeListener("data",s),this.removeListener("end",a),r(u)},s=u=>{this.removeListener("error",o),this.removeListener("end",a),this.pause(),i({value:u,done:!!this[ts]})},a=()=>{this.removeListener("error",o),this.removeListener("data",s),i({done:!0})},l=()=>o(new Error("stream destroyed"));return new Promise((u,c)=>{r=c,i=u,this.once(Ii,l),this.once("error",o),this.once("end",a),this.once("data",s)})}}}[tDe](){return{next:()=>{let t=this.read();return{value:t,done:t===null}}}}destroy(e){return this[Ii]?(e?this.emit("error",e):this.emit(Ii),this):(this[Ii]=!0,this.buffer=new hf,this[Vi]=0,typeof this.close=="function"&&!this[mv]&&this.close(),e?this.emit("error",e):this.emit(Ii),this)}static isStream(e){return!!e&&(e instanceof D$||e instanceof f$||e instanceof Vwe&&(typeof e.pipe=="function"||typeof e.write=="function"&&typeof e.end=="function"))}}});var S$=m(($Be,C$)=>{var rDe=require("zlib").constants||{ZLIB_VERNUM:4736};C$.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},rDe))});var hE=m(Mn=>{"use strict";var aE=require("assert"),ga=require("buffer").Buffer,E$=require("zlib"),Fl=Mn.constants=S$(),oDe=Jc(),T$=ga.concat,Il=Symbol("_superWrite"),mf=class extends Error{constructor(e){super("zlib: "+e.message);this.code=e.code,this.errno=e.errno,this.code||(this.code="ZLIB_ERROR"),this.message="zlib: "+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return"ZlibError"}},sDe=Symbol("opts"),pf=Symbol("flushFlag"),k$=Symbol("finishFlushFlag"),lE=Symbol("fullFlushFlag"),ft=Symbol("handle"),yv=Symbol("onError"),$c=Symbol("sawError"),nE=Symbol("level"),rE=Symbol("strategy"),oE=Symbol("ended"),XBe=Symbol("_defaultFullFlush"),uE=class extends oDe{constructor(e,t){if(!e||typeof e!="object")throw new TypeError("invalid options for ZlibBase constructor");super(e);this[$c]=!1,this[oE]=!1,this[sDe]=e,this[pf]=e.flush,this[k$]=e.finishFlush;try{this[ft]=new E$[t](e)}catch(i){throw new mf(i)}this[yv]=i=>{this[$c]||(this[$c]=!0,this.close(),this.emit("error",i))},this[ft].on("error",i=>this[yv](new mf(i))),this.once("end",()=>this.close)}close(){this[ft]&&(this[ft].close(),this[ft]=null,this.emit("close"))}reset(){if(!this[$c])return aE(this[ft],"zlib binding closed"),this[ft].reset()}flush(e){this.ended||(typeof e!="number"&&(e=this[lE]),this.write(Object.assign(ga.alloc(0),{[pf]:e})))}end(e,t,i){return e&&this.write(e,t),this.flush(this[k$]),this[oE]=!0,super.end(null,null,i)}get ended(){return this[oE]}write(e,t,i){if(typeof t=="function"&&(i=t,t="utf8"),typeof e=="string"&&(e=ga.from(e,t)),this[$c])return;aE(this[ft],"zlib binding closed");let r=this[ft]._handle,o=r.close;r.close=()=>{};let s=this[ft].close;this[ft].close=()=>{},ga.concat=u=>u;let a;try{let u=typeof e[pf]=="number"?e[pf]:this[pf];a=this[ft]._processChunk(e,u),ga.concat=T$}catch(u){ga.concat=T$,this[yv](new mf(u))}finally{this[ft]&&(this[ft]._handle=r,r.close=o,this[ft].close=s,this[ft].removeAllListeners("error"))}this[ft]&&this[ft].on("error",u=>this[yv](new mf(u)));let l;if(a)if(Array.isArray(a)&&a.length>0){l=this[Il](ga.from(a[0]));for(let u=1;u{this.flush(r),o()};try{this[ft].params(e,t)}finally{this[ft].flush=i}this[ft]&&(this[nE]=e,this[rE]=t)}}}},P$=class extends fa{constructor(e){super(e,"Deflate")}},_$=class extends fa{constructor(e){super(e,"Inflate")}},sE=Symbol("_portable"),R$=class extends fa{constructor(e){super(e,"Gzip");this[sE]=e&&!!e.portable}[Il](e){return this[sE]?(this[sE]=!1,e[9]=255,super[Il](e)):super[Il](e)}},L$=class extends fa{constructor(e){super(e,"Gunzip")}},F$=class extends fa{constructor(e){super(e,"DeflateRaw")}},I$=class extends fa{constructor(e){super(e,"InflateRaw")}},j$=class extends fa{constructor(e){super(e,"Unzip")}},cE=class extends uE{constructor(e,t){e=e||{},e.flush=e.flush||Fl.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||Fl.BROTLI_OPERATION_FINISH;super(e,t);this[lE]=Fl.BROTLI_OPERATION_FLUSH}},A$=class extends cE{constructor(e){super(e,"BrotliCompress")}},O$=class extends cE{constructor(e){super(e,"BrotliDecompress")}};Mn.Deflate=P$;Mn.Inflate=_$;Mn.Gzip=R$;Mn.Gunzip=L$;Mn.DeflateRaw=F$;Mn.InflateRaw=I$;Mn.Unzip=j$;typeof E$.BrotliCompress=="function"?(Mn.BrotliCompress=A$,Mn.BrotliDecompress=O$):Mn.BrotliCompress=Mn.BrotliDecompress=class{constructor(){throw new Error("Brotli is not supported in this version of Node.js")}}});var Xc=m((GBe,M$)=>{var aDe=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;M$.exports=aDe!=="win32"?n=>n:n=>n&&n.replace(/\\/g,"/")});var vv=m((KBe,N$)=>{"use strict";var lDe=Jc(),dE=Xc(),gE=Symbol("slurp");N$.exports=class extends lDe{constructor(e,t,i){super();switch(this.pause(),this.extended=t,this.globalExtended=i,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case"File":case"OldFile":case"Link":case"SymbolicLink":case"CharacterDevice":case"BlockDevice":case"Directory":case"FIFO":case"ContiguousFile":case"GNUDumpDir":break;case"NextFileHasLongLinkpath":case"NextFileHasLongPath":case"OldGnuLongPath":case"GlobalExtendedHeader":case"ExtendedHeader":case"OldExtendedHeader":this.meta=!0;break;default:this.ignore=!0}this.path=dE(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=dE(e.linkpath),this.uname=e.uname,this.gname=e.gname,t&&this[gE](t),i&&this[gE](i,!0)}write(e){let t=e.length;if(t>this.blockRemain)throw new Error("writing more to entry than is appropriate");let i=this.remain,r=this.blockRemain;return this.remain=Math.max(0,i-t),this.blockRemain=Math.max(0,r-t),this.ignore?!0:i>=t?super.write(e):super.write(e.slice(0,i))}[gE](e,t){for(let i in e)e[i]!==null&&e[i]!==void 0&&!(t&&i==="path")&&(this[i]=i==="path"||i==="linkpath"?dE(e[i]):e[i])}}});var fE=m(wv=>{"use strict";wv.name=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]);wv.code=new Map(Array.from(wv.name).map(n=>[n[1],n[0]]))});var Y$=m((VBe,q$)=>{"use strict";var uDe=(n,e)=>{if(Number.isSafeInteger(n))n<0?hDe(n,e):cDe(n,e);else throw Error("cannot encode number outside of javascript safe integer range");return e},cDe=(n,e)=>{e[0]=128;for(var t=e.length;t>1;t--)e[t-1]=n&255,n=Math.floor(n/256)},hDe=(n,e)=>{e[0]=255;var t=!1;n=n*-1;for(var i=e.length;i>1;i--){var r=n&255;n=Math.floor(n/256),t?e[i-1]=B$(r):r===0?e[i-1]=0:(t=!0,e[i-1]=H$(r))}},dDe=n=>{let e=n[0],t=e===128?fDe(n.slice(1,n.length)):e===255?gDe(n):null;if(t===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(t))throw Error("parsed number outside of javascript safe integer range");return t},gDe=n=>{for(var e=n.length,t=0,i=!1,r=e-1;r>-1;r--){var o=n[r],s;i?s=B$(o):o===0?s=o:(i=!0,s=H$(o)),s!==0&&(t-=s*Math.pow(256,e-r-1))}return t},fDe=n=>{for(var e=n.length,t=0,i=e-1;i>-1;i--){var r=n[i];r!==0&&(t+=r*Math.pow(256,e-i-1))}return t},B$=n=>(255^n)&255,H$=n=>(255^n)+1&255;q$.exports={encode:uDe,parse:dDe}});var Gc=m((eHe,J$)=>{"use strict";var pE=fE(),Uc=require("path").posix,W$=Y$(),mE=Symbol("slurp"),Nn=Symbol("type"),Z$=class{constructor(e,t,i,r){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[Nn]="0",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,t||0,i,r):e&&this.set(e)}decode(e,t,i,r){if(t||(t=0),!e||!(e.length>=t+512))throw new Error("need 512 bytes for header");if(this.path=jl(e,t,100),this.mode=pa(e,t+100,8),this.uid=pa(e,t+108,8),this.gid=pa(e,t+116,8),this.size=pa(e,t+124,12),this.mtime=bE(e,t+136,12),this.cksum=pa(e,t+148,12),this[mE](i),this[mE](r,!0),this[Nn]=jl(e,t+156,1),this[Nn]===""&&(this[Nn]="0"),this[Nn]==="0"&&this.path.substr(-1)==="/"&&(this[Nn]="5"),this[Nn]==="5"&&(this.size=0),this.linkpath=jl(e,t+157,100),e.slice(t+257,t+265).toString()==="ustar\x0000")if(this.uname=jl(e,t+265,32),this.gname=jl(e,t+297,32),this.devmaj=pa(e,t+329,8),this.devmin=pa(e,t+337,8),e[t+475]!==0){let s=jl(e,t+345,155);this.path=s+"/"+this.path}else{let s=jl(e,t+345,130);s&&(this.path=s+"/"+this.path),this.atime=bE(e,t+476,12),this.ctime=bE(e,t+488,12)}let o=8*32;for(let s=t;s=t+512))throw new Error("need 512 bytes for header");let i=this.ctime||this.atime?130:155,r=pDe(this.path||"",i),o=r[0],s=r[1];this.needPax=r[2],this.needPax=Al(e,t,100,o)||this.needPax,this.needPax=ma(e,t+100,8,this.mode)||this.needPax,this.needPax=ma(e,t+108,8,this.uid)||this.needPax,this.needPax=ma(e,t+116,8,this.gid)||this.needPax,this.needPax=ma(e,t+124,12,this.size)||this.needPax,this.needPax=yE(e,t+136,12,this.mtime)||this.needPax,e[t+156]=this[Nn].charCodeAt(0),this.needPax=Al(e,t+157,100,this.linkpath)||this.needPax,e.write("ustar\x0000",t+257,8),this.needPax=Al(e,t+265,32,this.uname)||this.needPax,this.needPax=Al(e,t+297,32,this.gname)||this.needPax,this.needPax=ma(e,t+329,8,this.devmaj)||this.needPax,this.needPax=ma(e,t+337,8,this.devmin)||this.needPax,this.needPax=Al(e,t+345,i,s)||this.needPax,e[t+475]!==0?this.needPax=Al(e,t+345,155,s)||this.needPax:(this.needPax=Al(e,t+345,130,s)||this.needPax,this.needPax=yE(e,t+476,12,this.atime)||this.needPax,this.needPax=yE(e,t+488,12,this.ctime)||this.needPax);let a=8*32;for(let l=t;l{let i=n,r="",o,s=Uc.parse(n).root||".";if(Buffer.byteLength(i)<100)o=[i,r,!1];else{r=Uc.dirname(i),i=Uc.basename(i);do Buffer.byteLength(i)<=100&&Buffer.byteLength(r)<=e?o=[i,r,!1]:Buffer.byteLength(i)>100&&Buffer.byteLength(r)<=e?o=[i.substr(0,100-1),r,!0]:(i=Uc.join(Uc.basename(r),i),r=Uc.dirname(r));while(r!==s&&!o);o||(o=[n.substr(0,100-1),"",!0])}return o},jl=(n,e,t)=>n.slice(e,e+t).toString("utf8").replace(/\0.*/,""),bE=(n,e,t)=>mDe(pa(n,e,t)),mDe=n=>n===null?null:new Date(n*1e3),pa=(n,e,t)=>n[e]&128?W$.parse(n.slice(e,e+t)):yDe(n,e,t),bDe=n=>isNaN(n)?null:n,yDe=(n,e,t)=>bDe(parseInt(n.slice(e,e+t).toString("utf8").replace(/\0.*$/,"").trim(),8)),vDe={12:8589934591,8:2097151},ma=(n,e,t,i)=>i===null?!1:i>vDe[t]||i<0?(W$.encode(i,n.slice(e,e+t)),!0):(wDe(n,e,t,i),!1),wDe=(n,e,t,i)=>n.write(DDe(i,t),e,t,"ascii"),DDe=(n,e)=>xDe(Math.floor(n).toString(8),e),xDe=(n,e)=>(n.length===e-1?n:new Array(e-n.length-1).join("0")+n+" ")+"\0",yE=(n,e,t,i)=>i===null?!1:ma(n,e,t,i.getTime()/1e3),CDe=new Array(156).join("\0"),Al=(n,e,t,i)=>i===null?!1:(n.write(i+CDe,e,t,"utf8"),i.length!==Buffer.byteLength(i)||i.length>t);J$.exports=Z$});var xv=m((tHe,$$)=>{"use strict";var SDe=Gc(),TDe=require("path"),Dv=class{constructor(e,t){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=t||!1}encode(){let e=this.encodeBody();if(e==="")return null;let t=Buffer.byteLength(e),i=512*Math.ceil(1+t/512),r=Buffer.allocUnsafe(i);for(let o=0;o<512;o++)r[o]=0;new SDe({path:("PaxHeader/"+TDe.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:t,mtime:this.mtime||null,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(r),r.write(e,512,t,"utf8");for(let o=t+512;o=Math.pow(10,o)&&(o+=1),o+r+i}};Dv.parse=(n,e,t)=>new Dv(kDe(EDe(n),e),t);var kDe=(n,e)=>e?Object.keys(n).reduce((t,i)=>(t[i]=n[i],t),e):n,EDe=n=>n.replace(/\n$/,"").split(` -`).reduce(PDe,Object.create(null)),PDe=(n,e)=>{let t=parseInt(e,10);if(t!==Buffer.byteLength(e)+1)return n;e=e.substr((t+" ").length);let i=e.split("="),r=i.shift().replace(/^SCHILY\.(dev|ino|nlink)/,"$1");if(!r)return n;let o=i.join("=");return n[r]=/^([A-Z]+\.)?([mac]|birth|creation)time$/.test(r)?new Date(o*1e3):/^[0-9]+$/.test(o)?+o:o,n};$$.exports=Dv});var Qc=m((iHe,X$)=>{X$.exports=n=>{let e=n.length-1,t=-1;for(;e>-1&&n.charAt(e)==="/";)t=e,e--;return t===-1?n:n.slice(0,t)}});var Cv=m((nHe,U$)=>{"use strict";U$.exports=n=>class extends n{warn(e,t,i={}){this.file&&(i.file=this.file),this.cwd&&(i.cwd=this.cwd),i.code=t instanceof Error&&t.code||e,i.tarCode=e,!this.strict&&i.recoverable!==!1?(t instanceof Error&&(i=Object.assign(t,i),t=t.message),this.emit("warn",i.tarCode,t,i)):t instanceof Error?this.emit("error",Object.assign(t,i)):this.emit("error",Object.assign(new Error(`${e}: ${t}`),i))}}});var wE=m((rHe,G$)=>{"use strict";var Sv=["|","<",">","?",":"],vE=Sv.map(n=>String.fromCharCode(61440+n.charCodeAt(0))),_De=new Map(Sv.map((n,e)=>[n,vE[e]])),RDe=new Map(vE.map((n,e)=>[n,Sv[e]]));G$.exports={encode:n=>Sv.reduce((e,t)=>e.split(t).join(_De.get(t)),n),decode:n=>vE.reduce((e,t)=>e.split(t).join(RDe.get(t)),n)}});var DE=m((oHe,K$)=>{var{isAbsolute:LDe,parse:Q$}=require("path").win32;K$.exports=n=>{let e="",t=Q$(n);for(;LDe(n)||t.root;){let i=n.charAt(0)==="/"&&n.slice(0,4)!=="//?/"?"/":t.root;n=n.substr(i.length),e+=i,t=Q$(n)}return[e,n]}});var V$=m((sHe,z$)=>{"use strict";z$.exports=(n,e,t)=>(n&=4095,t&&(n=(n|384)&-19),e&&(n&256&&(n|=64),n&32&&(n|=8),n&4&&(n|=1)),n)});var RE=m((uHe,fX)=>{"use strict";var sX=Jc(),aX=xv(),lX=Gc(),ao=require("fs"),eX=require("path"),so=Xc(),FDe=Qc(),uX=(n,e)=>e?(n=so(n).replace(/^\.(\/|$)/,""),FDe(e)+"/"+n):so(n),IDe=16*1024*1024,tX=Symbol("process"),iX=Symbol("file"),nX=Symbol("directory"),CE=Symbol("symlink"),rX=Symbol("hardlink"),bf=Symbol("header"),Tv=Symbol("read"),SE=Symbol("lstat"),kv=Symbol("onlstat"),TE=Symbol("onread"),kE=Symbol("onreadlink"),EE=Symbol("openfile"),PE=Symbol("onopenfile"),ba=Symbol("close"),Ev=Symbol("mode"),_E=Symbol("awaitDrain"),xE=Symbol("ondrain"),lo=Symbol("prefix"),oX=Symbol("hadError"),cX=Cv(),jDe=wE(),hX=DE(),dX=V$(),Pv=cX(class extends sX{constructor(e,t){t=t||{};super(t);if(typeof e!="string")throw new TypeError("path is required");this.path=so(e),this.portable=!!t.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||"",this.maxReadSize=t.maxReadSize||IDe,this.linkCache=t.linkCache||new Map,this.statCache=t.statCache||new Map,this.preservePaths=!!t.preservePaths,this.cwd=so(t.cwd||process.cwd()),this.strict=!!t.strict,this.noPax=!!t.noPax,this.noMtime=!!t.noMtime,this.mtime=t.mtime||null,this.prefix=t.prefix?so(t.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof t.onwarn=="function"&&this.on("warn",t.onwarn);let i=!1;if(!this.preservePaths){let[r,o]=hX(this.path);r&&(this.path=o,i=r)}this.win32=!!t.win32||process.platform==="win32",this.win32&&(this.path=jDe.decode(this.path.replace(/\\/g,"/")),e=e.replace(/\\/g,"/")),this.absolute=so(t.absolute||eX.resolve(this.cwd,e)),this.path===""&&(this.path="./"),i&&this.warn("TAR_ENTRY_INFO",`stripping ${i} from absolute path`,{entry:this,path:i+this.path}),this.statCache.has(this.absolute)?this[kv](this.statCache.get(this.absolute)):this[SE]()}emit(e,...t){return e==="error"&&(this[oX]=!0),super.emit(e,...t)}[SE](){ao.lstat(this.absolute,(e,t)=>{if(e)return this.emit("error",e);this[kv](t)})}[kv](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=ODe(e),this.emit("stat",e),this[tX]()}[tX](){switch(this.type){case"File":return this[iX]();case"Directory":return this[nX]();case"SymbolicLink":return this[CE]();default:return this.end()}}[Ev](e){return dX(e,this.type==="Directory",this.portable)}[lo](e){return uX(e,this.prefix)}[bf](){this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.header=new lX({path:this[lo](this.path),linkpath:this.type==="Link"?this[lo](this.linkpath):this.linkpath,mode:this[Ev](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:"",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new aX({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[lo](this.path),linkpath:this.type==="Link"?this[lo](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[nX](){this.path.substr(-1)!=="/"&&(this.path+="/"),this.stat.size=0,this[bf](),this.end()}[CE](){ao.readlink(this.absolute,(e,t)=>{if(e)return this.emit("error",e);this[kE](t)})}[kE](e){this.linkpath=so(e),this[bf](),this.end()}[rX](e){this.type="Link",this.linkpath=so(eX.relative(this.cwd,e)),this.stat.size=0,this[bf](),this.end()}[iX](){if(this.stat.nlink>1){let e=this.stat.dev+":"+this.stat.ino;if(this.linkCache.has(e)){let t=this.linkCache.get(e);if(t.indexOf(this.cwd)===0)return this[rX](t)}this.linkCache.set(e,this.absolute)}if(this[bf](),this.stat.size===0)return this.end();this[EE]()}[EE](){ao.open(this.absolute,"r",(e,t)=>{if(e)return this.emit("error",e);this[PE](t)})}[PE](e){if(this.fd=e,this[oX])return this[ba]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let t=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(t),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[Tv]()}[Tv](){let{fd:e,buf:t,offset:i,length:r,pos:o}=this;ao.read(e,t,i,r,o,(s,a)=>{if(s)return this[ba](()=>this.emit("error",s));this[TE](a)})}[ba](e){ao.close(this.fd,e)}[TE](e){if(e<=0&&this.remain>0){let r=new Error("encountered unexpected EOF");return r.path=this.absolute,r.syscall="read",r.code="EOF",this[ba](()=>this.emit("error",r))}if(e>this.remain){let r=new Error("did not encounter expected EOF");return r.path=this.absolute,r.syscall="read",r.code="EOF",this[ba](()=>this.emit("error",r))}if(e===this.remain)for(let r=e;rthis[xE]())}[_E](e){this.once("drain",e)}write(e){if(this.blockRemaine?this.emit("error",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[Tv]()}}),gX=class extends Pv{[SE](){this[kv](ao.lstatSync(this.absolute))}[CE](){this[kE](ao.readlinkSync(this.absolute))}[EE](){this[PE](ao.openSync(this.absolute,"r"))}[Tv](){let e=!0;try{let{fd:t,buf:i,offset:r,length:o,pos:s}=this,a=ao.readSync(t,i,r,o,s);this[TE](a),e=!1}finally{if(e)try{this[ba](()=>{})}catch{}}}[_E](e){e()}[ba](e){ao.closeSync(this.fd),e()}},ADe=cX(class extends sX{constructor(e,t){t=t||{};super(t);this.preservePaths=!!t.preservePaths,this.portable=!!t.portable,this.strict=!!t.strict,this.noPax=!!t.noPax,this.noMtime=!!t.noMtime,this.readEntry=e,this.type=e.type,this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.prefix=t.prefix||null,this.path=so(e.path),this.mode=this[Ev](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:t.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=so(e.linkpath),typeof t.onwarn=="function"&&this.on("warn",t.onwarn);let i=!1;if(!this.preservePaths){let[r,o]=hX(this.path);r&&(this.path=o,i=r)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new lX({path:this[lo](this.path),linkpath:this.type==="Link"?this[lo](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),i&&this.warn("TAR_ENTRY_INFO",`stripping ${i} from absolute path`,{entry:this,path:i+this.path}),this.header.encode()&&!this.noPax&&super.write(new aX({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[lo](this.path),linkpath:this.type==="Link"?this[lo](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[lo](e){return uX(e,this.prefix)}[Ev](e){return dX(e,this.type==="Directory",this.portable)}write(e){let t=e.length;if(t>this.blockRemain)throw new Error("writing more to entry than is appropriate");return this.blockRemain-=t,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});Pv.Sync=gX;Pv.Tar=ADe;var ODe=n=>n.isFile()?"File":n.isDirectory()?"Directory":n.isSymbolicLink()?"SymbolicLink":"Unsupported";fX.exports=Pv});var Ov=m((hHe,xX)=>{"use strict";var AE=class{constructor(e,t){this.path=e||"./",this.absolute=t,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},MDe=Jc(),NDe=hE(),BDe=vv(),BE=RE(),HDe=BE.Sync,qDe=BE.Tar,YDe=Ug(),pX=Buffer.alloc(1024),Lv=Symbol("onStat"),_v=Symbol("ended"),uo=Symbol("queue"),Kc=Symbol("current"),Ol=Symbol("process"),Rv=Symbol("processing"),mX=Symbol("processJob"),co=Symbol("jobs"),LE=Symbol("jobDone"),Fv=Symbol("addFSEntry"),bX=Symbol("addTarEntry"),OE=Symbol("stat"),ME=Symbol("readdir"),Iv=Symbol("onreaddir"),jv=Symbol("pipe"),yX=Symbol("entry"),FE=Symbol("entryOpt"),NE=Symbol("writeEntryClass"),wX=Symbol("write"),IE=Symbol("ondrain"),Av=require("fs"),vX=require("path"),WDe=Cv(),jE=Xc(),HE=WDe(class extends MDe{constructor(e){super(e);e=e||Object.create(null),this.opt=e,this.file=e.file||"",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=jE(e.prefix||""),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[NE]=BE,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!="object"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new NDe.Gzip(e.gzip),this.zip.on("data",t=>super.write(t)),this.zip.on("end",t=>super.end()),this.zip.on("drain",t=>this[IE]()),this.on("resume",t=>this.zip.resume())):this.on("drain",this[IE]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter=="function"?e.filter:t=>!0,this[uo]=new YDe,this[co]=0,this.jobs=+e.jobs||4,this[Rv]=!1,this[_v]=!1}[wX](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[_v]=!0,this[Ol](),this}write(e){if(this[_v])throw new Error("write after end");return e instanceof BDe?this[bX](e):this[Fv](e),this.flowing}[bX](e){let t=jE(vX.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let i=new AE(e.path,t,!1);i.entry=new qDe(e,this[FE](i)),i.entry.on("end",r=>this[LE](i)),this[co]+=1,this[uo].push(i)}this[Ol]()}[Fv](e){let t=jE(vX.resolve(this.cwd,e));this[uo].push(new AE(e,t)),this[Ol]()}[OE](e){e.pending=!0,this[co]+=1;let t=this.follow?"stat":"lstat";Av[t](e.absolute,(i,r)=>{e.pending=!1,this[co]-=1,i?this.emit("error",i):this[Lv](e,r)})}[Lv](e,t){this.statCache.set(e.absolute,t),e.stat=t,this.filter(e.path,t)||(e.ignore=!0),this[Ol]()}[ME](e){e.pending=!0,this[co]+=1,Av.readdir(e.absolute,(t,i)=>{if(e.pending=!1,this[co]-=1,t)return this.emit("error",t);this[Iv](e,i)})}[Iv](e,t){this.readdirCache.set(e.absolute,t),e.readdir=t,this[Ol]()}[Ol](){if(!this[Rv]){this[Rv]=!0;for(let e=this[uo].head;e!==null&&this[co]this.warn(t,i,r),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[yX](e){this[co]+=1;try{return new this[NE](e.path,this[FE](e)).on("end",()=>this[LE](e)).on("error",t=>this.emit("error",t))}catch(t){this.emit("error",t)}}[IE](){this[Kc]&&this[Kc].entry&&this[Kc].entry.resume()}[jv](e){e.piped=!0,e.readdir&&e.readdir.forEach(r=>{let o=e.path,s=o==="./"?"":o.replace(/\/*$/,"/");this[Fv](s+r)});let t=e.entry,i=this.zip;i?t.on("data",r=>{i.write(r)||t.pause()}):t.on("data",r=>{super.write(r)||t.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),DX=class extends HE{constructor(e){super(e);this[NE]=HDe}pause(){}resume(){}[OE](e){let t=this.follow?"statSync":"lstatSync";this[Lv](e,Av[t](e.absolute))}[ME](e,t){this[Iv](e,Av.readdirSync(e.absolute))}[jv](e){let t=e.entry,i=this.zip;e.readdir&&e.readdir.forEach(r=>{let o=e.path,s=o==="./"?"":o.replace(/\/*$/,"/");this[Fv](s+r)}),i?t.on("data",r=>{i.write(r)}):t.on("data",r=>{super[wX](r)})}};HE.Sync=DX;xX.exports=HE});var oh=m(vf=>{"use strict";var ZDe=Jc(),JDe=require("events").EventEmitter,yn=require("fs"),WE=yn.writev;if(!WE){let n=process.binding("fs"),e=n.FSReqWrap||n.FSReqCallback;WE=(t,i,r,o)=>{let s=(l,u)=>o(l,u,i),a=new e;a.oncomplete=s,n.writeBuffers(t,i,r,a)}}var nh=Symbol("_autoClose"),Nr=Symbol("_close"),yf=Symbol("_ended"),it=Symbol("_fd"),CX=Symbol("_finished"),va=Symbol("_flags"),qE=Symbol("_flush"),ZE=Symbol("_handleChunk"),JE=Symbol("_makeBuf"),qv=Symbol("_mode"),Mv=Symbol("_needDrain"),th=Symbol("_onerror"),rh=Symbol("_onopen"),YE=Symbol("_onread"),Vc=Symbol("_onwrite"),wa=Symbol("_open"),ns=Symbol("_path"),Ml=Symbol("_pos"),ho=Symbol("_queue"),eh=Symbol("_read"),SX=Symbol("_readSize"),ya=Symbol("_reading"),Nv=Symbol("_remain"),TX=Symbol("_size"),Bv=Symbol("_write"),zc=Symbol("_writing"),Hv=Symbol("_defaultFlag"),ih=Symbol("_errored"),$E=class extends ZDe{constructor(e,t){t=t||{};super(t);if(this.readable=!0,this.writable=!1,typeof e!="string")throw new TypeError("path must be a string");this[ih]=!1,this[it]=typeof t.fd=="number"?t.fd:null,this[ns]=e,this[SX]=t.readSize||16*1024*1024,this[ya]=!1,this[TX]=typeof t.size=="number"?t.size:1/0,this[Nv]=this[TX],this[nh]=typeof t.autoClose=="boolean"?t.autoClose:!0,typeof this[it]=="number"?this[eh]():this[wa]()}get fd(){return this[it]}get path(){return this[ns]}write(){throw new TypeError("this is a readable stream")}end(){throw new TypeError("this is a readable stream")}[wa](){yn.open(this[ns],"r",(e,t)=>this[rh](e,t))}[rh](e,t){e?this[th](e):(this[it]=t,this.emit("open",t),this[eh]())}[JE](){return Buffer.allocUnsafe(Math.min(this[SX],this[Nv]))}[eh](){if(!this[ya]){this[ya]=!0;let e=this[JE]();if(e.length===0)return process.nextTick(()=>this[YE](null,0,e));yn.read(this[it],e,0,e.length,null,(t,i,r)=>this[YE](t,i,r))}}[YE](e,t,i){this[ya]=!1,e?this[th](e):this[ZE](t,i)&&this[eh]()}[Nr](){if(this[nh]&&typeof this[it]=="number"){let e=this[it];this[it]=null,yn.close(e,t=>t?this.emit("error",t):this.emit("close"))}}[th](e){this[ya]=!0,this[Nr](),this.emit("error",e)}[ZE](e,t){let i=!1;return this[Nv]-=e,e>0&&(i=super.write(ethis[rh](e,t))}[rh](e,t){this[Hv]&&this[va]==="r+"&&e&&e.code==="ENOENT"?(this[va]="w",this[wa]()):e?this[th](e):(this[it]=t,this.emit("open",t),this[qE]())}end(e,t){return e&&this.write(e,t),this[yf]=!0,!this[zc]&&!this[ho].length&&typeof this[it]=="number"&&this[Vc](null,0),this}write(e,t){return typeof e=="string"&&(e=Buffer.from(e,t)),this[yf]?(this.emit("error",new Error("write() after end()")),!1):this[it]===null||this[zc]||this[ho].length?(this[ho].push(e),this[Mv]=!0,!1):(this[zc]=!0,this[Bv](e),!0)}[Bv](e){yn.write(this[it],e,0,e.length,this[Ml],(t,i)=>this[Vc](t,i))}[Vc](e,t){e?this[th](e):(this[Ml]!==null&&(this[Ml]+=t),this[ho].length?this[qE]():(this[zc]=!1,this[yf]&&!this[CX]?(this[CX]=!0,this[Nr](),this.emit("finish")):this[Mv]&&(this[Mv]=!1,this.emit("drain"))))}[qE](){if(this[ho].length===0)this[yf]&&this[Vc](null,0);else if(this[ho].length===1)this[Bv](this[ho].pop());else{let e=this[ho];this[ho]=[],WE(this[it],e,this[Ml],(t,i)=>this[Vc](t,i))}}[Nr](){if(this[nh]&&typeof this[it]=="number"){let e=this[it];this[it]=null,yn.close(e,t=>t?this.emit("error",t):this.emit("close"))}}},EX=class extends XE{[wa](){let e;if(this[Hv]&&this[va]==="r+")try{e=yn.openSync(this[ns],this[va],this[qv])}catch(t){if(t.code==="ENOENT")return this[va]="w",this[wa]();throw t}else e=yn.openSync(this[ns],this[va],this[qv]);this[rh](null,e)}[Nr](){if(this[nh]&&typeof this[it]=="number"){let e=this[it];this[it]=null,yn.closeSync(e),this.emit("close")}}[Bv](e){let t=!0;try{this[Vc](null,yn.writeSync(this[it],e,0,e.length,this[Ml])),t=!1}finally{if(t)try{this[Nr]()}catch{}}}};vf.ReadStream=$E;vf.ReadStreamSync=kX;vf.WriteStream=XE;vf.WriteStreamSync=EX});var Uv=m((fHe,jX)=>{"use strict";var $De=Cv(),XDe=Gc(),UDe=require("events"),GDe=Ug(),QDe=1024*1024,KDe=vv(),PX=xv(),zDe=hE(),UE=Buffer.from([31,139]),sr=Symbol("state"),Nl=Symbol("writeEntry"),rs=Symbol("readEntry"),GE=Symbol("nextEntry"),_X=Symbol("processEntry"),ar=Symbol("extendedHeader"),wf=Symbol("globalExtendedHeader"),Da=Symbol("meta"),RX=Symbol("emitMeta"),vt=Symbol("buffer"),os=Symbol("queue"),Bl=Symbol("ended"),LX=Symbol("emittedEnd"),Hl=Symbol("emit"),vn=Symbol("unzip"),Yv=Symbol("consumeChunk"),Wv=Symbol("consumeChunkSub"),QE=Symbol("consumeBody"),FX=Symbol("consumeMeta"),IX=Symbol("consumeHeader"),Zv=Symbol("consuming"),KE=Symbol("bufferConcat"),zE=Symbol("maybeEnd"),Df=Symbol("writing"),xa=Symbol("aborted"),Jv=Symbol("onDone"),ql=Symbol("sawValidEntry"),$v=Symbol("sawNullBlock"),Xv=Symbol("sawEOF"),VDe=n=>!0;jX.exports=$De(class extends UDe{constructor(e){e=e||{};super(e);this.file=e.file||"",this[ql]=null,this.on(Jv,t=>{(this[sr]==="begin"||this[ql]===!1)&&this.warn("TAR_BAD_ARCHIVE","Unrecognized archive format")}),e.ondone?this.on(Jv,e.ondone):this.on(Jv,t=>{this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||QDe,this.filter=typeof e.filter=="function"?e.filter:VDe,this.writable=!0,this.readable=!1,this[os]=new GDe,this[vt]=null,this[rs]=null,this[Nl]=null,this[sr]="begin",this[Da]="",this[ar]=null,this[wf]=null,this[Bl]=!1,this[vn]=null,this[xa]=!1,this[$v]=!1,this[Xv]=!1,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),typeof e.onentry=="function"&&this.on("entry",e.onentry)}[IX](e,t){this[ql]===null&&(this[ql]=!1);let i;try{i=new XDe(e,t,this[ar],this[wf])}catch(r){return this.warn("TAR_ENTRY_INVALID",r)}if(i.nullBlock)this[$v]?(this[Xv]=!0,this[sr]==="begin"&&(this[sr]="header"),this[Hl]("eof")):(this[$v]=!0,this[Hl]("nullBlock"));else if(this[$v]=!1,!i.cksumValid)this.warn("TAR_ENTRY_INVALID","checksum failure",{header:i});else if(!i.path)this.warn("TAR_ENTRY_INVALID","path is required",{header:i});else{let r=i.type;if(/^(Symbolic)?Link$/.test(r)&&!i.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath required",{header:i});else if(!/^(Symbolic)?Link$/.test(r)&&i.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath forbidden",{header:i});else{let o=this[Nl]=new KDe(i,this[ar],this[wf]);if(!this[ql])if(o.remain){let s=()=>{o.invalid||(this[ql]=!0)};o.on("end",s)}else this[ql]=!0;o.meta?o.size>this.maxMetaEntrySize?(o.ignore=!0,this[Hl]("ignoredEntry",o),this[sr]="ignore",o.resume()):o.size>0&&(this[Da]="",o.on("data",s=>this[Da]+=s),this[sr]="meta"):(this[ar]=null,o.ignore=o.ignore||!this.filter(o.path,o),o.ignore?(this[Hl]("ignoredEntry",o),this[sr]=o.remain?"ignore":"header",o.resume()):(o.remain?this[sr]="body":(this[sr]="header",o.end()),this[rs]?this[os].push(o):(this[os].push(o),this[GE]())))}}}[_X](e){let t=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[rs]=e,this.emit("entry",e),e.emittedEnd||(e.on("end",i=>this[GE]()),t=!1)):(this[rs]=null,t=!1),t}[GE](){do;while(this[_X](this[os].shift()));if(!this[os].length){let e=this[rs];!e||e.flowing||e.size===e.remain?this[Df]||this.emit("drain"):e.once("drain",i=>this.emit("drain"))}}[QE](e,t){let i=this[Nl],r=i.blockRemain,o=r>=e.length&&t===0?e:e.slice(t,t+r);return i.write(o),i.blockRemain||(this[sr]="header",this[Nl]=null,i.end()),o.length}[FX](e,t){let i=this[Nl],r=this[QE](e,t);return this[Nl]||this[RX](i),r}[Hl](e,t,i){!this[os].length&&!this[rs]?this.emit(e,t,i):this[os].push([e,t,i])}[RX](e){switch(this[Hl]("meta",this[Da]),e.type){case"ExtendedHeader":case"OldExtendedHeader":this[ar]=PX.parse(this[Da],this[ar],!1);break;case"GlobalExtendedHeader":this[wf]=PX.parse(this[Da],this[wf],!0);break;case"NextFileHasLongPath":case"OldGnuLongPath":this[ar]=this[ar]||Object.create(null),this[ar].path=this[Da].replace(/\0.*/,"");break;case"NextFileHasLongLinkpath":this[ar]=this[ar]||Object.create(null),this[ar].linkpath=this[Da].replace(/\0.*/,"");break;default:throw new Error("unknown meta: "+e.type)}}abort(e){this[xa]=!0,this.emit("abort",e),this.warn("TAR_ABORT",e,{recoverable:!1})}write(e){if(this[xa])return;if(this[vn]===null&&e){if(this[vt]&&(e=Buffer.concat([this[vt],e]),this[vt]=null),e.lengththis[Yv](o)),this[vn].on("error",o=>this.abort(o)),this[vn].on("end",o=>{this[Bl]=!0,this[Yv]()}),this[Df]=!0;let r=this[vn][i?"end":"write"](e);return this[Df]=!1,r}}this[Df]=!0,this[vn]?this[vn].write(e):this[Yv](e),this[Df]=!1;let t=this[os].length?!1:this[rs]?this[rs].flowing:!0;return!t&&!this[os].length&&this[rs].once("drain",i=>this.emit("drain")),t}[KE](e){e&&!this[xa]&&(this[vt]=this[vt]?Buffer.concat([this[vt],e]):e)}[zE](){if(this[Bl]&&!this[LX]&&!this[xa]&&!this[Zv]){this[LX]=!0;let e=this[Nl];if(e&&e.blockRemain){let t=this[vt]?this[vt].length:0;this.warn("TAR_BAD_ARCHIVE",`Truncated input (needed ${e.blockRemain} more bytes, only ${t} available)`,{entry:e}),this[vt]&&e.write(this[vt]),e.end()}this[Hl](Jv)}}[Yv](e){if(this[Zv])this[KE](e);else if(!e&&!this[vt])this[zE]();else{if(this[Zv]=!0,this[vt]){this[KE](e);let t=this[vt];this[vt]=null,this[Wv](t)}else this[Wv](e);for(;this[vt]&&this[vt].length>=512&&!this[xa]&&!this[Xv];){let t=this[vt];this[vt]=null,this[Wv](t)}this[Zv]=!1}(!this[vt]||this[Bl])&&this[zE]()}[Wv](e){let t=0,i=e.length;for(;t+512<=i&&!this[xa]&&!this[Xv];)switch(this[sr]){case"begin":case"header":this[IX](e,t),t+=512;break;case"ignore":case"body":t+=this[QE](e,t);break;case"meta":t+=this[FX](e,t);break;default:throw new Error("invalid state: "+this[sr])}t{"use strict";var exe=Zc(),OX=Uv(),sh=require("fs"),txe=oh(),AX=require("path"),VE=Qc();NX.exports=(n,e,t)=>{typeof n=="function"?(t=n,e=null,n={}):Array.isArray(n)&&(e=n,n={}),typeof e=="function"&&(t=e,e=null),e?e=Array.from(e):e=[];let i=exe(n);if(i.sync&&typeof t=="function")throw new TypeError("callback not supported for sync tar functions");if(!i.file&&typeof t=="function")throw new TypeError("callback only supported with file option");return e.length&&nxe(i,e),i.noResume||ixe(i),i.file&&i.sync?rxe(i):i.file?oxe(i,t):MX(i)};var ixe=n=>{let e=n.onentry;n.onentry=e?t=>{e(t),t.resume()}:t=>t.resume()},nxe=(n,e)=>{let t=new Map(e.map(o=>[VE(o),!0])),i=n.filter,r=(o,s)=>{let a=s||AX.parse(o).root||".",l=o===a?!1:t.has(o)?t.get(o):r(AX.dirname(o),a);return t.set(o,l),l};n.filter=i?(o,s)=>i(o,s)&&r(VE(o)):o=>r(VE(o))},rxe=n=>{let e=MX(n),t=n.file,i=!0,r;try{let o=sh.statSync(t),s=n.maxReadSize||16*1024*1024;if(o.size{let t=new OX(n),i=n.maxReadSize||16*1024*1024,r=n.file,o=new Promise((s,a)=>{t.on("error",a),t.on("end",s),sh.stat(r,(l,u)=>{if(l)a(l);else{let c=new txe.ReadStream(r,{readSize:i,size:u.size});c.on("error",a),c.pipe(t)}})});return e?o.then(e,e):o},MX=n=>new OX(n)});var ZX=m((mHe,WX)=>{"use strict";var sxe=Zc(),Qv=Ov(),BX=oh(),HX=Gv(),qX=require("path");WX.exports=(n,e,t)=>{if(typeof e=="function"&&(t=e),Array.isArray(n)&&(e=n,n={}),!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");e=Array.from(e);let i=sxe(n);if(i.sync&&typeof t=="function")throw new TypeError("callback not supported for sync tar functions");if(!i.file&&typeof t=="function")throw new TypeError("callback only supported with file option");return i.file&&i.sync?axe(i,e):i.file?lxe(i,e,t):i.sync?uxe(i,e):cxe(i,e)};var axe=(n,e)=>{let t=new Qv.Sync(n),i=new BX.WriteStreamSync(n.file,{mode:n.mode||438});t.pipe(i),YX(t,e)},lxe=(n,e,t)=>{let i=new Qv(n),r=new BX.WriteStream(n.file,{mode:n.mode||438});i.pipe(r);let o=new Promise((s,a)=>{r.on("error",a),r.on("close",s),i.on("error",a)});return eP(i,e),t?o.then(t,t):o},YX=(n,e)=>{e.forEach(t=>{t.charAt(0)==="@"?HX({file:qX.resolve(n.cwd,t.substr(1)),sync:!0,noResume:!0,onentry:i=>n.add(i)}):n.add(t)}),n.end()},eP=(n,e)=>{for(;e.length;){let t=e.shift();if(t.charAt(0)==="@")return HX({file:qX.resolve(n.cwd,t.substr(1)),noResume:!0,onentry:i=>n.add(i)}).then(i=>eP(n,e));n.add(t)}n.end()},uxe=(n,e)=>{let t=new Qv.Sync(n);return YX(t,e),t},cxe=(n,e)=>{let t=new Qv(n);return eP(t,e),t}});var tP=m((bHe,KX)=>{"use strict";var hxe=Zc(),JX=Ov(),Bn=require("fs"),$X=oh(),XX=Gv(),UX=require("path"),GX=Gc();KX.exports=(n,e,t)=>{let i=hxe(n);if(!i.file)throw new TypeError("file is required");if(i.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),i.sync?dxe(i,e):fxe(i,e,t)};var dxe=(n,e)=>{let t=new JX.Sync(n),i=!0,r,o;try{try{r=Bn.openSync(n.file,"r+")}catch(l){if(l.code==="ENOENT")r=Bn.openSync(n.file,"w+");else throw l}let s=Bn.fstatSync(r),a=Buffer.alloc(512);e:for(o=0;os.size)break;o+=u,n.mtimeCache&&n.mtimeCache.set(l.path,l.mtime)}i=!1,gxe(n,t,o,r,e)}finally{if(i)try{Bn.closeSync(r)}catch{}}},gxe=(n,e,t,i,r)=>{let o=new $X.WriteStreamSync(n.file,{fd:i,start:t});e.pipe(o),pxe(e,r)},fxe=(n,e,t)=>{e=Array.from(e);let i=new JX(n),r=(s,a,l)=>{let u=(f,p)=>{f?Bn.close(s,b=>l(f)):l(null,p)},c=0;if(a===0)return u(null,0);let h=0,d=Buffer.alloc(512),g=(f,p)=>{if(f)return u(f);if(h+=p,h<512&&p)return Bn.read(s,d,h,d.length-h,c+h,g);if(c===0&&d[0]===31&&d[1]===139)return u(new Error("cannot append to compressed archives"));if(h<512)return u(null,c);let b=new GX(d);if(!b.cksumValid)return u(null,c);let v=512*Math.ceil(b.size/512);if(c+v+512>a||(c+=v+512,c>=a))return u(null,c);n.mtimeCache&&n.mtimeCache.set(b.path,b.mtime),h=0,Bn.read(s,d,0,512,c,g)};Bn.read(s,d,0,512,c,g)},o=new Promise((s,a)=>{i.on("error",a);let l="r+",u=(c,h)=>{if(c&&c.code==="ENOENT"&&l==="r+")return l="w+",Bn.open(n.file,l,u);if(c)return a(c);Bn.fstat(h,(d,g)=>{if(d)return Bn.close(h,()=>a(d));r(h,g.size,(f,p)=>{if(f)return a(f);let b=new $X.WriteStream(n.file,{fd:h,start:p});i.pipe(b),b.on("error",a),b.on("close",s),QX(i,e)})})};Bn.open(n.file,l,u)});return t?o.then(t,t):o},pxe=(n,e)=>{e.forEach(t=>{t.charAt(0)==="@"?XX({file:UX.resolve(n.cwd,t.substr(1)),sync:!0,noResume:!0,onentry:i=>n.add(i)}):n.add(t)}),n.end()},QX=(n,e)=>{for(;e.length;){let t=e.shift();if(t.charAt(0)==="@")return XX({file:UX.resolve(n.cwd,t.substr(1)),noResume:!0,onentry:i=>n.add(i)}).then(i=>QX(n,e));n.add(t)}n.end()}});var VX=m((yHe,zX)=>{"use strict";var mxe=Zc(),bxe=tP();zX.exports=(n,e,t)=>{let i=mxe(n);if(!i.file)throw new TypeError("file is required");if(i.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),yxe(i),bxe(i,e,t)};var yxe=n=>{let e=n.filter;n.mtimeCache||(n.mtimeCache=new Map),n.filter=e?(t,i)=>e(t,i)&&!(n.mtimeCache.get(t)>i.mtime):(t,i)=>!(n.mtimeCache.get(t)>i.mtime)}});var iU=m((vHe,tU)=>{var{promisify:eU}=require("util"),Ca=require("fs"),vxe=n=>{if(!n)n={mode:511,fs:Ca};else if(typeof n=="object")n=ge({mode:511,fs:Ca},n);else if(typeof n=="number")n={mode:n,fs:Ca};else if(typeof n=="string")n={mode:parseInt(n,8),fs:Ca};else throw new TypeError("invalid options argument");return n.mkdir=n.mkdir||n.fs.mkdir||Ca.mkdir,n.mkdirAsync=eU(n.mkdir),n.stat=n.stat||n.fs.stat||Ca.stat,n.statAsync=eU(n.stat),n.statSync=n.statSync||n.fs.statSync||Ca.statSync,n.mkdirSync=n.mkdirSync||n.fs.mkdirSync||Ca.mkdirSync,n};tU.exports=vxe});var rU=m((wHe,nU)=>{var wxe=process.env.__TESTING_MKDIRP_PLATFORM__||process.platform,{resolve:Dxe,parse:xxe}=require("path"),Cxe=n=>{if(/\0/.test(n))throw Object.assign(new TypeError("path must be a string without null bytes"),{path:n,code:"ERR_INVALID_ARG_VALUE"});if(n=Dxe(n),wxe==="win32"){let e=/[*|"<>?:]/,{root:t}=xxe(n);if(e.test(n.substr(t.length)))throw Object.assign(new Error("Illegal characters in path."),{path:n,code:"EINVAL"})}return n};nU.exports=Cxe});var uU=m((DHe,lU)=>{var{dirname:oU}=require("path"),sU=(n,e,t=void 0)=>t===e?Promise.resolve():n.statAsync(e).then(i=>i.isDirectory()?t:void 0,i=>i.code==="ENOENT"?sU(n,oU(e),e):void 0),aU=(n,e,t=void 0)=>{if(t!==e)try{return n.statSync(e).isDirectory()?t:void 0}catch(i){return i.code==="ENOENT"?aU(n,oU(e),e):void 0}};lU.exports={findMade:sU,findMadeSync:aU}});var rP=m((xHe,hU)=>{var{dirname:cU}=require("path"),iP=(n,e,t)=>{e.recursive=!1;let i=cU(n);return i===n?e.mkdirAsync(n,e).catch(r=>{if(r.code!=="EISDIR")throw r}):e.mkdirAsync(n,e).then(()=>t||n,r=>{if(r.code==="ENOENT")return iP(i,e).then(o=>iP(n,e,o));if(r.code!=="EEXIST"&&r.code!=="EROFS")throw r;return e.statAsync(n).then(o=>{if(o.isDirectory())return t;throw r},()=>{throw r})})},nP=(n,e,t)=>{let i=cU(n);if(e.recursive=!1,i===n)try{return e.mkdirSync(n,e)}catch(r){if(r.code!=="EISDIR")throw r;return}try{return e.mkdirSync(n,e),t||n}catch(r){if(r.code==="ENOENT")return nP(n,e,nP(i,e,t));if(r.code!=="EEXIST"&&r.code!=="EROFS")throw r;try{if(!e.statSync(n).isDirectory())throw r}catch{throw r}}};hU.exports={mkdirpManual:iP,mkdirpManualSync:nP}});var fU=m((CHe,gU)=>{var{dirname:dU}=require("path"),{findMade:Sxe,findMadeSync:Txe}=uU(),{mkdirpManual:kxe,mkdirpManualSync:Exe}=rP(),Pxe=(n,e)=>(e.recursive=!0,dU(n)===n?e.mkdirAsync(n,e):Sxe(e,n).then(i=>e.mkdirAsync(n,e).then(()=>i).catch(r=>{if(r.code==="ENOENT")return kxe(n,e);throw r}))),_xe=(n,e)=>{if(e.recursive=!0,dU(n)===n)return e.mkdirSync(n,e);let i=Txe(e,n);try{return e.mkdirSync(n,e),i}catch(r){if(r.code==="ENOENT")return Exe(n,e);throw r}};gU.exports={mkdirpNative:Pxe,mkdirpNativeSync:_xe}});var yU=m((SHe,bU)=>{var pU=require("fs"),Rxe=process.env.__TESTING_MKDIRP_NODE_VERSION__||process.version,oP=Rxe.replace(/^v/,"").split("."),mU=+oP[0]>10||+oP[0]==10&&+oP[1]>=12,Lxe=mU?n=>n.mkdir===pU.mkdir:()=>!1,Fxe=mU?n=>n.mkdirSync===pU.mkdirSync:()=>!1;bU.exports={useNative:Lxe,useNativeSync:Fxe}});var SU=m((THe,CU)=>{var ah=iU(),lh=rU(),{mkdirpNative:vU,mkdirpNativeSync:wU}=fU(),{mkdirpManual:DU,mkdirpManualSync:xU}=rP(),{useNative:Ixe,useNativeSync:jxe}=yU(),uh=(n,e)=>(n=lh(n),e=ah(e),Ixe(e)?vU(n,e):DU(n,e)),Axe=(n,e)=>(n=lh(n),e=ah(e),jxe(e)?wU(n,e):xU(n,e));uh.sync=Axe;uh.native=(n,e)=>vU(lh(n),ah(e));uh.manual=(n,e)=>DU(lh(n),ah(e));uh.nativeSync=(n,e)=>wU(lh(n),ah(e));uh.manualSync=(n,e)=>xU(lh(n),ah(e));CU.exports=uh});var LU=m((kHe,RU)=>{"use strict";var lr=require("fs"),Yl=require("path"),Oxe=lr.lchown?"lchown":"chown",Mxe=lr.lchownSync?"lchownSync":"chownSync",kU=lr.lchown&&!process.version.match(/v1[1-9]+\./)&&!process.version.match(/v10\.[6-9]/),TU=(n,e,t)=>{try{return lr[Mxe](n,e,t)}catch(i){if(i.code!=="ENOENT")throw i}},Nxe=(n,e,t)=>{try{return lr.chownSync(n,e,t)}catch(i){if(i.code!=="ENOENT")throw i}},Bxe=kU?(n,e,t,i)=>r=>{!r||r.code!=="EISDIR"?i(r):lr.chown(n,e,t,i)}:(n,e,t,i)=>i,sP=kU?(n,e,t)=>{try{return TU(n,e,t)}catch(i){if(i.code!=="EISDIR")throw i;Nxe(n,e,t)}}:(n,e,t)=>TU(n,e,t),Hxe=process.version,EU=(n,e,t)=>lr.readdir(n,e,t),qxe=(n,e)=>lr.readdirSync(n,e);/^v4\./.test(Hxe)&&(EU=(n,e,t)=>lr.readdir(n,t));var Kv=(n,e,t,i)=>{lr[Oxe](n,e,t,Bxe(n,e,t,r=>{i(r&&r.code!=="ENOENT"?r:null)}))},PU=(n,e,t,i,r)=>{if(typeof e=="string")return lr.lstat(Yl.resolve(n,e),(o,s)=>{if(o)return r(o.code!=="ENOENT"?o:null);s.name=e,PU(n,s,t,i,r)});if(e.isDirectory())aP(Yl.resolve(n,e.name),t,i,o=>{if(o)return r(o);let s=Yl.resolve(n,e.name);Kv(s,t,i,r)});else{let o=Yl.resolve(n,e.name);Kv(o,t,i,r)}},aP=(n,e,t,i)=>{EU(n,{withFileTypes:!0},(r,o)=>{if(r){if(r.code==="ENOENT")return i();if(r.code!=="ENOTDIR"&&r.code!=="ENOTSUP")return i(r)}if(r||!o.length)return Kv(n,e,t,i);let s=o.length,a=null,l=u=>{if(!a){if(u)return i(a=u);if(--s===0)return Kv(n,e,t,i)}};o.forEach(u=>PU(n,u,e,t,l))})},Yxe=(n,e,t,i)=>{if(typeof e=="string")try{let r=lr.lstatSync(Yl.resolve(n,e));r.name=e,e=r}catch(r){if(r.code==="ENOENT")return;throw r}e.isDirectory()&&_U(Yl.resolve(n,e.name),t,i),sP(Yl.resolve(n,e.name),t,i)},_U=(n,e,t)=>{let i;try{i=qxe(n,{withFileTypes:!0})}catch(r){if(r.code==="ENOENT")return;if(r.code==="ENOTDIR"||r.code==="ENOTSUP")return sP(n,e,t);throw r}return i&&i.length&&i.forEach(r=>Yxe(n,r,e,t)),sP(n,e,t)};RU.exports=aP;aP.sync=_U});var AU=m((EHe,cP)=>{"use strict";var FU=SU(),ur=require("fs"),zv=require("path"),IU=LU(),Br=Xc(),lP=class extends Error{constructor(e,t){super("Cannot extract through symbolic link");this.path=t,this.symlink=e}get name(){return"SylinkError"}},uP=class extends Error{constructor(e,t){super(t+": Cannot cd into '"+e+"'");this.path=e,this.code=t}get name(){return"CwdError"}},Vv=(n,e)=>n.get(Br(e)),xf=(n,e,t)=>n.set(Br(e),t),Wxe=(n,e)=>{ur.stat(n,(t,i)=>{(t||!i.isDirectory())&&(t=new uP(n,t&&t.code||"ENOTDIR")),e(t)})};cP.exports=(n,e,t)=>{n=Br(n);let i=e.umask,r=e.mode|448,o=(r&i)!==0,s=e.uid,a=e.gid,l=typeof s=="number"&&typeof a=="number"&&(s!==e.processUid||a!==e.processGid),u=e.preserve,c=e.unlink,h=e.cache,d=Br(e.cwd),g=(b,v)=>{b?t(b):(xf(h,n,!0),v&&l?IU(v,s,a,w=>g(w)):o?ur.chmod(n,r,t):t())};if(h&&Vv(h,n)===!0)return g();if(n===d)return Wxe(n,g);if(u)return FU(n,{mode:r}).then(b=>g(null,b),g);let p=Br(zv.relative(d,n)).split("/");ew(d,p,r,h,c,d,null,g)};var ew=(n,e,t,i,r,o,s,a)=>{if(!e.length)return a(null,s);let l=e.shift(),u=Br(zv.resolve(n+"/"+l));if(Vv(i,u))return ew(u,e,t,i,r,o,s,a);ur.mkdir(u,t,jU(u,e,t,i,r,o,s,a))},jU=(n,e,t,i,r,o,s,a)=>l=>{l?ur.lstat(n,(u,c)=>{if(u)u.path=u.path&&Br(u.path),a(u);else if(c.isDirectory())ew(n,e,t,i,r,o,s,a);else if(r)ur.unlink(n,h=>{if(h)return a(h);ur.mkdir(n,t,jU(n,e,t,i,r,o,s,a))});else{if(c.isSymbolicLink())return a(new lP(n,n+"/"+e.join("/")));a(l)}}):(s=s||n,ew(n,e,t,i,r,o,s,a))},Zxe=n=>{let e=!1,t="ENOTDIR";try{e=ur.statSync(n).isDirectory()}catch(i){t=i.code}finally{if(!e)throw new uP(n,t)}};cP.exports.sync=(n,e)=>{n=Br(n);let t=e.umask,i=e.mode|448,r=(i&t)!==0,o=e.uid,s=e.gid,a=typeof o=="number"&&typeof s=="number"&&(o!==e.processUid||s!==e.processGid),l=e.preserve,u=e.unlink,c=e.cache,h=Br(e.cwd),d=b=>{xf(c,n,!0),b&&a&&IU.sync(b,o,s),r&&ur.chmodSync(n,i)};if(c&&Vv(c,n)===!0)return d();if(n===h)return Zxe(h),d();if(l)return d(FU.sync(n,i));let f=Br(zv.relative(h,n)).split("/"),p=null;for(let b=f.shift(),v=h;b&&(v+="/"+b);b=f.shift())if(v=Br(zv.resolve(v)),!Vv(c,v))try{ur.mkdirSync(v,i),p=p||v,xf(c,v,!0)}catch{let D=ur.lstatSync(v);if(D.isDirectory()){xf(c,v,!0);continue}else if(u){ur.unlinkSync(v),ur.mkdirSync(v,i),p=p||v,xf(c,v,!0);continue}else if(D.isSymbolicLink())return new lP(v,v+"/"+f.join("/"))}return d(p)}});var dP=m((PHe,OU)=>{var hP=Object.create(null),{hasOwnProperty:Jxe}=Object.prototype;OU.exports=n=>(Jxe.call(hP,n)||(hP[n]=n.normalize("NFKD")),hP[n])});var HU=m((_He,BU)=>{var MU=require("assert"),$xe=dP(),Xxe=Qc(),{join:NU}=require("path"),Uxe=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Gxe=Uxe==="win32";BU.exports=()=>{let n=new Map,e=new Map,t=u=>u.split("/").slice(0,-1).reduce((h,d)=>(h.length&&(d=NU(h[h.length-1],d)),h.push(d||"/"),h),[]),i=new Set,r=u=>{let c=e.get(u);if(!c)throw new Error("function does not have any path reservations");return{paths:c.paths.map(h=>n.get(h)),dirs:[...c.dirs].map(h=>n.get(h))}},o=u=>{let{paths:c,dirs:h}=r(u);return c.every(d=>d[0]===u)&&h.every(d=>d[0]instanceof Set&&d[0].has(u))},s=u=>i.has(u)||!o(u)?!1:(i.add(u),u(()=>a(u)),!0),a=u=>{if(!i.has(u))return!1;let{paths:c,dirs:h}=e.get(u),d=new Set;return c.forEach(g=>{let f=n.get(g);MU.equal(f[0],u),f.length===1?n.delete(g):(f.shift(),typeof f[0]=="function"?d.add(f[0]):f[0].forEach(p=>d.add(p)))}),h.forEach(g=>{let f=n.get(g);MU(f[0]instanceof Set),f[0].size===1&&f.length===1?n.delete(g):f[0].size===1?(f.shift(),d.add(f[0])):f[0].delete(u)}),i.delete(u),d.forEach(g=>s(g)),!0};return{check:o,reserve:(u,c)=>{u=Gxe?["win32 parallelization disabled"]:u.map(d=>$xe(Xxe(NU(d))).toLowerCase());let h=new Set(u.map(d=>t(d)).reduce((d,g)=>d.concat(g)));return e.set(c,{dirs:h,paths:u}),u.forEach(d=>{let g=n.get(d);g?g.push(c):n.set(d,[c])}),h.forEach(d=>{let g=n.get(d);g?g[g.length-1]instanceof Set?g[g.length-1].add(c):g.push(new Set([c])):n.set(d,[new Set([c])])}),s(c)}}}});var WU=m((RHe,YU)=>{var Qxe=process.env.__FAKE_PLATFORM__||process.platform,Kxe=Qxe==="win32",zxe=global.__FAKE_TESTING_FS__||require("fs"),{O_CREAT:Vxe,O_TRUNC:eCe,O_WRONLY:tCe,UV_FS_O_FILEMAP:qU=0}=zxe.constants,iCe=Kxe&&!!qU,nCe=512*1024,rCe=qU|eCe|Vxe|tCe;YU.exports=iCe?n=>n"w"});var wP=m((LHe,r8)=>{"use strict";var oCe=require("assert"),sCe=Uv(),He=require("fs"),aCe=oh(),ss=require("path"),e8=AU(),ZU=wE(),lCe=HU(),uCe=DE(),Hn=Xc(),cCe=Qc(),hCe=dP(),JU=Symbol("onEntry"),pP=Symbol("checkFs"),$U=Symbol("checkFs2"),nw=Symbol("pruneCache"),mP=Symbol("isReusable"),cr=Symbol("makeFs"),bP=Symbol("file"),yP=Symbol("directory"),rw=Symbol("link"),XU=Symbol("symlink"),UU=Symbol("hardlink"),GU=Symbol("unsupported"),QU=Symbol("checkPath"),Sa=Symbol("mkdir"),ji=Symbol("onError"),tw=Symbol("pending"),KU=Symbol("pend"),ch=Symbol("unpend"),gP=Symbol("ended"),fP=Symbol("maybeClose"),vP=Symbol("skip"),Cf=Symbol("doChown"),Sf=Symbol("uid"),Tf=Symbol("gid"),kf=Symbol("checkedCwd"),t8=require("crypto"),i8=WU(),dCe=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Ef=dCe==="win32",gCe=(n,e)=>{if(!Ef)return He.unlink(n,e);let t=n+".DELETE."+t8.randomBytes(16).toString("hex");He.rename(n,t,i=>{if(i)return e(i);He.unlink(t,e)})},fCe=n=>{if(!Ef)return He.unlinkSync(n);let e=n+".DELETE."+t8.randomBytes(16).toString("hex");He.renameSync(n,e),He.unlinkSync(e)},zU=(n,e,t)=>n===n>>>0?n:e===e>>>0?e:t,VU=n=>hCe(cCe(Hn(n))).toLowerCase(),pCe=(n,e)=>{e=VU(e);for(let t of n.keys()){let i=VU(t);(i===e||i.indexOf(e+"/")===0)&&n.delete(t)}},mCe=n=>{for(let e of n.keys())n.delete(e)},ow=class extends sCe{constructor(e){e||(e={}),e.ondone=t=>{this[gP]=!0,this[fP]()};super(e);if(this[kf]=!1,this.reservations=lCe(),this.transform=typeof e.transform=="function"?e.transform:null,this.writable=!0,this.readable=!1,this[tw]=0,this[gP]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid=="number"||typeof e.gid=="number"){if(typeof e.uid!="number"||typeof e.gid!="number")throw new TypeError("cannot set owner without number uid and gid");if(e.preserveOwner)throw new TypeError("cannot preserve owner in archive and also set owner explicitly");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!="number"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||Ef,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=Hn(ss.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask=="number"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on("entry",t=>this[JU](t))}warn(e,t,i={}){return(e==="TAR_BAD_ARCHIVE"||e==="TAR_ABORT")&&(i.recoverable=!1),super.warn(e,t,i)}[fP](){this[gP]&&this[tw]===0&&(this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close"))}[QU](e){if(this.strip){let t=Hn(e.path).split("/");if(t.length=this.strip)e.linkpath=i.slice(this.strip).join("/");else return!1}}if(!this.preservePaths){let t=Hn(e.path),i=t.split("/");if(i.includes("..")||Ef&&/^[a-z]:\.\.$/i.test(i[0]))return this.warn("TAR_ENTRY_ERROR","path contains '..'",{entry:e,path:t}),!1;let[r,o]=uCe(t);r&&(e.path=o,this.warn("TAR_ENTRY_INFO",`stripping ${r} from absolute path`,{entry:e,path:t}))}if(ss.isAbsolute(e.path)?e.absolute=Hn(ss.resolve(e.path)):e.absolute=Hn(ss.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+"/")!==0&&e.absolute!==this.cwd)return this.warn("TAR_ENTRY_ERROR","path escaped extraction target",{entry:e,path:Hn(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!=="Directory"&&e.type!=="GNUDumpDir")return!1;if(this.win32){let{root:t}=ss.win32.parse(e.absolute);e.absolute=t+ZU.encode(e.absolute.substr(t.length));let{root:i}=ss.win32.parse(e.path);e.path=i+ZU.encode(e.path.substr(i.length))}return!0}[JU](e){if(!this[QU](e))return e.resume();switch(oCe.equal(typeof e.absolute,"string"),e.type){case"Directory":case"GNUDumpDir":e.mode&&(e.mode=e.mode|448);case"File":case"OldFile":case"ContiguousFile":case"Link":case"SymbolicLink":return this[pP](e);case"CharacterDevice":case"BlockDevice":case"FIFO":default:return this[GU](e)}}[ji](e,t){e.name==="CwdError"?this.emit("error",e):(this.warn("TAR_ENTRY_ERROR",e,{entry:t}),this[ch](),t.resume())}[Sa](e,t,i){e8(Hn(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:t,noChmod:this.noChmod},i)}[Cf](e){return this.forceChown||this.preserveOwner&&(typeof e.uid=="number"&&e.uid!==this.processUid||typeof e.gid=="number"&&e.gid!==this.processGid)||typeof this.uid=="number"&&this.uid!==this.processUid||typeof this.gid=="number"&&this.gid!==this.processGid}[Sf](e){return zU(this.uid,e.uid,this.processUid)}[Tf](e){return zU(this.gid,e.gid,this.processGid)}[bP](e,t){let i=e.mode&4095||this.fmode,r=new aCe.WriteStream(e.absolute,{flags:i8(e.size),mode:i,autoClose:!1});r.on("error",l=>{r.fd&&He.close(r.fd,()=>{}),r.write=()=>!0,this[ji](l,e),t()});let o=1,s=l=>{if(l){r.fd&&He.close(r.fd,()=>{}),this[ji](l,e),t();return}--o===0&&He.close(r.fd,u=>{u?this[ji](u,e):this[ch](),t()})};r.on("finish",l=>{let u=e.absolute,c=r.fd;if(e.mtime&&!this.noMtime){o++;let h=e.atime||new Date,d=e.mtime;He.futimes(c,h,d,g=>g?He.utimes(u,h,d,f=>s(f&&g)):s())}if(this[Cf](e)){o++;let h=this[Sf](e),d=this[Tf](e);He.fchown(c,h,d,g=>g?He.chown(u,h,d,f=>s(f&&g)):s())}s()});let a=this.transform&&this.transform(e)||e;a!==e&&(a.on("error",l=>{this[ji](l,e),t()}),e.pipe(a)),a.pipe(r)}[yP](e,t){let i=e.mode&4095||this.dmode;this[Sa](e.absolute,i,r=>{if(r){this[ji](r,e),t();return}let o=1,s=a=>{--o===0&&(t(),this[ch](),e.resume())};e.mtime&&!this.noMtime&&(o++,He.utimes(e.absolute,e.atime||new Date,e.mtime,s)),this[Cf](e)&&(o++,He.chown(e.absolute,this[Sf](e),this[Tf](e),s)),s()})}[GU](e){e.unsupported=!0,this.warn("TAR_ENTRY_UNSUPPORTED",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[XU](e,t){this[rw](e,e.linkpath,"symlink",t)}[UU](e,t){let i=Hn(ss.resolve(this.cwd,e.linkpath));this[rw](e,i,"link",t)}[KU](){this[tw]++}[ch](){this[tw]--,this[fP]()}[vP](e){this[ch](),e.resume()}[mP](e,t){return e.type==="File"&&!this.unlink&&t.isFile()&&t.nlink<=1&&!Ef}[pP](e){this[KU]();let t=[e.path];e.linkpath&&t.push(e.linkpath),this.reservations.reserve(t,i=>this[$U](e,i))}[nw](e){e.type==="SymbolicLink"?mCe(this.dirCache):e.type!=="Directory"&&pCe(this.dirCache,e.absolute)}[$U](e,t){this[nw](e);let i=a=>{this[nw](e),t(a)},r=()=>{this[Sa](this.cwd,this.dmode,a=>{if(a){this[ji](a,e),i();return}this[kf]=!0,o()})},o=()=>{if(e.absolute!==this.cwd){let a=Hn(ss.dirname(e.absolute));if(a!==this.cwd)return this[Sa](a,this.dmode,l=>{if(l){this[ji](l,e),i();return}s()})}s()},s=()=>{He.lstat(e.absolute,(a,l)=>{if(l&&(this.keep||this.newer&&l.mtime>e.mtime)){this[vP](e),i();return}if(a||this[mP](e,l))return this[cr](null,e,i);if(l.isDirectory()){if(e.type==="Directory"){let u=!this.noChmod&&e.mode&&(l.mode&4095)!==e.mode,c=h=>this[cr](h,e,i);return u?He.chmod(e.absolute,e.mode,c):c()}if(e.absolute!==this.cwd)return He.rmdir(e.absolute,u=>this[cr](u,e,i))}if(e.absolute===this.cwd)return this[cr](null,e,i);gCe(e.absolute,u=>this[cr](u,e,i))})};this[kf]?o():r()}[cr](e,t,i){if(e){this[ji](e,t),i();return}switch(t.type){case"File":case"OldFile":case"ContiguousFile":return this[bP](t,i);case"Link":return this[UU](t,i);case"SymbolicLink":return this[XU](t,i);case"Directory":case"GNUDumpDir":return this[yP](t,i)}}[rw](e,t,i,r){He[i](t,e.absolute,o=>{o?this[ji](o,e):(this[ch](),e.resume()),r()})}},iw=n=>{try{return[null,n()]}catch(e){return[e,null]}},n8=class extends ow{[cr](e,t){return super[cr](e,t,()=>{})}[pP](e){if(this[nw](e),!this[kf]){let o=this[Sa](this.cwd,this.dmode);if(o)return this[ji](o,e);this[kf]=!0}if(e.absolute!==this.cwd){let o=Hn(ss.dirname(e.absolute));if(o!==this.cwd){let s=this[Sa](o,this.dmode);if(s)return this[ji](s,e)}}let[t,i]=iw(()=>He.lstatSync(e.absolute));if(i&&(this.keep||this.newer&&i.mtime>e.mtime))return this[vP](e);if(t||this[mP](e,i))return this[cr](null,e);if(i.isDirectory()){if(e.type==="Directory"){let s=!this.noChmod&&e.mode&&(i.mode&4095)!==e.mode,[a]=s?iw(()=>{He.chmodSync(e.absolute,e.mode)}):[];return this[cr](a,e)}let[o]=iw(()=>He.rmdirSync(e.absolute));this[cr](o,e)}let[r]=e.absolute===this.cwd?[]:iw(()=>fCe(e.absolute));this[cr](r,e)}[bP](e,t){let i=e.mode&4095||this.fmode,r=a=>{let l;try{He.closeSync(o)}catch(u){l=u}(a||l)&&this[ji](a||l,e),t()},o;try{o=He.openSync(e.absolute,i8(e.size),i)}catch(a){return r(a)}let s=this.transform&&this.transform(e)||e;s!==e&&(s.on("error",a=>this[ji](a,e)),e.pipe(s)),s.on("data",a=>{try{He.writeSync(o,a,0,a.length)}catch(l){r(l)}}),s.on("end",a=>{let l=null;if(e.mtime&&!this.noMtime){let u=e.atime||new Date,c=e.mtime;try{He.futimesSync(o,u,c)}catch(h){try{He.utimesSync(e.absolute,u,c)}catch{l=h}}}if(this[Cf](e)){let u=this[Sf](e),c=this[Tf](e);try{He.fchownSync(o,u,c)}catch(h){try{He.chownSync(e.absolute,u,c)}catch{l=l||h}}}r(l)})}[yP](e,t){let i=e.mode&4095||this.dmode,r=this[Sa](e.absolute,i);if(r){this[ji](r,e),t();return}if(e.mtime&&!this.noMtime)try{He.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[Cf](e))try{He.chownSync(e.absolute,this[Sf](e),this[Tf](e))}catch{}t(),e.resume()}[Sa](e,t){try{return e8.sync(Hn(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:t})}catch(i){return i}}[rw](e,t,i,r){try{He[i+"Sync"](t,e.absolute),r(),e.resume()}catch(o){return this[ji](o,e)}}};ow.Sync=n8;r8.exports=ow});var u8=m((FHe,l8)=>{"use strict";var bCe=Zc(),sw=wP(),s8=require("fs"),a8=oh(),o8=require("path"),DP=Qc();l8.exports=(n,e,t)=>{typeof n=="function"?(t=n,e=null,n={}):Array.isArray(n)&&(e=n,n={}),typeof e=="function"&&(t=e,e=null),e?e=Array.from(e):e=[];let i=bCe(n);if(i.sync&&typeof t=="function")throw new TypeError("callback not supported for sync tar functions");if(!i.file&&typeof t=="function")throw new TypeError("callback only supported with file option");return e.length&&yCe(i,e),i.file&&i.sync?vCe(i):i.file?wCe(i,t):i.sync?DCe(i):xCe(i)};var yCe=(n,e)=>{let t=new Map(e.map(o=>[DP(o),!0])),i=n.filter,r=(o,s)=>{let a=s||o8.parse(o).root||".",l=o===a?!1:t.has(o)?t.get(o):r(o8.dirname(o),a);return t.set(o,l),l};n.filter=i?(o,s)=>i(o,s)&&r(DP(o)):o=>r(DP(o))},vCe=n=>{let e=new sw.Sync(n),t=n.file,i=s8.statSync(t),r=n.maxReadSize||16*1024*1024;new a8.ReadStreamSync(t,{readSize:r,size:i.size}).pipe(e)},wCe=(n,e)=>{let t=new sw(n),i=n.maxReadSize||16*1024*1024,r=n.file,o=new Promise((s,a)=>{t.on("error",a),t.on("close",s),s8.stat(r,(l,u)=>{if(l)a(l);else{let c=new a8.ReadStream(r,{readSize:i,size:u.size});c.on("error",a),c.pipe(t)}})});return e?o.then(e,e):o},DCe=n=>new sw.Sync(n),xCe=n=>new sw(n)});var c8=m(ni=>{"use strict";ni.c=ni.create=ZX();ni.r=ni.replace=tP();ni.t=ni.list=Gv();ni.u=ni.update=VX();ni.x=ni.extract=u8();ni.Pack=Ov();ni.Unpack=wP();ni.Parse=Uv();ni.ReadEntry=vv();ni.WriteEntry=RE();ni.Header=Gc();ni.Pax=xv();ni.types=fE()});var f8=m((jHe,g8)=>{g8.exports=Ai;function Ai(n){if(!(this instanceof Ai))return new Ai(n);this.value=n}Ai.prototype.get=function(n){for(var e=this.value,t=0;t{var CCe=f8(),SCe=require("events").EventEmitter;p8.exports=hh;function hh(n){var e=hh.saw(n,{}),t=n.call(e.handlers,e);return t!==void 0&&(e.handlers=t),e.record(),e.chain()}hh.light=function(e){var t=hh.saw(e,{}),i=e.call(t.handlers,t);return i!==void 0&&(t.handlers=i),t.chain()};hh.saw=function(n,e){var t=new SCe;return t.handlers=e,t.actions=[],t.chain=function(){var i=CCe(t.handlers).map(function(r){if(this.isRoot)return r;var o=this.path;typeof r=="function"&&this.update(function(){return t.actions.push({path:o,args:[].slice.call(arguments)}),i})});return process.nextTick(function(){t.emit("begin"),t.next()}),i},t.pop=function(){return t.actions.shift()},t.next=function(){var i=t.pop();if(!i)t.emit("end");else if(!i.trap){var r=t.handlers;i.path.forEach(function(o){r=r[o]}),r.apply(t.handlers,i.args)}},t.nest=function(i){var r=[].slice.call(arguments,1),o=!0;if(typeof i=="boolean"){var o=i;i=r.shift()}var s=hh.saw(n,{}),a=n.call(s.handlers,s);a!==void 0&&(s.handlers=a),typeof t.step<"u"&&s.record(),i.apply(s.chain(),r),o!==!1&&s.on("end",t.next)},t.record=function(){TCe(t)},["trap","down","jump"].forEach(function(i){t[i]=function(){throw new Error("To use the trap, down and jump features, please call record() first to start recording actions.")}}),t};function TCe(n){n.step=0,n.pop=function(){return n.actions[n.step++]},n.trap=function(e,t){var i=Array.isArray(e)?e:[e];n.actions.push({path:i,step:n.step,cb:t,trap:!0})},n.down=function(e){var t=(Array.isArray(e)?e:[e]).join("/"),i=n.actions.slice(n.step).map(function(o){return o.trap&&o.step<=n.step?!1:o.path.join("/")==t}).indexOf(!0);i>=0?n.step+=i:n.step=n.actions.length;var r=n.actions[n.step-1];r&&r.trap?(n.step=r.step,r.cb()):n.next()},n.jump=function(e){n.step=e,n.next()}}});var y8=m((OHe,b8)=>{b8.exports=en;function en(n){if(!(this instanceof en))return new en(n);this.buffers=n||[],this.length=this.buffers.reduce(function(e,t){return e+t.length},0)}en.prototype.push=function(){for(var n=0;n=0?n:this.length-n,r=[].slice.call(arguments,2);e===void 0?e=this.length-i:e>this.length-i&&(e=this.length-i);for(var n=0;n0){var u=i-a;if(u+e0){var g=r.slice();g.unshift(h),g.push(d),t.splice.apply(t,[l,1].concat(g)),l+=g.length,r=[]}else t.splice(l,1,h,d),l+=2}else o.push(t[l].slice(u)),t[l]=t[l].slice(0,u),l++}for(r.length>0&&(t.splice.apply(t,[l,0].concat(r)),l+=r.length);o.lengththis.length&&(e=this.length);for(var i=0,r=0;r=e-n?Math.min(u+(e-n)-s,l):l;t[a].copy(o,s,u,c),s+=c-u}return o};en.prototype.pos=function(n){if(n<0||n>=this.length)throw new Error("oob");for(var e=n,t=0,i=null;;){if(i=this.buffers[t],e=this.buffers[t].length;)if(i=0,t++,t>=this.buffers.length)return-1;var l=this.buffers[t][i];if(l==n[r]){if(r==0&&(o={i:t,j:i,pos:s}),r++,r==n.length)return o.pos}else r!=0&&(t=o.i,i=o.j,s=o.pos,r=0);i++,s++}};en.prototype.toBuffer=function(){return this.slice()};en.prototype.toString=function(n,e,t){return this.slice(e,t).toString(n)}});var w8=m((MHe,v8)=>{v8.exports=function(n){function e(i,r){var o=t.store,s=i.split(".");s.slice(0,-1).forEach(function(l){o[l]===void 0&&(o[l]={}),o=o[l]});var a=s[s.length-1];return arguments.length==1?o[a]:o[a]=r}var t={get:function(i){return e(i)},set:function(i,r){return e(i,r)},store:n||{}};return t}});var k8=m((Wl,T8)=>{var kCe=m8(),D8=require("events").EventEmitter,ECe=y8(),aw=w8(),PCe=require("stream").Stream;Wl=T8.exports=function(n,e){if(Buffer.isBuffer(n))return Wl.parse(n);var t=Wl.stream();return n&&n.pipe?n.pipe(t):n&&(n.on(e||"data",function(i){t.write(i)}),n.on("end",function(){t.end()})),t};Wl.stream=function(n){if(n)return Wl.apply(null,arguments);var e=null;function t(h,d,g){e={bytes:h,skip:g,cb:function(f){e=null,d(f)}},r()}var i=null;function r(){if(!e){c&&(u=!0);return}if(typeof e=="function")e();else{var h=i+e.bytes;if(a.length>=h){var d;i==null?(d=a.splice(0,h),e.skip||(d=d.slice())):(e.skip||(d=a.slice(i,h)),i=h),e.skip?e.cb():e.cb(d)}}}function o(h){function d(){u||h.next()}var g=S8(function(f,p){return function(b){t(f,function(v){l.set(b,p(v)),d()})}});return g.tap=function(f){h.nest(f,l.store)},g.into=function(f,p){l.get(f)||l.set(f,{});var b=l;l=aw(b.get(f)),h.nest(function(){p.apply(this,arguments),this.tap(function(){l=b})},l.store)},g.flush=function(){l.store={},d()},g.loop=function(f){var p=!1;h.nest(!1,function b(){this.vars=l.store,f.call(this,function(){p=!0,d()},l.store),this.tap(function(){p?h.next():b.call(this)}.bind(this))},l.store)},g.buffer=function(f,p){typeof p=="string"&&(p=l.get(p)),t(p,function(b){l.set(f,b),d()})},g.skip=function(f){typeof f=="string"&&(f=l.get(f)),t(f,function(){d()})},g.scan=function(p,b){if(typeof b=="string")b=new Buffer(b);else if(!Buffer.isBuffer(b))throw new Error("search must be a Buffer or a string");var v=0;e=function(){var w=a.indexOf(b,i+v),D=w-i-v;w!==-1?(e=null,i!=null?(l.set(p,a.slice(i,i+v+D)),i+=v+D+b.length):(l.set(p,a.slice(0,v+D)),a.splice(0,v+D+b.length)),d(),r()):D=Math.max(a.length-b.length-i-v,0),v+=D},r()},g.peek=function(f){i=0,h.nest(function(){f.call(this,l.store),this.tap(function(){i=null})})},g}var s=kCe.light(o);s.writable=!0;var a=ECe();s.write=function(h){a.push(h),r()};var l=aw(),u=!1,c=!1;return s.end=function(){c=!0},s.pipe=PCe.prototype.pipe,Object.getOwnPropertyNames(D8.prototype).forEach(function(h){s[h]=D8.prototype[h]}),s};Wl.parse=function(e){var t=S8(function(o,s){return function(a){if(i+o<=e.length){var l=e.slice(i,i+o);i+=o,r.set(a,s(l))}else r.set(a,null);return t}}),i=0,r=aw();return t.vars=r.store,t.tap=function(o){return o.call(t,r.store),t},t.into=function(o,s){r.get(o)||r.set(o,{});var a=r;return r=aw(a.get(o)),s.call(t,r.store),r=a,t},t.loop=function(o){for(var s=!1,a=function(){s=!0};s===!1;)o.call(t,a,r.store);return t},t.buffer=function(o,s){typeof s=="string"&&(s=r.get(s));var a=e.slice(i,Math.min(e.length,i+s));return i+=s,r.set(o,a),t},t.skip=function(o){return typeof o=="string"&&(o=r.get(o)),i+=o,t},t.scan=function(o,s){if(typeof s=="string")s=new Buffer(s);else if(!Buffer.isBuffer(s))throw new Error("search must be a Buffer or a string");r.set(o,null);for(var a=0;a+i<=e.length-s.length+1;a++){for(var l=0;l=e.length},t};function x8(n){for(var e=0,t=0;t{var E8=require("stream").Transform,LCe=require("util");function Zl(n,e){if(!(this instanceof Zl))return new Zl;E8.call(this);var t=typeof n=="object"?n.pattern:n;this.pattern=Buffer.isBuffer(t)?t:Buffer.from(t),this.requiredLength=this.pattern.length,n.requiredExtraSize&&(this.requiredLength+=n.requiredExtraSize),this.data=new Buffer(""),this.bytesSoFar=0,this.matchFn=e}LCe.inherits(Zl,E8);Zl.prototype.checkDataChunk=function(n){var e=this.data.length>=this.requiredLength;if(!!e){var t=this.data.indexOf(this.pattern,n?1:0);if(t>=0&&t+this.requiredLength>this.data.length){if(t>0){var i=this.data.slice(0,t);this.push(i),this.bytesSoFar+=t,this.data=this.data.slice(t)}return}if(t===-1){var r=this.data.length-this.requiredLength+1,i=this.data.slice(0,r);this.push(i),this.bytesSoFar+=r,this.data=this.data.slice(r);return}if(t>0){var i=this.data.slice(0,t);this.data=this.data.slice(t),this.push(i),this.bytesSoFar+=t}var o=this.matchFn?this.matchFn(this.data,this.bytesSoFar):!0;if(o){this.data=new Buffer("");return}return!0}};Zl.prototype._transform=function(n,e,t){this.data=Buffer.concat([this.data,n]);for(var i=!0;this.checkDataChunk(!i);)i=!1;t()};Zl.prototype._flush=function(n){if(this.data.length>0)for(var e=!0;this.checkDataChunk(!e);)e=!1;this.data.length>0&&(this.push(this.data),this.data=null),n()};P8.exports=Zl});var L8=m((BHe,R8)=>{"use strict";var xP=require("stream"),FCe=require("util").inherits;function Pf(){if(!(this instanceof Pf))return new Pf;xP.PassThrough.call(this),this.path=null,this.type=null,this.isDirectory=!1}FCe(Pf,xP.PassThrough);Pf.prototype.autodrain=function(){return this.pipe(new xP.Transform({transform:function(n,e,t){t()}}))};R8.exports=Pf});var SP=m((HHe,I8)=>{"use strict";var Ta=k8(),CP=require("stream"),ICe=require("util"),jCe=require("zlib"),ACe=_8(),F8=L8(),de={STREAM_START:0,START:1,LOCAL_FILE_HEADER:2,LOCAL_FILE_HEADER_SUFFIX:3,FILE_DATA:4,FILE_DATA_END:5,DATA_DESCRIPTOR:6,CENTRAL_DIRECTORY_FILE_HEADER:7,CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX:8,CDIR64_END:9,CDIR64_END_DATA_SECTOR:10,CDIR64_LOCATOR:11,CENTRAL_DIRECTORY_END:12,CENTRAL_DIRECTORY_END_COMMENT:13,TRAILING_JUNK:14,ERROR:99},_f=4294967296,OCe=67324752,MCe=134695760,NCe=33639248,BCe=101075792,HCe=117853008,qCe=101010256;function vi(n){if(!(this instanceof vi))return new vi(n);CP.Transform.call(this),this.options=n||{},this.data=new Buffer(""),this.state=de.STREAM_START,this.skippedBytes=0,this.parsedEntity=null,this.outStreamInfo={}}ICe.inherits(vi,CP.Transform);vi.prototype.processDataChunk=function(n){var e;switch(this.state){case de.STREAM_START:case de.START:e=4;break;case de.LOCAL_FILE_HEADER:e=26;break;case de.LOCAL_FILE_HEADER_SUFFIX:e=this.parsedEntity.fileNameLength+this.parsedEntity.extraFieldLength;break;case de.DATA_DESCRIPTOR:e=12;break;case de.CENTRAL_DIRECTORY_FILE_HEADER:e=42;break;case de.CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX:e=this.parsedEntity.fileNameLength+this.parsedEntity.extraFieldLength+this.parsedEntity.fileCommentLength;break;case de.CDIR64_END:e=52;break;case de.CDIR64_END_DATA_SECTOR:e=this.parsedEntity.centralDirectoryRecordSize-44;break;case de.CDIR64_LOCATOR:e=16;break;case de.CENTRAL_DIRECTORY_END:e=18;break;case de.CENTRAL_DIRECTORY_END_COMMENT:e=this.parsedEntity.commentLength;break;case de.FILE_DATA:return 0;case de.FILE_DATA_END:return 0;case de.TRAILING_JUNK:return this.options.debug&&console.log("found",n.length,"bytes of TRAILING_JUNK"),n.length;default:return n.length}var t=n.length;if(t>>8,(o&255)===80){s=a;break}return this.skippedBytes+=s,this.options.debug&&console.log("Skipped",this.skippedBytes,"bytes"),s}this.state=de.ERROR;var l=r?"Not a valid zip file":"Invalid signature in zip file";if(this.options.debug){var u=n.readUInt32LE(0),c;try{c=n.slice(0,4).toString()}catch{}console.log("Unexpected signature in zip file: 0x"+u.toString(16),'"'+c+'", skipped',this.skippedBytes,"bytes")}return this.emit("error",new Error(l)),n.length}return this.skippedBytes=0,e;case de.LOCAL_FILE_HEADER:return this.parsedEntity=this._readFile(n),this.state=de.LOCAL_FILE_HEADER_SUFFIX,e;case de.LOCAL_FILE_HEADER_SUFFIX:var h=new F8,d=(this.parsedEntity.flags&2048)!==0;h.path=this._decodeString(n.slice(0,this.parsedEntity.fileNameLength),d);var f=n.slice(this.parsedEntity.fileNameLength,this.parsedEntity.fileNameLength+this.parsedEntity.extraFieldLength),p=this._readExtraFields(f);if(p&&p.parsed&&(p.parsed.path&&!d&&(h.path=p.parsed.path),Number.isFinite(p.parsed.uncompressedSize)&&this.parsedEntity.uncompressedSize===_f-1&&(this.parsedEntity.uncompressedSize=p.parsed.uncompressedSize),Number.isFinite(p.parsed.compressedSize)&&this.parsedEntity.compressedSize===_f-1&&(this.parsedEntity.compressedSize=p.parsed.compressedSize)),this.parsedEntity.extra=p.parsed||{},this.options.debug){let S=Object.assign({},this.parsedEntity,{path:h.path,flags:"0x"+this.parsedEntity.flags.toString(16),extraFields:p&&p.debug});console.log("decoded LOCAL_FILE_HEADER:",JSON.stringify(S,null,2))}return this._prepareOutStream(this.parsedEntity,h),this.emit("entry",h),this.state=de.FILE_DATA,e;case de.CENTRAL_DIRECTORY_FILE_HEADER:return this.parsedEntity=this._readCentralDirectoryEntry(n),this.state=de.CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX,e;case de.CENTRAL_DIRECTORY_FILE_HEADER_SUFFIX:var d=(this.parsedEntity.flags&2048)!==0,g=this._decodeString(n.slice(0,this.parsedEntity.fileNameLength),d),f=n.slice(this.parsedEntity.fileNameLength,this.parsedEntity.fileNameLength+this.parsedEntity.extraFieldLength),p=this._readExtraFields(f);p&&p.parsed&&p.parsed.path&&!d&&(g=p.parsed.path),this.parsedEntity.extra=p.parsed;var b=(this.parsedEntity.versionMadeBy&65280)>>8===3,v,w;if(b){v=this.parsedEntity.externalFileAttributes>>>16;var D=v>>>12;w=(D&10)===10}if(this.options.debug){let S=Object.assign({},this.parsedEntity,{path:g,flags:"0x"+this.parsedEntity.flags.toString(16),unixAttrs:v&&"0"+v.toString(8),isSymlink:w,extraFields:p.debug});console.log("decoded CENTRAL_DIRECTORY_FILE_HEADER:",JSON.stringify(S,null,2))}return this.state=de.START,e;case de.CDIR64_END:return this.parsedEntity=this._readEndOfCentralDirectory64(n),this.options.debug&&console.log("decoded CDIR64_END_RECORD:",this.parsedEntity),this.state=de.CDIR64_END_DATA_SECTOR,e;case de.CDIR64_END_DATA_SECTOR:return this.state=de.START,e;case de.CDIR64_LOCATOR:return this.state=de.START,e;case de.CENTRAL_DIRECTORY_END:return this.parsedEntity=this._readEndOfCentralDirectory(n),this.options.debug&&console.log("decoded CENTRAL_DIRECTORY_END:",this.parsedEntity),this.state=de.CENTRAL_DIRECTORY_END_COMMENT,e;case de.CENTRAL_DIRECTORY_END_COMMENT:return this.options.debug&&console.log("decoded CENTRAL_DIRECTORY_END_COMMENT:",n.slice(0,e).toString()),this.state=de.TRAILING_JUNK,e;case de.ERROR:return n.length;default:return console.log("didn't handle state #",this.state,"discarding"),n.length}};vi.prototype._prepareOutStream=function(n,e){var t=this,i=n.uncompressedSize===0&&/[\/\\]$/.test(e.path);e.path=e.path.replace(/^([/\\]*[.]+[/\\]+)*[/\\]*/,""),e.type=i?"Directory":"File",e.isDirectory=i;var r=!(n.flags&8);r&&(e.size=n.uncompressedSize);var o=n.versionsNeededToExtract<=45;if(this.outStreamInfo={stream:null,limit:r?n.compressedSize:-1,written:0},r)this.outStreamInfo.stream=new CP.PassThrough;else{var s=new Buffer(4);s.writeUInt32LE(MCe,0);var a=n.extra.zip64Mode,l=a?20:12,u={pattern:s,requiredExtraSize:l},c=new ACe(u,function(p,b){var v=t._readDataDescriptor(p,a),w=v.compressedSize===b;if(!a&&!w&&b>=_f)for(var D=b-_f;D>=0&&(w=v.compressedSize===D,!w);)D-=_f;if(!!w){t.state=de.FILE_DATA_END;var S=a?24:16;return t.data.length>0?t.data=Buffer.concat([p.slice(S),t.data]):t.data=p.slice(S),!0}});this.outStreamInfo.stream=c}var h=n.flags&1||n.flags&64;if(h||!o){var d=h?"Encrypted files are not supported!":"Zip version "+Math.floor(n.versionsNeededToExtract/10)+"."+n.versionsNeededToExtract%10+" is not supported";e.skip=!0,setImmediate(()=>{e.emit("error",new Error(d))}),this.outStreamInfo.stream.pipe(new F8().autodrain());return}var g=n.compressionMethod>0;if(g){var f=jCe.createInflateRaw();f.on("error",function(p){t.state=de.ERROR,t.emit("error",p)}),this.outStreamInfo.stream.pipe(f).pipe(e)}else this.outStreamInfo.stream.pipe(e);this._drainAllEntries&&e.autodrain()};vi.prototype._readFile=function(n){var e=Ta.parse(n).word16lu("versionsNeededToExtract").word16lu("flags").word16lu("compressionMethod").word16lu("lastModifiedTime").word16lu("lastModifiedDate").word32lu("crc32").word32lu("compressedSize").word32lu("uncompressedSize").word16lu("fileNameLength").word16lu("extraFieldLength").vars;return e};vi.prototype._readExtraFields=function(n){var e={},t={parsed:e};this.options.debug&&(t.debug=[]);for(var i=0;i=w+4&&a&1&&(e.mtime=new Date(n.readUInt32LE(i+w)*1e3),w+=4),r.extraSize>=w+4&&a&2&&(e.atime=new Date(n.readUInt32LE(i+w)*1e3),w+=4),r.extraSize>=w+4&&a&4&&(e.ctime=new Date(n.readUInt32LE(i+w)*1e3));break;case 28789:o="Info-ZIP Unicode Path Extra Field";var l=n.readUInt8(i);if(l===1){var w=1,u=n.readUInt32LE(i+w);w+=4;var c=n.slice(i+w);e.path=c.toString()}break;case 13:case 22613:o=r.extraId===13?"PKWARE Unix":"Info-ZIP UNIX (type 1)";var w=0;if(r.extraSize>=8){var h=new Date(n.readUInt32LE(i+w)*1e3);w+=4;var d=new Date(n.readUInt32LE(i+w)*1e3);if(w+=4,e.atime=h,e.mtime=d,r.extraSize>=12){var g=n.readUInt16LE(i+w);w+=2;var f=n.readUInt16LE(i+w);w+=2,e.uid=g,e.gid=f}}break;case 30805:o="Info-ZIP UNIX (type 2)";var w=0;if(r.extraSize>=4){var g=n.readUInt16LE(i+w);w+=2;var f=n.readUInt16LE(i+w);w+=2,e.uid=g,e.gid=f}break;case 30837:o="Info-ZIP New Unix";var w=0,p=n.readUInt8(i);if(w+=1,p===1){var b=n.readUInt8(i+w);w+=1,b<=6&&(e.uid=n.readUIntLE(i+w,b)),w+=b;var v=n.readUInt8(i+w);w+=1,v<=6&&(e.gid=n.readUIntLE(i+w,v))}break;case 30062:o="ASi Unix";var w=0;if(r.extraSize>=14){var D=n.readUInt32LE(i+w);w+=4;var S=n.readUInt16LE(i+w);w+=2;var F=n.readUInt32LE(i+w);w+=4;var g=n.readUInt16LE(i+w);w+=2;var f=n.readUInt16LE(i+w);if(w+=2,e.mode=S,e.uid=g,e.gid=f,r.extraSize>14){var L=i+w,j=i+r.extraSize-14,W=this._decodeString(n.slice(L,j));e.symlink=W}}break}this.options.debug&&t.debug.push({extraId:"0x"+r.extraId.toString(16),description:o,data:n.slice(i,i+r.extraSize).inspect()}),i+=r.extraSize}return t};vi.prototype._readDataDescriptor=function(n,e){if(e){var t=Ta.parse(n).word32lu("dataDescriptorSignature").word32lu("crc32").word64lu("compressedSize").word64lu("uncompressedSize").vars;return t}var t=Ta.parse(n).word32lu("dataDescriptorSignature").word32lu("crc32").word32lu("compressedSize").word32lu("uncompressedSize").vars;return t};vi.prototype._readCentralDirectoryEntry=function(n){var e=Ta.parse(n).word16lu("versionMadeBy").word16lu("versionsNeededToExtract").word16lu("flags").word16lu("compressionMethod").word16lu("lastModifiedTime").word16lu("lastModifiedDate").word32lu("crc32").word32lu("compressedSize").word32lu("uncompressedSize").word16lu("fileNameLength").word16lu("extraFieldLength").word16lu("fileCommentLength").word16lu("diskNumber").word16lu("internalFileAttributes").word32lu("externalFileAttributes").word32lu("offsetToLocalFileHeader").vars;return e};vi.prototype._readEndOfCentralDirectory64=function(n){var e=Ta.parse(n).word64lu("centralDirectoryRecordSize").word16lu("versionMadeBy").word16lu("versionsNeededToExtract").word32lu("diskNumber").word32lu("diskNumberWithCentralDirectoryStart").word64lu("centralDirectoryEntries").word64lu("totalCentralDirectoryEntries").word64lu("sizeOfCentralDirectory").word64lu("offsetToStartOfCentralDirectory").vars;return e};vi.prototype._readEndOfCentralDirectory=function(n){var e=Ta.parse(n).word16lu("diskNumber").word16lu("diskStart").word16lu("centralDirectoryEntries").word16lu("totalCentralDirectoryEntries").word32lu("sizeOfCentralDirectory").word32lu("offsetToStartOfCentralDirectory").word16lu("commentLength").vars;return e};var YCe="\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\xB6\xA7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xA2\xA3\xA5\u20A7\u0192\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\u2310\xAC\xBD\xBC\xA1\xAB\xBB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\xDF\u0393\u03C0\u03A3\u03C3\xB5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\xB1\u2265\u2264\u2320\u2321\xF7\u2248\xB0\u2219\xB7\u221A\u207F\xB2\u25A0 ";vi.prototype._decodeString=function(n,e){if(e)return n.toString("utf8");if(this.options.decodeString)return this.options.decodeString(n);let t="";for(var i=0;i0&&(this.data=this.data.slice(t),this.data.length!==0););if(this.state===de.FILE_DATA){if(this.outStreamInfo.limit>=0){var i=this.outStreamInfo.limit-this.outStreamInfo.written,r;i{if(this.state===de.FILE_DATA_END)return this.state=de.START,o.end(e);e()})}return}e()};vi.prototype.drainAll=function(){this._drainAllEntries=!0};vi.prototype._transform=function(n,e,t){var i=this;i.data.length>0?i.data=Buffer.concat([i.data,n]):i.data=n;var r=i.data.length,o=function(){if(i.data.length>0&&i.data.length0){e._parseOrOutput("buffer",function(){if(e.data.length>0)return setImmediate(function(){e._flush(n)});n()});return}if(e.state===de.FILE_DATA)return n(new Error("Stream finished in an invalid state, uncompression failed"));setImmediate(n)};I8.exports=vi});var A8=m((qHe,j8)=>{var Rf=require("stream").Transform,WCe=require("util"),ZCe=SP();function ka(n){if(!(this instanceof ka))return new ka(n);var e=n||{};Rf.call(this,{readableObjectMode:!0}),this.opts=n||{},this.unzipStream=new ZCe(this.opts);var t=this;this.unzipStream.on("entry",function(i){t.push(i)}),this.unzipStream.on("error",function(i){t.emit("error",i)})}WCe.inherits(ka,Rf);ka.prototype._transform=function(n,e,t){this.unzipStream.write(n,e,t)};ka.prototype._flush=function(n){var e=this;this.unzipStream.end(function(){process.nextTick(function(){e.emit("close")}),n()})};ka.prototype.on=function(n,e){return n==="entry"?Rf.prototype.on.call(this,"data",e):Rf.prototype.on.call(this,n,e)};ka.prototype.drainAll=function(){return this.unzipStream.drainAll(),this.pipe(new Rf({objectMode:!0,transform:function(n,e,t){t()}}))};j8.exports=ka});var B8=m((YHe,N8)=>{var Lf=require("path"),O8=require("fs"),M8=parseInt("0777",8);N8.exports=dh.mkdirp=dh.mkdirP=dh;function dh(n,e,t,i){typeof e=="function"?(t=e,e={}):(!e||typeof e!="object")&&(e={mode:e});var r=e.mode,o=e.fs||O8;r===void 0&&(r=M8),i||(i=null);var s=t||function(){};n=Lf.resolve(n),o.mkdir(n,r,function(a){if(!a)return i=i||n,s(null,i);switch(a.code){case"ENOENT":if(Lf.dirname(n)===n)return s(a);dh(Lf.dirname(n),e,function(l,u){l?s(l,u):dh(n,e,s,u)});break;default:o.stat(n,function(l,u){l||!u.isDirectory()?s(a,i):s(null,i)});break}})}dh.sync=function n(e,t,i){(!t||typeof t!="object")&&(t={mode:t});var r=t.mode,o=t.fs||O8;r===void 0&&(r=M8),i||(i=null),e=Lf.resolve(e);try{o.mkdirSync(e,r),i=i||e}catch(a){switch(a.code){case"ENOENT":i=n(Lf.dirname(e),t,i),n(e,t,i);break;default:var s;try{s=o.statSync(e)}catch{throw a}if(!s.isDirectory())throw a;break}}return i}});var W8=m((WHe,Y8)=>{var JCe=require("fs"),H8=require("path"),$Ce=require("util"),XCe=B8(),q8=require("stream").Transform,UCe=SP();function Ea(n){if(!(this instanceof Ea))return new Ea(n);q8.call(this),this.opts=n||{},this.unzipStream=new UCe(this.opts),this.unfinishedEntries=0,this.afterFlushWait=!1,this.createdDirectories={};var e=this;this.unzipStream.on("entry",this._processEntry.bind(this)),this.unzipStream.on("error",function(t){e.emit("error",t)})}$Ce.inherits(Ea,q8);Ea.prototype._transform=function(n,e,t){this.unzipStream.write(n,e,t)};Ea.prototype._flush=function(n){var e=this,t=function(){process.nextTick(function(){e.emit("close")}),n()};this.unzipStream.end(function(){if(e.unfinishedEntries>0)return e.afterFlushWait=!0,e.on("await-finished",t);t()})};Ea.prototype._processEntry=function(n){var e=this,t=H8.join(this.opts.path,n.path),i=n.isDirectory?t:H8.dirname(t);this.unfinishedEntries++;var r=function(){var o=JCe.createWriteStream(t);o.on("close",function(){e.unfinishedEntries--,e._notifyAwaiter()}),o.on("error",function(s){e.emit("error",s)}),n.pipe(o)};if(this.createdDirectories[i]||i===".")return r();XCe(i,function(o){if(o)return e.emit("error",o);if(e.createdDirectories[i]=!0,n.isDirectory){e.unfinishedEntries--,e._notifyAwaiter();return}r()})};Ea.prototype._notifyAwaiter=function(){this.afterFlushWait&&this.unfinishedEntries===0&&(this.emit("await-finished"),this.afterFlushWait=!1)};Y8.exports=Ea});var Z8=m(TP=>{"use strict";TP.Parse=A8();TP.Extract=W8()});var J8=m(kP=>{"use strict";Object.defineProperty(kP,"__esModule",{value:!0});function GCe(n,e,{signal:t}={}){return new Promise((i,r)=>{function o(){t==null||t.removeEventListener("abort",o),n.removeListener(e,s),n.removeListener("error",a)}function s(...l){o(),i(l)}function a(l){o(),r(l)}t==null||t.addEventListener("abort",o),n.on(e,s),n.on("error",a)})}kP.default=GCe});var $8=m(EP=>{"use strict";Object.defineProperty(EP,"__esModule",{value:!0});function QCe(n){return function(e,t){return new Promise((i,r)=>{n.call(this,e,t,(o,s)=>{o?r(o):i(s)})})}}EP.default=QCe});var RP=m((_P,U8)=>{"use strict";var X8=_P&&_P.__importDefault||function(n){return n&&n.__esModule?n:{default:n}},KCe=require("events"),zCe=X8(Ot()),VCe=X8($8()),Ff=zCe.default("agent-base");function eSe(n){return Boolean(n)&&typeof n.addRequest=="function"}function PP(){let{stack:n}=new Error;return typeof n!="string"?!1:n.split(` -`).some(e=>e.indexOf("(https.js:")!==-1||e.indexOf("node:https:")!==-1)}function lw(n,e){return new lw.Agent(n,e)}(function(n){class e extends KCe.EventEmitter{constructor(i,r){super();let o=r;typeof i=="function"?this.callback=i:i&&(o=i),this.timeout=null,o&&typeof o.timeout=="number"&&(this.timeout=o.timeout),this.maxFreeSockets=1,this.maxSockets=1,this.maxTotalSockets=1/0,this.sockets={},this.freeSockets={},this.requests={},this.options={}}get defaultPort(){return typeof this.explicitDefaultPort=="number"?this.explicitDefaultPort:PP()?443:80}set defaultPort(i){this.explicitDefaultPort=i}get protocol(){return typeof this.explicitProtocol=="string"?this.explicitProtocol:PP()?"https:":"http:"}set protocol(i){this.explicitProtocol=i}callback(i,r,o){throw new Error('"agent-base" has no default implementation, you must subclass and override `callback()`')}addRequest(i,r){let o=Object.assign({},r);typeof o.secureEndpoint!="boolean"&&(o.secureEndpoint=PP()),o.host==null&&(o.host="localhost"),o.port==null&&(o.port=o.secureEndpoint?443:80),o.protocol==null&&(o.protocol=o.secureEndpoint?"https:":"http:"),o.host&&o.path&&delete o.path,delete o.agent,delete o.hostname,delete o._defaultAgent,delete o.defaultPort,delete o.createConnection,i._last=!0,i.shouldKeepAlive=!1;let s=!1,a=null,l=o.timeout||this.timeout,u=g=>{i._hadError||(i.emit("error",g),i._hadError=!0)},c=()=>{a=null,s=!0;let g=new Error(`A "socket" was not created for HTTP request before ${l}ms`);g.code="ETIMEOUT",u(g)},h=g=>{s||(a!==null&&(clearTimeout(a),a=null),u(g))},d=g=>{if(s)return;if(a!=null&&(clearTimeout(a),a=null),eSe(g)){Ff("Callback returned another Agent instance %o",g.constructor.name),g.addRequest(i,o);return}if(g){g.once("free",()=>{this.freeSocket(g,o)}),i.onSocket(g);return}let f=new Error(`no Duplex stream was returned to agent-base for \`${i.method} ${i.path}\``);u(f)};if(typeof this.callback!="function"){u(new Error("`callback` is not defined"));return}this.promisifiedCallback||(this.callback.length>=3?(Ff("Converting legacy callback function to promise"),this.promisifiedCallback=VCe.default(this.callback)):this.promisifiedCallback=this.callback),typeof l=="number"&&l>0&&(a=setTimeout(c,l)),"port"in o&&typeof o.port!="number"&&(o.port=Number(o.port));try{Ff("Resolving socket for %o request: %o",o.protocol,`${i.method} ${i.path}`),Promise.resolve(this.promisifiedCallback(i,o)).then(d,h)}catch(g){Promise.reject(g).catch(h)}}freeSocket(i,r){Ff("Freeing socket %o %o",i.constructor.name,r),i.destroy()}destroy(){Ff("Destroying agent %o",this.constructor.name)}}n.Agent=e,n.prototype=n.Agent.prototype})(lw||(lw={}));U8.exports=lw});var Q8=m(Jl=>{"use strict";var tSe=Jl&&Jl.__awaiter||function(n,e,t,i){function r(o){return o instanceof t?o:new t(function(s){s(o)})}return new(t||(t=Promise))(function(o,s){function a(c){try{u(i.next(c))}catch(h){s(h)}}function l(c){try{u(i.throw(c))}catch(h){s(h)}}function u(c){c.done?o(c.value):r(c.value).then(a,l)}u((i=i.apply(n,e||[])).next())})},If=Jl&&Jl.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Jl,"__esModule",{value:!0});var iSe=If(require("net")),nSe=If(require("tls")),LP=If(require("url")),rSe=If(Ot()),oSe=If(J8()),sSe=RP(),Pa=(0,rSe.default)("http-proxy-agent");function aSe(n){return typeof n=="string"?/^https:?$/i.test(n):!1}var G8=class extends sSe.Agent{constructor(e){let t;if(typeof e=="string"?t=LP.default.parse(e):t=e,!t)throw new Error("an HTTP(S) proxy server `host` and `port` must be specified!");Pa("Creating new HttpProxyAgent instance: %o",t);super(t);let i=Object.assign({},t);this.secureProxy=t.secureProxy||aSe(i.protocol),i.host=i.hostname||i.host,typeof i.port=="string"&&(i.port=parseInt(i.port,10)),!i.port&&i.host&&(i.port=this.secureProxy?443:80),i.host&&i.path&&(delete i.path,delete i.pathname),this.proxy=i}callback(e,t){return tSe(this,void 0,void 0,function*(){let{proxy:i,secureProxy:r}=this,o=LP.default.parse(e.path);o.protocol||(o.protocol="http:"),o.hostname||(o.hostname=t.hostname||t.host||null),o.port==null&&typeof t.port&&(o.port=String(t.port)),o.port==="80"&&(o.port=""),e.path=LP.default.format(o),i.auth&&e.setHeader("Proxy-Authorization",`Basic ${Buffer.from(i.auth).toString("base64")}`);let s;if(r?(Pa("Creating `tls.Socket`: %o",i),s=nSe.default.connect(i)):(Pa("Creating `net.Socket`: %o",i),s=iSe.default.connect(i)),e._header){let a,l;Pa("Regenerating stored HTTP header string for request"),e._header=null,e._implicitHeader(),e.output&&e.output.length>0?(Pa("Patching connection write() output buffer with updated header"),a=e.output[0],l=a.indexOf(`\r -\r -`)+4,e.output[0]=e._header+a.substring(l),Pa("Output buffer: %o",e.output)):e.outputData&&e.outputData.length>0&&(Pa("Patching connection write() output buffer with updated header"),a=e.outputData[0].data,l=a.indexOf(`\r -\r -`)+4,e.outputData[0].data=e._header+a.substring(l),Pa("Output buffer: %o",e.outputData[0].data))}return yield(0,oSe.default)(s,"connect"),s})}};Jl.default=G8});var z8=m((jP,K8)=>{"use strict";var lSe=jP&&jP.__importDefault||function(n){return n&&n.__esModule?n:{default:n}},FP=lSe(Q8());function IP(n){return new FP.default(n)}(function(n){n.HttpProxyAgent=FP.default,n.prototype=FP.default.prototype})(IP||(IP={}));K8.exports=IP});var V8=m(Af=>{"use strict";var uSe=Af&&Af.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(Af,"__esModule",{value:!0});var cSe=uSe(Ot()),jf=cSe.default("https-proxy-agent:parse-proxy-response");function hSe(n){return new Promise((e,t)=>{let i=0,r=[];function o(){let h=n.read();h?c(h):n.once("readable",o)}function s(){n.removeListener("end",l),n.removeListener("error",u),n.removeListener("close",a),n.removeListener("readable",o)}function a(h){jf("onclose had error %o",h)}function l(){jf("onend")}function u(h){s(),jf("onerror %o",h),t(h)}function c(h){r.push(h),i+=h.length;let d=Buffer.concat(r,i);if(d.indexOf(`\r -\r -`)===-1){jf("have not received end of HTTP headers yet..."),o();return}let f=d.toString("ascii",0,d.indexOf(`\r -`)),p=+f.split(" ")[1];jf("got proxy server response: %o",f),e({statusCode:p,buffered:d})}n.on("error",u),n.on("close",a),n.on("end",l),o()})}Af.default=hSe});var nG=m($l=>{"use strict";var dSe=$l&&$l.__awaiter||function(n,e,t,i){function r(o){return o instanceof t?o:new t(function(s){s(o)})}return new(t||(t=Promise))(function(o,s){function a(c){try{u(i.next(c))}catch(h){s(h)}}function l(c){try{u(i.throw(c))}catch(h){s(h)}}function u(c){c.done?o(c.value):r(c.value).then(a,l)}u((i=i.apply(n,e||[])).next())})},gh=$l&&$l.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty($l,"__esModule",{value:!0});var eG=gh(require("net")),tG=gh(require("tls")),gSe=gh(require("url")),fSe=gh(require("assert")),pSe=gh(Ot()),mSe=RP(),bSe=gh(V8()),Of=pSe.default("https-proxy-agent:agent"),iG=class extends mSe.Agent{constructor(e){let t;if(typeof e=="string"?t=gSe.default.parse(e):t=e,!t)throw new Error("an HTTP(S) proxy server `host` and `port` must be specified!");Of("creating new HttpsProxyAgent instance: %o",t);super(t);let i=Object.assign({},t);this.secureProxy=t.secureProxy||wSe(i.protocol),i.host=i.hostname||i.host,typeof i.port=="string"&&(i.port=parseInt(i.port,10)),!i.port&&i.host&&(i.port=this.secureProxy?443:80),this.secureProxy&&!("ALPNProtocols"in i)&&(i.ALPNProtocols=["http 1.1"]),i.host&&i.path&&(delete i.path,delete i.pathname),this.proxy=i}callback(e,t){return dSe(this,void 0,void 0,function*(){let{proxy:i,secureProxy:r}=this,o;r?(Of("Creating `tls.Socket`: %o",i),o=tG.default.connect(i)):(Of("Creating `net.Socket`: %o",i),o=eG.default.connect(i));let s=Object.assign({},i.headers),l=`CONNECT ${`${t.host}:${t.port}`} HTTP/1.1\r -`;i.auth&&(s["Proxy-Authorization"]=`Basic ${Buffer.from(i.auth).toString("base64")}`);let{host:u,port:c,secureEndpoint:h}=t;vSe(c,h)||(u+=`:${c}`),s.Host=u,s.Connection="close";for(let b of Object.keys(s))l+=`${b}: ${s[b]}\r -`;let d=bSe.default(o);o.write(`${l}\r -`);let{statusCode:g,buffered:f}=yield d;if(g===200){if(e.once("socket",ySe),t.secureEndpoint){let b=t.servername||t.host;if(!b)throw new Error('Could not determine "servername"');return Of("Upgrading socket connection to TLS"),tG.default.connect(Object.assign(Object.assign({},DSe(t,"host","hostname","path","port")),{socket:o,servername:b}))}return o}o.destroy();let p=new eG.default.Socket;return p.readable=!0,e.once("socket",b=>{Of("replaying proxy buffer for failed request"),fSe.default(b.listenerCount("data")>0),b.push(f),b.push(null)}),p})}};$l.default=iG;function ySe(n){n.resume()}function vSe(n,e){return Boolean(!e&&n===80||e&&n===443)}function wSe(n){return typeof n=="string"?/^https:?$/i.test(n):!1}function DSe(n,...e){let t={},i;for(i in n)e.includes(i)||(t[i]=n[i]);return t}});var oG=m((MP,rG)=>{"use strict";var xSe=MP&&MP.__importDefault||function(n){return n&&n.__esModule?n:{default:n}},AP=xSe(nG());function OP(n){return new AP.default(n)}(function(n){n.HttpsProxyAgent=AP.default,n.prototype=AP.default.prototype})(OP||(OP={}));rG.exports=OP});var aG=m((QHe,sG)=>{"use strict";var CSe=["aborted","complete","headers","httpVersion","httpVersionMinor","httpVersionMajor","method","rawHeaders","rawTrailers","setTimeout","socket","statusCode","statusMessage","trailers","url"];sG.exports=(n,e)=>{if(e._readableState.autoDestroy)throw new Error("The second stream must have the `autoDestroy` option set to `false`");let t=new Set(Object.keys(n).concat(CSe)),i={};for(let r of t)r in e||(i[r]={get(){let o=n[r];return typeof o=="function"?o.bind(n):o},set(o){n[r]=o},enumerable:!0,configurable:!1});return Object.defineProperties(e,i),n.once("aborted",()=>{e.destroy(),e.emit("aborted")}),n.once("close",()=>{n.complete&&e.readable?e.once("end",()=>{e.emit("close")}):e.emit("close")}),e}});var uG=m((KHe,lG)=>{"use strict";var{Transform:SSe,PassThrough:TSe}=require("stream"),NP=require("zlib"),kSe=aG();lG.exports=n=>{let e=(n.headers["content-encoding"]||"").toLowerCase();if(!["gzip","deflate","br"].includes(e))return n;let t=e==="br";if(t&&typeof NP.createBrotliDecompress!="function")return n.destroy(new Error("Brotli is not supported on Node.js < 12")),n;let i=!0,r=new SSe({transform(a,l,u){i=!1,u(null,a)},flush(a){a()}}),o=new TSe({autoDestroy:!1,destroy(a,l){n.destroy(),l(a)}}),s=t?NP.createBrotliDecompress():NP.createUnzip();return s.once("error",a=>{if(i&&!n.readable){o.end();return}o.destroy(a)}),kSe(n,o),n.pipe(r).pipe(s).pipe(o),o}});function ESe(n){let e;n.protocol==="http:"?e=process.env.HTTP_PROXY||process.env.http_proxy||null:n.protocol==="https:"&&(e=process.env.HTTPS_PROXY||process.env.https_proxy||process.env.HTTP_PROXY||process.env.http_proxy||null);let t=process.env.NO_PROXY||process.env.no_proxy;if(t==="*")e=null;else if(t){let i=n.hostname.replace(/^\.*/,".").toLowerCase(),r=n.port||n.protocol.startsWith("https")?"443":"80",o=t.split(",");for(let s=0,a=o.length;s{if(i){let u=i.onCancellationRequested(()=>{u.dispose(),l.destroy(new Error("request aborted"))})}let a,l=r.request(t,u=>{let c=u;if(u.statusCode>=200&&u.statusCode<300||u.statusCode===1223){let h=u.headers||{},d=[],g=h["content-type"]||"";c=(0,fG.default)(u),c.on("data",f=>{d.push(f)}),c.on("end",()=>{a&&clearTimeout(a);let f=Buffer.concat(d);if(!t.buffer&&(g.startsWith("application/json")||g.startsWith("text/"))){let p=g.match(/charset=(\S+)/),b=p?p[1]:"utf8",v=f.toString(b);if(!g.includes("application/json"))o(v);else try{let w=JSON.parse(v);o(w)}catch(w){s(new Error(`Parse response error: ${w}`))}}else o(f)}),c.on("error",f=>{s(new Error(`Unable to connect ${n}: ${f.message}`))})}else s(new Error(`Bad response from ${n}: ${u.statusCode}`))});l.on("error",u=>{t.agent&&u.code=="ECONNRESET"?a=setTimeout(()=>{s(u)},500):s(u)}),l.on("timeout",()=>{l.destroy(new Error(`Request timeout after ${t.timeout}ms`))}),e&&(typeof e=="string"||Buffer.isBuffer(e)?l.write(e):l.write(JSON.stringify(e))),t.timeout&&l.setTimeout(t.timeout),l.end()})}function RSe(n){return n===null?"null":n===void 0?"undefined":typeof n=="string"?"string":Buffer.isBuffer(n)?"buffer":Array.isArray(n)||_t(n)?"object":"unknown"}function fh(n,e={},t){let i=HP(n,e);return _Se(n,e.data,i,t).catch(r=>{if(pG.error(`Fetch error for ${n}:`,i,r),i.agent&&i.agent.proxy){let{proxy:o}=i.agent;throw new Error(`Request failed using proxy ${o.host}: ${r.message}`)}else throw r})}var uw,BP,cG,hG,dG,gG,fG,pG,cw=_(()=>{"use strict";uw=C(eE()),BP=require("url"),cG=C(require("fs"));In();V();hG=require("querystring"),dG=C(z8()),gG=C(oG()),fG=C(uG()),pG=q()("model-fetch")});function Nf(n,e,t){let{dest:i,onProgress:r,extract:o}=e;if(!i||!Mf.default.isAbsolute(i))throw new Error("Expect absolute file path for dest option.");let s;try{s=hw.default.statSync(i)}catch{hw.default.mkdirpSync(i)}if(s&&!s.isDirectory())throw new Error(`${i} exists, but not directory!`);let a=n.startsWith("https")?dw.https:dw.http,l=HP(n,e),u=Mf.default.extname(n);return new Promise((c,h)=>{if(t){let f=t.onCancellationRequested(()=>{f.dispose(),g.destroy(new Error("request aborted"))})}let d,g=a.request(l,f=>{var p,b;if(f.statusCode>=200&&f.statusCode<300||f.statusCode===1223){let v=f.headers||{},w=v["content-disposition"];if(!u&&w){let L=mG.default.parse(w);(p=L.parameters)!=null&&p.filename&&(u=Mf.default.extname(L.parameters.filename))}if(o===!0)if(u===".zip"||v["content-type"]=="application/zip")o="unzip";else if(u==".tgz")o="untar";else{h(new Error(`Unable to extract for ${n}`));return}let D=Number(v["content-length"]),S=0;isNaN(D)||f.on("data",L=>{S+=L.length;let j=(S/D*100).toFixed(1);r?r(j):qP.info(`Download ${n} progress ${j}%`)}),f.on("error",L=>{h(new Error(`Unable to connect ${n}: ${L.message}`))}),f.on("data",()=>{d&&(clearTimeout(d),d=void 0)}),f.on("end",()=>{qP.info("Download completed:",n)});let F;o==="untar"?F=f.pipe(bG.default.x({strip:(b=e.strip)!=null?b:1,C:i})):o==="unzip"?F=f.pipe(yG.default.Extract({path:i})):(i=Mf.default.join(i,`${Uo()}${u}`),F=f.pipe(hw.default.createWriteStream(i))),F.on("finish",()=>{qP.info(`Downloaded ${n} => ${i}`),setTimeout(()=>{c(i)},100)}),F.on("error",h)}else h(new Error(`Invalid response from ${n}: ${f.statusCode}`))});g.on("error",f=>{l.agent&&f.code=="ECONNRESET"?d=setTimeout(()=>{h(f)},500):h(f)}),g.on("timeout",()=>{g.destroy(new Error(`request timeout after ${e.timeout}ms`))}),e.timeout&&g.setTimeout(e.timeout),g.end()})}var mG,dw,hw,Mf,bG,yG,qP,YP=_(()=>{"use strict";mG=C(n$()),dw=C(eE()),hw=C(Rn()),Mf=C(require("path")),bG=C(c8()),yG=C(Z8());Oe();cw();qP=q()("model-download")});function FSe(n="coc.nvim"){let e="https://registry.npmjs.org/",t=qn.default.join(LSe,".npmrc");if($t.default.existsSync(t))try{let i=$t.default.readFileSync(t,"utf8"),r={};for(let o of i.split(/\r?\n/))if(o.indexOf("=")>-1){let[s,a,l]=o.match(/^(.*?)=(.*)$/);r[a]=l}r[`${n}:registry`]?e=r[`${n}:registry`]:r.registry&&(e=r.registry)}catch(i){WP.error("Error on read .npmrc:",i)}return e.endsWith("/")?e:e+"/"}function ISe(n){let e=qn.default.basename(n);return e==="npm"||e==="npm.CMD"}function jSe(n){let e=qn.default.basename(n);return["yarn","yarn.CMD","yarnpkg","yarnpkg.CMD"].includes(e)}function ASe(n,e){let t=["install","--ignore-scripts","--no-lockfile","--production"];return e.startsWith("https://github.com")&&(t=["install"]),ISe(n)&&(t.push("--legacy-peer-deps"),t.push("--no-global")),jSe(n)&&t.push("--ignore-engines"),t}function OSe(n){let e;try{e=JSON.parse(n).dependencies||{}}catch{e={}}return zi(e,["coc.nvim","esbuild","webpack","@types/node"])}function vG(n){return!!($t.default.existsSync(n)&&$t.default.lstatSync(n).isSymbolicLink())}function pw(n,e){return t=>new CG(e,n,t)}var wG,DG,$t,fw,qn,xG,gw,WP,LSe,CG,SG=_(()=>{"use strict";wG=require("child_process"),DG=require("events"),$t=C(Rn());Eg();fw=C(require("os")),qn=C(require("path")),xG=C(require("readline")),gw=C(nf());Je();Vo();V();YP();cw();WP=q()("model-installer"),LSe=global.__TEST__?fw.default.tmpdir():fw.default.homedir();CG=class extends DG.EventEmitter{constructor(e,t,i){super();this.root=e;this.npm=t;this.def=i;if($t.default.existsSync(e)||$t.default.mkdirpSync(e),/^https?:/.test(i))this.url=i;else{let r=i.match(/(.+)@([^/]+)$/);r?(this.name=r[1],this.version=r[2]):this.name=i}}get info(){return{name:this.name,version:this.version}}async install(){this.log(`Using npm from: ${this.npm}`);let e=await this.getInfo();WP.info(`Fetched info of ${this.def}`,e);let{name:t}=e,i=e["engines.coc"]?e["engines.coc"].replace(/^\^/,">="):"";if(i&&!gw.default.satisfies(y.version,i))throw new Error(`${t} ${e.version} requires coc.nvim >= ${i}, please update coc.nvim.`);return await this.doInstall(e),t}async update(e){this.url=e;let t=qn.default.join(this.root,this.name);if(vG(t)){this.log("Skipped update for symbol link");return}let i;if($t.default.existsSync(qn.default.join(t,"package.json"))){let a=await $t.default.readFile(qn.default.join(t,"package.json"),"utf8");i=JSON.parse(a).version}this.log(`Using npm from: ${this.npm}`);let r=await this.getInfo();if(i&&r.version&&gw.default.gte(i,r.version)){this.log(`Current version ${i} is up to date.`);return}let o=r["engines.coc"]?r["engines.coc"].replace(/^\^/,">="):"";if(o&&!gw.default.satisfies(y.version,o))throw new Error(`${r.version} requires coc.nvim ${o}, please update coc.nvim.`);await this.doInstall(r);let s=qn.default.join(this.root,r.name,"package.json");return this.log(`Updated to v${r.version}`),qn.default.dirname(s)}async doInstall(e){let t=qn.default.join(this.root,e.name);if(vG(t))return!1;let i=await $t.default.mkdtemp(qn.default.join(fw.default.tmpdir(),`${e.name.replace("/","-")}-`)),r=e["dist.tarball"];this.log(`Downloading from ${r}`),await Nf(r,{dest:i,onProgress:d=>this.log(`Download progress ${d}%`,!0),extract:"untar"}),this.log(`Extension download at ${i}`);let o=await $t.default.readFile(qn.default.join(i,"package.json"),"utf8"),s=OSe(o);Object.keys(s).length&&await new Promise((g,f)=>{let p=ASe(this.npm,r);this.log(`Installing dependencies by: ${this.npm} ${p.join(" ")}.`);let b=(0,wG.spawn)(this.npm,p,{cwd:i});xG.default.createInterface({input:b.stdout}).on("line",D=>{this.log(`[npm] ${D}`,!0)}),b.stderr.setEncoding("utf8"),b.stdout.setEncoding("utf8"),b.on("error",f);let w="";b.stderr.on("data",D=>{w+=D}),b.on("exit",D=>{if(D){w&&this.log(w),f(new Error(`${this.npm} install exited with ${D}`));return}g()})});let a=qn.default.resolve(this.root,global.__TEST__?"":"..","package.json"),l=[];$t.default.existsSync(a)||$t.default.writeFileSync(a,"{}");let u=_c($t.default.readFileSync(a,"utf8"),l,{allowTrailingComma:!0});if(l&&l.length>0)throw new Error(`Error on load ${a}`);u.dependencies=u.dependencies||{},this.url?u.dependencies[e.name]=this.url:u.dependencies[e.name]=">="+e.version;let c={dependencies:{}};Object.keys(u.dependencies).sort().forEach(d=>{c.dependencies[d]=u.dependencies[d]});let h=await Ht(t);return h&&(h.isDirectory()?$t.default.removeSync(t):$t.default.unlinkSync(t)),await $t.default.move(i,t,{overwrite:!0}),await $t.default.writeFile(a,JSON.stringify(c,null,2),{encoding:"utf8"}),$t.default.existsSync(i)&&$t.default.rmdirSync(i),this.log(`Update package.json at ${a}`),this.log(`Installed extension ${this.name}@${e.version} at ${t}`),!0}async getInfo(){if(this.url)return await this.getInfoFromUri();let e=FSe();this.log(`Get info from ${e}`);let t=await fh(e+this.name,{timeout:1e4,buffer:!0}),i=JSON.parse(t.toString());this.version||(this.version=i["dist-tags"].latest);let r=i.versions[this.version];if(!r)throw new Error(`${this.def} doesn't exists in ${e}.`);let o=r.engines&&r.engines.coc;if(!o)throw new Error(`${this.def} is not valid coc extension, "engines" field with coc property required.`);return{"dist.tarball":r.dist.tarball,"engines.coc":o,version:r.version,name:i.name}}async getInfoFromUri(){let{url:e}=this;if(!e.startsWith("https://github.com"))throw new Error(`"${e}" is not supported, coc.nvim support github.com only`);e=e.replace(/\/$/,"");let t="master";if(e.includes("@")){let s=e.indexOf("@");t=e.substr(s+1),e=e.substring(0,s)}let i=e.replace("github.com","raw.githubusercontent.com")+`/${t}/package.json`;this.log(`Get info from ${i}`);let r=await fh(i,{timeout:1e4}),o=typeof r=="string"?JSON.parse(r):r;return this.name=o.name,{"dist.tarball":`${e}/archive/${t}.tar.gz`,"engines.coc":o.engines?o.engines.coc:null,name:o.name,version:o.version}}log(e,t=!1){WP.info(e),this.emit("message",e,t)}}});var ph,MSe,mw,TG=_(()=>{"use strict";ph=C(require("fs"));Jt();MSe=q()("model-memos"),mw=class{constructor(e){this.filepath=e;ph.default.existsSync(e)||ph.default.writeFileSync(e,"{}","utf8")}fetchContent(e,t){try{let i=ph.default.readFileSync(this.filepath,"utf8"),o=JSON.parse(i)[e];return o?o[t]:void 0}catch{return}}async update(e,t,i){let{filepath:r}=this;try{let o=ph.default.readFileSync(r,"utf8"),s=o?JSON.parse(o):{};s[e]=s[e]||{},i!==void 0?s[e][t]=Pr(i):delete s[e][t],o=JSON.stringify(s,null,2),ph.default.writeFileSync(r,o,"utf8")}catch(o){MSe.error("Error on update memos:",o)}}createMemento(e){return{get:(t,i)=>{let r=this.fetchContent(e,t);return r===void 0?i:r},update:async(t,i)=>{await this.update(e,t,i)}}}}});var bw,kG=_(()=>{"use strict";we();uk();bw=class{constructor(e,t){if(typeof e!="string"&&(!e||!O.isUri(e)&&typeof e.uri!="string"))throw ak("base");if(typeof t!="string")throw ak("pattern");typeof e=="string"?this.baseUri=O.file(e):O.isUri(e)?this.baseUri=e:this.baseUri=O.parse(e.uri),this.pattern=t}toJSON(){return{pattern:this.pattern,baseUri:this.baseUri.toJSON()}}}});var PG=m((xqe,EG)=>{"use strict";EG.exports=H()});function _G(n,e){if(!n.killed)if(NSe)try{let t={stdio:["pipe","pipe","ignore"]};return e&&(t.cwd=e),Bf.execFileSync("taskkill",["/T","/F","/PID",n.pid.toString()],t),!0}catch{return!1}else if(HSe||BSe)try{let t=(0,yw.join)(qSe,"bin/terminateProcess.sh");return!Bf.spawnSync(t,[n.pid.toString()]).error}catch{return!1}else return n.kill("SIGKILL"),!0}var Bf,yw,NSe,BSe,HSe,qSe,RG=_(()=>{"use strict";Bf=C(require("child_process")),yw=require("path"),NSe=process.platform==="win32",BSe=process.platform==="darwin",HSe=process.platform==="linux",qSe=(0,yw.dirname)(__dirname)});function YSe(n){return typeof n!="number"?!1:n>=0&&n<=100}var LG,Aqe,Hf,ZP=_(()=>{"use strict";LG=C(H());z();ke();V();Aqe=q()("language-client-progressPart"),Hf=class{constructor(e,t,i,r){this.id=e;this.token=i;this.disposables=[];this._cancelled=!1;this._percent=0;this._started=!1;!y.env.dialog||this.disposables.push(t.onProgress(LG.WorkDoneProgress.type,this.token,o=>{switch(o.kind){case"begin":this.begin(o);break;case"report":this.report(o);break;case"end":this.done(o.message),r&&r(this);break}}))}begin(e){this._started||(this._started=!0,k.withProgress({source:`language-client-${this.id}`,cancellable:e.cancellable,title:e.title},(t,i)=>(this.progress=t,this.report(e),new Promise(r=>{e.cancellable&&i.onCancellationRequested(()=>{this.cancel(),r()}),this._resolve=r}))).catch(t=>{k.showErrorMessage(t.message)}).finally(()=>{this._resolve=void 0,this.progress=void 0}))}report(e){if(!this.progress)return;let t={};e.message&&(t.message=e.message),YSe(e.percentage)&&(t.increment=e.percentage-this._percent,this._percent=e.percentage),Object.keys(t).length>0&&this.progress.report(t)}cancel(){this._cancelled||(this._cancelled=!0,Z(this.disposables))}done(e){if(this.progress){let t={};e&&(t.message=e),this._percent>0&&(t.increment=100-this._percent),this.progress.report(t)}setTimeout(()=>{this._resolve&&this._resolve()},300),this.cancel()}}});var JP,$P,FG=_(()=>{"use strict";JP=C(H()),$P=class{constructor(e){this.defaultDelay=e,this.timeout=void 0,this.completionPromise=void 0,this.onSuccess=void 0,this.task=void 0}trigger(e,t=this.defaultDelay){return this.task=e,t>=0&&this.cancelTimeout(),this.completionPromise||(this.completionPromise=new Promise(i=>{this.onSuccess=i}).then(()=>{this.completionPromise=void 0,this.onSuccess=void 0;let i=this.task();return this.task=void 0,i})),(t>=0||this.timeout===void 0)&&(this.timeout=(0,JP.RAL)().timer.setTimeout(()=>{this.timeout=void 0,this.onSuccess(void 0)},t>=0?t:this.defaultDelay)),this.completionPromise}forceDelivery(){if(!this.completionPromise)return;this.cancelTimeout();let e=this.task();return this.completionPromise=void 0,this.onSuccess=void 0,this.task=void 0,e}isTriggered(){return this.timeout!==void 0}cancel(){this.cancelTimeout(),this.completionPromise=void 0}dispose(){this.cancelTimeout()}cancelTimeout(){this.timeout!==void 0&&((0,JP.RAL)().timer.clearTimeout(this.timeout),this.timeout=void 0)}}});function IG(n){return{uri:n.uri,languageId:n.languageId,version:n.version,text:n.getText()}}function jG(n){return{textDocument:{uri:n.uri}}}function AG(n){return{textDocument:{uri:n.uri,version:n.version},contentChanges:[{text:n.getText()}]}}function XP(n){return{textDocument:vw(n.document),reason:n.reason}}function vw(n){return{uri:n.uri,version:n.version}}function OG(n,e){let t={textDocument:vw(n)};return e&&(t.text=n.getText()),t}function qf(n){return n.toString()}function MG(n,e,t){return{textDocument:{uri:n.uri},position:e,context:zi(t,["option"])}}function wn(n,e){return{textDocument:{uri:n.uri},position:e}}function NG(n,e,t){return{textDocument:Xl(n),position:e,context:t}}function Xl(n){return{uri:n.uri}}function BG(n,e,t){return{textDocument:{uri:n.uri},position:e,context:{includeDeclaration:t.includeDeclaration}}}function HG(n){return{textDocument:{uri:n.uri}}}function qG(n){return{textDocument:{uri:n.uri}}}var _a=_(()=>{"use strict";Vo()});function qe(){return re()}var ww=_(()=>{"use strict";Oe()});function WSe(n,e,t,i,r){let o=new WG,s=(0,x.createProtocolConnection)(n,e,o,r),a=[];return s.onError(u=>{t(u[0],u[1],u[2])},null,a),s.onClose(i,null,a),{listen:()=>s.listen(),unlisten:()=>{Z(a)},sendRequest:(u,...c)=>s.sendRequest(Ee(u)?u:u.method,...c),onRequest:(u,c)=>s.onRequest(Ee(u)?u:u.method,c),sendNotification:(u,c)=>s.sendNotification(Ee(u)?u:u.method,c),onNotification:(u,c)=>s.onNotification(Ee(u)?u:u.method,c),onProgress:s.onProgress,sendProgress:s.sendProgress,trace:(u,c,h)=>{let d={sendNotification:!1,traceFormat:x.TraceFormat.Text};h===void 0?s.trace(u,c,d):(Kn(h),s.trace(u,c,h))},initialize:u=>s.sendRequest(x.InitializeRequest.type,u),shutdown:()=>s.sendRequest(x.ShutdownRequest.type,void 0),exit:()=>s.sendNotification(x.ExitNotification.type),onLogMessage:u=>s.onNotification(x.LogMessageNotification.type,u),onShowMessage:u=>s.onNotification(x.ShowMessageNotification.type,u),onTelemetry:u=>s.onNotification(x.TelemetryEventNotification.type,u),didChangeConfiguration:u=>s.sendNotification(x.DidChangeConfigurationNotification.type,u),didChangeWatchedFiles:u=>s.sendNotification(x.DidChangeWatchedFilesNotification.type,u),didOpenTextDocument:u=>s.sendNotification(x.DidOpenTextDocumentNotification.type,u),didChangeTextDocument:u=>s.sendNotification(x.DidChangeTextDocumentNotification.type,u),didCloseTextDocument:u=>s.sendNotification(x.DidCloseTextDocumentNotification.type,u),didSaveTextDocument:u=>s.sendNotification(x.DidSaveTextDocumentNotification.type,u),onDiagnostics:u=>s.onNotification(x.PublishDiagnosticsNotification.type,u),end:()=>s.end(),dispose:()=>s.dispose()}}function U(n,e){return n[e]===void 0&&(n[e]={}),n[e]}var GP,x,YG,go,WG,zP,VP,e_,ZG,Dw,xw,Cw,JG,ZSe,$G,QP,fo,XG,UG,GG,QG,KG,zG,VG,Me,e6,t6,i6,n6,r6,o6,s6,a6,l6,u6,c6,h6,d6,g6,f6,p6,m6,b6,mh,KP,t_,Dn=_(()=>{"use strict";GP=C(require("path")),x=C(H());we();wi();Ce();Je();In();Vo();Ob();ke();V();Ul();ZP();FG();YG=C(require("os"));_a();ww();yt();z();go=q()("language-client-client"),WG=class{error(e){go.error(e)}warn(e){go.warn(e)}info(e){go.info(e)}log(e){go.log(e)}},zP=class{error(e){}warn(e){}info(e){}log(e){}};VP=(t=>(t[t.Continue=1]="Continue",t[t.Shutdown=2]="Shutdown",t))(VP||{}),e_=(t=>(t[t.DoNotRestart=1]="DoNotRestart",t[t.Restart=2]="Restart",t))(e_||{}),ZG=class{constructor(e,t){this.name=e;this.maxRestartCount=t;this.restarts=[]}error(e,t,i){return i&&i<=3?1:2}closed(){return this.restarts.push(Date.now()),this.restarts.length(r[r.Info=1]="Info",r[r.Warn=2]="Warn",r[r.Error=3]="Error",r[r.Never=4]="Never",r))(Dw||{}),xw=(i=>(i[i.Stopped=1]="Stopped",i[i.Running=2]="Running",i[i.Starting=3]="Starting",i))(xw||{}),Cw=(s=>(s[s.Initial=0]="Initial",s[s.Starting=1]="Starting",s[s.StartFailed=2]="StartFailed",s[s.Running=3]="Running",s[s.Stopping=4]="Stopping",s[s.Stopped=5]="Stopped",s))(Cw||{}),JG=[x.SymbolKind.File,x.SymbolKind.Module,x.SymbolKind.Namespace,x.SymbolKind.Package,x.SymbolKind.Class,x.SymbolKind.Method,x.SymbolKind.Property,x.SymbolKind.Field,x.SymbolKind.Constructor,x.SymbolKind.Enum,x.SymbolKind.Interface,x.SymbolKind.Function,x.SymbolKind.Variable,x.SymbolKind.Constant,x.SymbolKind.String,x.SymbolKind.Number,x.SymbolKind.Boolean,x.SymbolKind.Array,x.SymbolKind.Object,x.SymbolKind.Key,x.SymbolKind.Null,x.SymbolKind.EnumMember,x.SymbolKind.Struct,x.SymbolKind.Event,x.SymbolKind.Operator,x.SymbolKind.TypeParameter],ZSe=[x.CompletionItemKind.Text,x.CompletionItemKind.Method,x.CompletionItemKind.Function,x.CompletionItemKind.Constructor,x.CompletionItemKind.Field,x.CompletionItemKind.Variable,x.CompletionItemKind.Class,x.CompletionItemKind.Interface,x.CompletionItemKind.Module,x.CompletionItemKind.Property,x.CompletionItemKind.Unit,x.CompletionItemKind.Value,x.CompletionItemKind.Enum,x.CompletionItemKind.Keyword,x.CompletionItemKind.Snippet,x.CompletionItemKind.Color,x.CompletionItemKind.File,x.CompletionItemKind.Reference,x.CompletionItemKind.Folder,x.CompletionItemKind.EnumMember,x.CompletionItemKind.Constant,x.CompletionItemKind.Struct,x.CompletionItemKind.Event,x.CompletionItemKind.Operator,x.CompletionItemKind.TypeParameter],$G=[x.SymbolTag.Deprecated];(e=>{function n(t){let i=t;return i&&Qs(i.register)&&Qs(i.unregister)&&Qs(i.dispose)&&i.registrationType!==void 0}e.is=n})(QP||(QP={}));fo=class{constructor(e,t,i,r,o,s){this._client=e;this._event=t;this._type=i;this._middleware=r;this._createParams=o;this._selectorFilter=s;this._selectors=new Map}static textDocumentFilter(e,t){for(let i of e)if(y.match(i,t)>0)return!0;return!1}register(e){!e.registerOptions.documentSelector||(this._listener||(this._listener=this._event(this.callback,this)),this._selectors.set(e.id,e.registerOptions.documentSelector))}callback(e){(!this._selectorFilter||this._selectorFilter(this._selectors.values(),e))&&(this._middleware?this._middleware(e,t=>this._client.sendNotification(this._type,this._createParams(t))):this._client.sendNotification(this._type,this._createParams(e)),this.notificationSent(e))}notificationSent(e){}unregister(e){this._selectors.delete(e),this._selectors.size===0&&this._listener&&(this._listener.dispose(),this._listener=void 0)}dispose(){this._selectors.clear(),this._listener&&(this._listener.dispose(),this._listener=void 0)}getProvider(e){for(let t of this._selectors.values())if(y.match(t,e))return{send:i=>{this.callback(i)}}}},XG=class extends fo{constructor(e,t){super(e,y.onDidOpenTextDocument,x.DidOpenTextDocumentNotification.type,e.clientOptions.middleware.didOpen,i=>({textDocument:IG(i)}),fo.textDocumentFilter);this._syncedDocuments=t}get registrationType(){return x.DidOpenTextDocumentNotification.type}fillClientCapabilities(e){U(U(e,"textDocument"),"synchronization").dynamicRegistration=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;t&&i&&i.openClose&&this.register({id:qe(),registerOptions:{documentSelector:t}})}register(e){if(super.register(e),!e.registerOptions.documentSelector)return;let t=e.registerOptions.documentSelector;y.textDocuments.forEach(i=>{let r=i.uri.toString();if(!this._syncedDocuments.has(r)&&y.match(t,i)>0){let o=this._client.clientOptions.middleware,s=a=>{this._client.sendNotification(this._type,this._createParams(a))};o.didOpen?o.didOpen(i,s):s(i),this._syncedDocuments.set(r,i)}})}notificationSent(e){super.notificationSent(e),this._syncedDocuments.set(e.uri.toString(),e)}},UG=class extends fo{constructor(e,t){super(e,y.onDidCloseTextDocument,x.DidCloseTextDocumentNotification.type,e.clientOptions.middleware.didClose,i=>jG(i),fo.textDocumentFilter);this._syncedDocuments=t}get registrationType(){return x.DidCloseTextDocumentNotification.type}fillClientCapabilities(e){U(U(e,"textDocument"),"synchronization").dynamicRegistration=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;t&&i&&i.openClose&&this.register({id:qe(),registerOptions:{documentSelector:t}})}notificationSent(e){super.notificationSent(e),this._syncedDocuments.delete(e.uri.toString())}unregister(e){let t=this._selectors.get(e);super.unregister(e);let i=this._selectors.values();this._syncedDocuments.forEach(r=>{if(y.match(t,r)>0&&!this._selectorFilter(i,r)){let o=this._client.clientOptions.middleware,s=a=>{this._client.sendNotification(this._type,this._createParams(a))};this._syncedDocuments.delete(r.uri.toString()),o.didClose?o.didClose(r,s):s(r)}})}},GG=class{constructor(e){this._client=e;this._changeData=new Map}get registrationType(){return x.DidChangeTextDocumentNotification.type}fillClientCapabilities(e){U(U(e,"textDocument"),"synchronization").dynamicRegistration=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;t&&i&&i.change!==void 0&&i.change!==x.TextDocumentSyncKind.None&&this.register({id:qe(),registerOptions:Object.assign({},{documentSelector:t},{syncKind:i.change})})}register(e){!e.registerOptions.documentSelector||(this._listener||(this._listener=y.onDidChangeTextDocument(t=>{this.callback({textDocument:t.textDocument,contentChanges:t.contentChanges.slice()})},this)),this._changeData.set(e.id,{documentSelector:e.registerOptions.documentSelector,syncKind:e.registerOptions.syncKind}))}callback(e){if(e.contentChanges.length===0)return;let t=y.getDocument(e.textDocument.uri);if(!t)return;let{textDocument:i}=t;for(let r of this._changeData.values())if(y.match(r.documentSelector,i)>0){let o=this._client.clientOptions.middleware;if(r.syncKind===x.TextDocumentSyncKind.Incremental){let s=a=>{this._client.sendNotification(x.DidChangeTextDocumentNotification.type,zi(a,["bufnr","original","originalLines"]))};o.didChange?o.didChange(e,s):s(e)}else if(r.syncKind===x.TextDocumentSyncKind.Full){let s=()=>{this._client.sendNotification(x.DidChangeTextDocumentNotification.type,AG(i))};o.didChange?o.didChange(e,s):s(e)}}}unregister(e){this._changeData.delete(e),this._changeData.size===0&&this._listener&&(this._listener.dispose(),this._listener=void 0)}dispose(){this._changeData.clear(),this._listener&&(this._listener.dispose(),this._listener=void 0)}getProvider(e){for(let t of this._changeData.values())if(y.match(t.documentSelector,e))return{send:i=>{this.callback(i)}}}},QG=class extends fo{constructor(e){super(e,y.onWillSaveTextDocument,x.WillSaveTextDocumentNotification.type,e.clientOptions.middleware.willSave,t=>XP(t),(t,i)=>fo.textDocumentFilter(t,i.document))}get registrationType(){return x.WillSaveTextDocumentNotification.type}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"synchronization");t.willSave=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;t&&i&&i.willSave&&this.register({id:qe(),registerOptions:{documentSelector:t}})}},KG=class{constructor(e){this._client=e;this._selectors=new Map}get registrationType(){return x.WillSaveTextDocumentWaitUntilRequest.type}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"synchronization");t.willSaveWaitUntil=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;t&&i&&i.willSaveWaitUntil&&this.register({id:qe(),registerOptions:{documentSelector:t}})}register(e){!e.registerOptions.documentSelector||(this._listener||(this._listener=y.onWillSaveTextDocument(this.callback,this)),this._selectors.set(e.id,e.registerOptions.documentSelector))}callback(e){if(fo.textDocumentFilter(this._selectors.values(),e.document)){let t=this._client.clientOptions.middleware,i=r=>this._client.sendRequest(x.WillSaveTextDocumentWaitUntilRequest.type,XP(r)).then(o=>o||[],o=>(k.showMessage(`Error on willSaveWaitUntil: ${o}`,"error"),go.error(o),[]));e.waitUntil(t.willSaveWaitUntil?t.willSaveWaitUntil(e,i):i(e))}}unregister(e){this._selectors.delete(e),this._selectors.size===0&&this._listener&&(this._listener.dispose(),this._listener=void 0)}dispose(){this._selectors.clear(),this._listener&&(this._listener.dispose(),this._listener=void 0)}},zG=class extends fo{constructor(e){super(e,y.onDidSaveTextDocument,x.DidSaveTextDocumentNotification.type,e.clientOptions.middleware.didSave,t=>OG(t,this._includeText),fo.textDocumentFilter);this._includeText=!1}get registrationType(){return x.DidSaveTextDocumentNotification.type}fillClientCapabilities(e){U(U(e,"textDocument"),"synchronization").didSave=!0}initialize(e,t){let i=e.resolvedTextDocumentSync;if(t&&i&&i.save){let r=typeof i.save=="boolean"?{includeText:!1}:{includeText:!!i.save.includeText};this.register({id:qe(),registerOptions:Object.assign({},{documentSelector:t},r)})}}register(e){this._includeText=!!e.registerOptions.includeText,super.register(e)}},VG=class{constructor(e,t){this._notifyFileEvent=t;this._watchers=new Map}get registrationType(){return x.DidChangeWatchedFilesNotification.type}fillClientCapabilities(e){U(U(e,"workspace"),"didChangeWatchedFiles").dynamicRegistration=!0}initialize(e,t){}register(e){if(!Array.isArray(e.registerOptions.watchers))return;let t=[];for(let i of e.registerOptions.watchers){if(!Ee(i.globPattern))continue;let r=!0,o=!0,s=!0;i.kind!=null&&(r=(i.kind&x.WatchKind.Create)!==0,o=(i.kind&x.WatchKind.Change)!=0,s=(i.kind&x.WatchKind.Delete)!=0);let a=y.createFileSystemWatcher(i.globPattern,!r,!o,!s);this.hookListeners(a,r,o,s,t),t.push(a)}this._watchers.set(e.id,t)}registerRaw(e,t){let i=[];for(let r of t)i.push(r),this.hookListeners(r,!0,!0,!0,i);this._watchers.set(e,i)}hookListeners(e,t,i,r,o){t&&e.onDidCreate(s=>this._notifyFileEvent({uri:qf(s),type:x.FileChangeType.Created}),null,o),i&&e.onDidChange(s=>this._notifyFileEvent({uri:qf(s),type:x.FileChangeType.Changed}),null,o),r&&e.onDidDelete(s=>this._notifyFileEvent({uri:qf(s),type:x.FileChangeType.Deleted}),null,o)}unregister(e){let t=this._watchers.get(e);if(t)for(let i of t)i.dispose()}dispose(){this._watchers.forEach(e=>{for(let t of e)t.dispose()}),this._watchers.clear()}},Me=class{constructor(e,t){this._client=e;this._registrationType=t;this._registrations=new Map}get registrationType(){return this._registrationType}register(e){if(!e.registerOptions.documentSelector)return;let t=this.registerLanguageProvider(e.registerOptions);this._registrations.set(e.id,{disposable:t[0],data:e,provider:t[1]})}unregister(e){let t=this._registrations.get(e);t&&t.disposable.dispose()}dispose(){this._registrations.forEach(e=>{e.disposable.dispose()}),this._registrations.clear()}getRegistration(e,t){if(t){if(x.TextDocumentRegistrationOptions.is(t)){let i=x.StaticRegistrationOptions.hasId(t)?t.id:qe(),r=t.documentSelector||e;if(r)return[i,Object.assign({},t,{documentSelector:r})]}else if(Kn(t)&&t===!0||x.WorkDoneProgressOptions.is(t)){if(!e)return[void 0,void 0];let i=Kn(t)&&t===!0?{documentSelector:e}:Object.assign({},t,{documentSelector:e});return[qe(),i]}}else return[void 0,void 0];return[void 0,void 0]}getRegistrationOptions(e,t){if(!(!e||!t))return Kn(t)&&t===!0?{documentSelector:e}:Object.assign({},t,{documentSelector:e})}getProvider(e){for(let t of this._registrations.values()){let i=t.data.registerOptions.documentSelector;if(i!==null&&y.match(i,e)>0)return t.provider}}getAllProviders(){let e=[];for(let t of this._registrations.values())e.push(t.provider);return e}},e6=class{constructor(e,t){this._client=e;this._registrationType=t;this._registrations=new Map}get registrationType(){return this._registrationType}register(e){let t=this.registerLanguageProvider(e.registerOptions);this._registrations.set(e.id,{disposable:t[0],provider:t[1]})}unregister(e){let t=this._registrations.get(e);t&&t.disposable.dispose()}dispose(){this._registrations.forEach(e=>{e.disposable.dispose()}),this._registrations.clear()}getProviders(){let e=[];for(let t of this._registrations.values())e.push(t.provider);return e}},t6=class extends Me{constructor(e){super(e,x.CompletionRequest.type)}fillClientCapabilities(e){let t=this._client.clientOptions.disableSnippetCompletion!==!0,i=U(U(e,"textDocument"),"completion");i.dynamicRegistration=!0,i.contextSupport=!0,i.completionItem={snippetSupport:t,commitCharactersSupport:!0,documentationFormat:this._client.supportedMarkupKind,deprecatedSupport:!0,preselectSupport:!0,insertReplaceSupport:!0,tagSupport:{valueSet:[x.CompletionItemTag.Deprecated]},resolveSupport:{properties:["documentation","detail","additionalTextEdits"]},insertTextModeSupport:{valueSet:[x.InsertTextMode.asIs,x.InsertTextMode.adjustIndentation]}},i.completionItemKind={valueSet:ZSe},i.insertTextMode=x.InsertTextMode.adjustIndentation}initialize(e,t){this.index=0;let i=this.getRegistrationOptions(t,e.completionProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t=e.triggerCharacters||[],i=e.allCommitCharacters||[],r=e.priority,o={provideCompletionItems:(l,u,c,h)=>{let d=this._client,g=this._client.clientOptions.middleware,f=(p,b,v,w)=>d.sendRequest(x.CompletionRequest.type,MG(p,b,v),w).then(D=>D!=null?D:[],D=>d.handleFailedRequest(x.CompletionRequest.type,w,D,[]));return g.provideCompletionItem?g.provideCompletionItem(l,u,h,c,f):f(l,u,h,c)},resolveCompletionItem:e.resolveProvider?(l,u)=>{let c=this._client,h=this._client.clientOptions.middleware,d=(g,f)=>c.sendRequest(x.CompletionResolveRequest.type,g,f).then(p=>p,p=>c.handleFailedRequest(x.CompletionResolveRequest.type,f,p,g));return h.resolveCompletionItem?h.resolveCompletionItem(l,u,d):d(l,u)}:void 0},s=this._client.id+(this.index?"-"+this.index:"");Lt.removeSource(s);let a=A.registerCompletionItemProvider(s,"LS",e.documentSelector||this._client.clientOptions.documentSelector,o,t,r,i);return this.index=this.index+1,[a,o]}},i6=class extends Me{constructor(e){super(e,x.HoverRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"hover");t.dynamicRegistration=!0,t.contentFormat=this._client.supportedMarkupKind}initialize(e,t){let i=this.getRegistrationOptions(t,e.hoverProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideHover:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(x.HoverRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(x.HoverRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideHover?l.provideHover(i,r,o,a):a(i,r,o)}};return[A.registerHoverProvider(e.documentSelector,t),t]}},n6=class extends Me{constructor(e){super(e,x.SignatureHelpRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"signatureHelp");t.dynamicRegistration=!0,t.contextSupport=!0,t.signatureInformation={documentationFormat:this._client.supportedMarkupKind,activeParameterSupport:!0,parameterInformation:{labelOffsetSupport:!0}}}initialize(e,t){let i=this.getRegistrationOptions(t,e.signatureHelpProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideSignatureHelp:(o,s,a,l)=>{let u=this._client,c=(d,g,f,p)=>u.sendRequest(x.SignatureHelpRequest.type,NG(d,g,f),p).then(b=>b,b=>u.handleFailedRequest(x.SignatureHelpRequest.type,p,b,null)),h=u.clientOptions.middleware;return h.provideSignatureHelp?h.provideSignatureHelp(o,s,l,a,c):c(o,s,l,a)}},i=e.triggerCharacters||[];return[A.registerSignatureHelpProvider(e.documentSelector,t,i),t]}},r6=class extends Me{constructor(e){super(e,x.DefinitionRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"definition");t.dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.definitionProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDefinition:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(x.DefinitionRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(x.DefinitionRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideDefinition?l.provideDefinition(i,r,o,a):a(i,r,o)}};return[A.registerDefinitionProvider(e.documentSelector,t),t]}},o6=class extends Me{constructor(e){super(e,x.ReferencesRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"references").dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.referencesProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideReferences:(i,r,o,s)=>{let a=this._client,l=(c,h,d,g)=>a.sendRequest(x.ReferencesRequest.type,BG(c,h,d),g).then(f=>f,f=>a.handleFailedRequest(x.ReferencesRequest.type,g,f,null)),u=a.clientOptions.middleware;return u.provideReferences?u.provideReferences(i,r,o,s,l):l(i,r,o,s)}};return[A.registerReferencesProvider(e.documentSelector,t),t]}},s6=class extends Me{constructor(e){super(e,x.DocumentHighlightRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"documentHighlight").dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentHighlightProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDocumentHighlights:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(x.DocumentHighlightRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(x.DocumentHighlightRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideDocumentHighlights?l.provideDocumentHighlights(i,r,o,a):a(i,r,o)}};return[A.registerDocumentHighlightProvider(e.documentSelector,t),t]}},a6=class extends Me{constructor(e){super(e,x.DocumentSymbolRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"documentSymbol");t.dynamicRegistration=!0,t.symbolKind={valueSet:JG},t.hierarchicalDocumentSymbolSupport=!0,t.tagSupport={valueSet:$G},t.labelSupport=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentSymbolProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDocumentSymbols:(r,o)=>{let s=this._client,a=(u,c)=>s.sendRequest(x.DocumentSymbolRequest.type,HG(u),c).then(h=>{if(h!==null){if(h.length===0)return[];{let d=h[0];return x.DocumentSymbol.is(d),h}}},h=>s.handleFailedRequest(x.DocumentSymbolRequest.type,c,h,null)),l=s.clientOptions.middleware;return l.provideDocumentSymbols?l.provideDocumentSymbols(r,o,a):a(r,o)}},i=e.label?{label:e.label}:void 0;return[A.registerDocumentSymbolProvider(e.documentSelector,t,i),t]}},l6=class extends e6{constructor(e){super(e,x.WorkspaceSymbolRequest.type)}fillClientCapabilities(e){let t=U(U(e,"workspace"),"symbol");t.dynamicRegistration=!0,t.symbolKind={valueSet:JG},t.tagSupport={valueSet:$G}}initialize(e){!e.workspaceSymbolProvider||this.register({id:qe(),registerOptions:e.workspaceSymbolProvider===!0?{workDoneProgress:!1}:e.workspaceSymbolProvider})}registerLanguageProvider(e){let t={provideWorkspaceSymbols:(i,r)=>{let o=this._client,s=(l,u)=>o.sendRequest(x.WorkspaceSymbolRequest.type,{query:l},u).then(c=>c,c=>o.handleFailedRequest(x.WorkspaceSymbolRequest.type,u,c,null)),a=o.clientOptions.middleware;return a.provideWorkspaceSymbols?a.provideWorkspaceSymbols(i,r,s):s(i,r)}};return[A.registerWorkspaceSymbolProvider(t),t]}},u6=class extends Me{constructor(e){super(e,x.CodeActionRequest.type);this.disposables=[]}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"codeAction");t.dynamicRegistration=!0,t.isPreferredSupport=!0,t.disabledSupport=!0,t.dataSupport=!0,t.honorsChangeAnnotations=!1,t.resolveSupport={properties:["edit"]},t.codeActionLiteralSupport={codeActionKind:{valueSet:[x.CodeActionKind.Empty,x.CodeActionKind.QuickFix,x.CodeActionKind.Refactor,x.CodeActionKind.RefactorExtract,x.CodeActionKind.RefactorInline,x.CodeActionKind.RefactorRewrite,x.CodeActionKind.Source,x.CodeActionKind.SourceOrganizeImports]}}}initialize(e,t){let i=this.getRegistrationOptions(t,e.codeActionProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t=r=>{if(oe.has(r))return;let o=this._client,s=(l,u)=>{let c={command:l,arguments:u};return o.sendRequest(x.ExecuteCommandRequest.type,c).then(void 0,h=>{throw o.handleFailedRequest(x.ExecuteCommandRequest.type,void 0,h,void 0),h})},a=o.clientOptions.middleware;this.disposables.push(oe.registerCommand(r,(...l)=>a.executeCommand?a.executeCommand(r,l,s):s(r,l),null,!0))},i={provideCodeActions:(r,o,s,a)=>{let l=this._client,u=(h,d,g,f)=>{let p={textDocument:{uri:h.uri},range:d,context:g};return l.sendRequest(x.CodeActionRequest.type,p,f).then(b=>{if(b!==null)return b.forEach(v=>{var D;let w=x.Command.is(v)?v.command:(D=v.command)==null?void 0:D.command;w&&!oe.has(w)&&t(w)}),b},b=>l.handleFailedRequest(x.CodeActionRequest.type,f,b,null))},c=l.clientOptions.middleware;return c.provideCodeActions?c.provideCodeActions(r,o,s,a,u):u(r,o,s,a)},resolveCodeAction:e.resolveProvider?(r,o)=>{let s=this._client,a=this._client.clientOptions.middleware,l=(u,c)=>s.sendRequest(x.CodeActionResolveRequest.type,u,c).then(h=>h,h=>s.handleFailedRequest(x.CodeActionResolveRequest.type,c,h,u));return a.resolveCodeAction?a.resolveCodeAction(r,o,l):l(r,o)}:void 0};return[A.registerCodeActionProvider(e.documentSelector,i,this._client.id,e.codeActionKinds),i]}dispose(){this.disposables.forEach(e=>{e.dispose()}),this.disposables=[],super.dispose()}},c6=class extends Me{constructor(e){super(e,x.CodeLensRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"codeLens").dynamicRegistration=!0,U(U(e,"workspace"),"codeLens").refreshSupport=!0}initialize(e,t){this._client.onRequest(x.CodeLensRefreshRequest.type,async()=>{for(let o of this.getAllProviders())o.onDidChangeCodeLensEmitter.fire()});let r=this.getRegistrationOptions(t,e.codeLensProvider);!r||this.register({id:qe(),registerOptions:r})}registerLanguageProvider(e){let t=new x.Emitter,i={onDidChangeCodeLenses:t.event,provideCodeLenses:(r,o)=>{let s=this._client,a=(u,c)=>s.sendRequest(x.CodeLensRequest.type,qG(u),c).then(h=>h,h=>s.handleFailedRequest(x.CodeLensRequest.type,c,h,null)),l=s.clientOptions.middleware;return l.provideCodeLenses?l.provideCodeLenses(r,o,a):a(r,o)},resolveCodeLens:e.resolveProvider?(r,o)=>{let s=this._client,a=(u,c)=>s.sendRequest(x.CodeLensResolveRequest.type,u,c).then(h=>h,h=>s.handleFailedRequest(x.CodeLensResolveRequest.type,c,h,u)),l=s.clientOptions.middleware;return l.resolveCodeLens?l.resolveCodeLens(r,o,a):a(r,o)}:void 0};return[A.registerCodeLensProvider(e.documentSelector,i),{provider:i,onDidChangeCodeLensEmitter:t}]}},h6=class extends Me{constructor(e){super(e,x.DocumentFormattingRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"formatting").dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentFormattingProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDocumentFormattingEdits:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d={textDocument:{uri:u.uri},options:c};return s.sendRequest(x.DocumentFormattingRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(x.DocumentFormattingRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.provideDocumentFormattingEdits?l.provideDocumentFormattingEdits(i,r,o,a):a(i,r,o)}};return[A.registerDocumentFormatProvider(e.documentSelector,t,this._client.clientOptions.formatterPriority),t]}},d6=class extends Me{constructor(e){super(e,x.DocumentRangeFormattingRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"rangeFormatting").dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentRangeFormattingProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDocumentRangeFormattingEdits:(i,r,o,s)=>{let a=this._client,l=(c,h,d,g)=>{let f={textDocument:{uri:c.uri},range:h,options:d};return a.sendRequest(x.DocumentRangeFormattingRequest.type,f,g).then(p=>p,p=>a.handleFailedRequest(x.DocumentRangeFormattingRequest.type,g,p,null))},u=a.clientOptions.middleware;return u.provideDocumentRangeFormattingEdits?u.provideDocumentRangeFormattingEdits(i,r,o,s,l):l(i,r,o,s)}};return[A.registerDocumentRangeFormatProvider(e.documentSelector,t),t]}},g6=class extends Me{constructor(e){super(e,x.DocumentOnTypeFormattingRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"onTypeFormatting").dynamicRegistration=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentOnTypeFormattingProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideOnTypeFormattingEdits:(o,s,a,l,u)=>{let c=this._client,h=(g,f,p,b,v)=>{let w={textDocument:vw(g),position:f,ch:p,options:b};return c.sendRequest(x.DocumentOnTypeFormattingRequest.type,w,v).then(D=>D,D=>c.handleFailedRequest(x.DocumentOnTypeFormattingRequest.type,v,D,null))},d=c.clientOptions.middleware;return d.provideOnTypeFormattingEdits?d.provideOnTypeFormattingEdits(o,s,a,l,u,h):h(o,s,a,l,u)}},i=e.moreTriggerCharacter||[],r=[e.firstTriggerCharacter,...i];return[A.registerOnTypeFormattingEditProvider(e.documentSelector,t,r),t]}},f6=class extends Me{constructor(e){super(e,x.RenameRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"rename");t.dynamicRegistration=!0,t.prepareSupport=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.renameProvider);!i||(Kn(e.renameProvider)&&(i.prepareProvider=!1),this.register({id:qe(),registerOptions:i}))}registerLanguageProvider(e){let t={provideRenameEdits:(i,r,o,s)=>{let a=this._client,l=(c,h,d,g)=>{let f={textDocument:{uri:c.uri},position:h,newName:d};return a.sendRequest(x.RenameRequest.type,f,g).then(p=>p,p=>a.handleFailedRequest(x.RenameRequest.type,g,p,null))},u=a.clientOptions.middleware;return u.provideRenameEdits?u.provideRenameEdits(i,r,o,s,l):l(i,r,o,s)},prepareRename:e.prepareProvider?(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d={textDocument:Xl(u),position:c};return s.sendRequest(x.PrepareRenameRequest.type,d,h).then(g=>x.Range.is(g)?g:this.isDefaultBehavior(g)?g.defaultBehavior===!0?null:Promise.reject(new Error("The element can't be renamed.")):g&&x.Range.is(g.range)?{range:g.range,placeholder:g.placeholder}:Promise.reject(new Error("The element can't be renamed.")),g=>s.handleFailedRequest(x.PrepareRenameRequest.type,h,g,void 0))},l=s.clientOptions.middleware;return l.prepareRename?l.prepareRename(i,r,o,a):a(i,r,o)}:void 0};return[A.registerRenameProvider(e.documentSelector,t),t]}isDefaultBehavior(e){let t=e;return t&&Kn(t.defaultBehavior)}},p6=class extends Me{constructor(e){super(e,x.DocumentLinkRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"documentLink");t.dynamicRegistration=!0,t.tooltipSupport=!0}initialize(e,t){let i=this.getRegistrationOptions(t,e.documentLinkProvider);!i||this.register({id:qe(),registerOptions:i})}registerLanguageProvider(e){let t={provideDocumentLinks:(i,r)=>{let o=this._client,s=(l,u)=>o.sendRequest(x.DocumentLinkRequest.type,{textDocument:{uri:l.uri}},u).then(c=>c,c=>o.handleFailedRequest(x.DocumentLinkRequest.type,u,c,null)),a=o.clientOptions.middleware;return a.provideDocumentLinks?a.provideDocumentLinks(i,r,s):s(i,r)},resolveDocumentLink:e.resolveProvider?(i,r)=>{let o=this._client,s=(l,u)=>o.sendRequest(x.DocumentLinkResolveRequest.type,l,u).then(c=>c,c=>o.handleFailedRequest(x.DocumentLinkResolveRequest.type,u,c,l)),a=o.clientOptions.middleware;return a.resolveDocumentLink?a.resolveDocumentLink(i,r,s):s(i,r)}:void 0};return[A.registerDocumentLinkProvider(e.documentSelector,t),t]}},m6=class{constructor(e){this._client=e;this._listeners=new Map}get registrationType(){return x.DidChangeConfigurationNotification.type}fillClientCapabilities(e){U(U(e,"workspace"),"didChangeConfiguration").dynamicRegistration=!0}initialize(){var t;let e=(t=this._client.clientOptions.synchronize)==null?void 0:t.configurationSection;e!==void 0&&this.register({id:qe(),registerOptions:{section:e}})}register(e){let{section:t}=e.registerOptions,i=y.onDidChangeConfiguration(r=>{this.onDidChangeConfiguration(e.registerOptions.section,r)});this._listeners.set(e.id,i),t!=null&&this.onDidChangeConfiguration(t,void 0)}unregister(e){let t=this._listeners.get(e);t&&(this._listeners.delete(e),t.dispose())}dispose(){for(let e of this._listeners.values())e.dispose();this._listeners.clear()}onDidChangeConfiguration(e,t){let i=typeof e=="string"&&e.startsWith("languageserver."),r;if(Ee(e)?r=[e]:r=e,r!=null&&t!=null&&!r.some(l=>t.affectsConfiguration(l)))return;let o=a=>{if(a==null){this._client.sendNotification(x.DidChangeConfigurationNotification.type,{settings:null});return}this._client.sendNotification(x.DidChangeConfigurationNotification.type,{settings:i?this.getConfiguredSettings(a[0]):this.extractSettingsInformation(a)})},s=this.getMiddleware();s?s(r,o):o(r)}getConfiguredSettings(e){let t=9,i=y.getConfiguration(e.slice(0,-t));return aY(i.get("settings",{}))}extractSettingsInformation(e){function t(r,o){let s=r;for(let a=0;a=0?a=y.getConfiguration(o.substr(0,s)).get(o.substr(s+1)):a=y.getConfiguration(o),a){let l=e[r].split(".");t(i,l)[l[l.length-1]]=a}}return i}getMiddleware(){let e=this._client.clientOptions.middleware;if(e.workspace&&e.workspace.didChangeConfiguration)return e.workspace.didChangeConfiguration}},b6=class{constructor(e){this._client=e;this._commands=new Map}get registrationType(){return x.ExecuteCommandRequest.type}fillClientCapabilities(e){U(U(e,"workspace"),"executeCommand").dynamicRegistration=!0}initialize(e){!e.executeCommandProvider||this.register({id:qe(),registerOptions:Object.assign({},e.executeCommandProvider)})}register(e){let t=this._client,i=t.clientOptions.middleware,r=(o,s)=>{let a={command:o,arguments:s};return t.sendRequest(x.ExecuteCommandRequest.type,a).then(void 0,l=>{throw t.handleFailedRequest(x.ExecuteCommandRequest.type,void 0,l,void 0),l})};if(e.registerOptions.commands){let o=[];for(let s of e.registerOptions.commands)o.push(oe.registerCommand(s,(...a)=>i.executeCommand?i.executeCommand(s,a,r):r(s,a),null,!0));this._commands.set(e.id,o)}}unregister(e){let t=this._commands.get(e);t&&t.forEach(i=>i.dispose())}dispose(){this._commands.forEach(e=>{e.forEach(t=>t.dispose())}),this._commands.clear()}};(e=>{function n(t){return t&&x.MessageReader.is(t.reader)&&x.MessageWriter.is(t.writer)}e.is=n})(mh||(mh={}));KP=class{constructor(e,t){this._resolve=e;this._reject=t;this._used=!1}get isUsed(){return this._used}resolve(){this._used=!0,this._resolve()}reject(e){this._used=!0,this._reject(e)}},t_=class{constructor(e,t,i){this._features=[];this._dynamicFeatures=new Map;var l;this._id=e,this._name=t,i.outputChannel?this._outputChannel=i.outputChannel:this._outputChannel=void 0;let r=!1;(y.getConfiguration("suggest").get("snippetsSupport",!0)===!1||i.disableSnippetCompletion)&&(r=!0);let s={isTrusted:!1,supportHtml:!1};i.markdown!=null&&(s.isTrusted=i.markdown.isTrusted===!0,s.supportHtml=i.markdown.supportHtml===!0),this._clientOptions={disableSnippetCompletion:r,disableDynamicRegister:i.disableDynamicRegister,disabledFeatures:i.disabledFeatures||[],formatterPriority:i.formatterPriority,ignoredRootPaths:i.ignoredRootPaths,documentSelector:i.documentSelector||[],synchronize:i.synchronize||{},diagnosticCollectionName:i.diagnosticCollectionName,outputChannelName:i.outputChannelName||this._id,revealOutputChannelOn:i.revealOutputChannelOn||4,stdioEncoding:i.stdioEncoding||"utf8",initializationOptions:i.initializationOptions,initializationFailedHandler:i.initializationFailedHandler,progressOnInitialization:!!i.progressOnInitialization,errorHandler:i.errorHandler||this.createDefaultErrorHandler((l=i.connectionOptions)==null?void 0:l.maxRestartCount),middleware:i.middleware||{},workspaceFolder:i.workspaceFolder,connectionOptions:i.connectionOptions,markdown:s};for(let u of["disableCompletion","disableWorkspaceFolders","disableDiagnostics"])if(typeof i[u]=="boolean"){let c=` -`+Error().stack.split(` -`).slice(2,4).join(` -`);if(go.warn(`${u} in the client options is deprecated. use disabledFeatures instead.`,c),this.warn(`${u} in the client options is deprecated. use disabledFeatures instead.`,c),i[u]===!0){let h=u.slice(7);this._clientOptions.disabledFeatures.push(h[0].toLowerCase()+h.slice(1))}}this.state=0,this._connectionPromise=void 0,this._resolvedConnection=void 0,this._initializeResult=void 0,this._listeners=void 0,this._providers=void 0,this._diagnostics=void 0,this._fileEvents=[],this._fileEventDelayer=new $P(250),this._onReady=new Promise((u,c)=>{this._onReadyCallbacks=new KP(u,c)}),this._onStop=void 0,this._stateChangeEmitter=new x.Emitter,this._trace=x.Trace.Off,this._tracer={log:(u,c)=>{Ee(u)?this.logTrace(u,c):this.logObjectTrace(u)}},this._syncedDocuments=new Map;let a=y.getConfiguration("coc.preferences");this._markdownSupport=a.get("enableMarkdown",!0),this.registerBuiltinFeatures()}get supportedMarkupKind(){return this._markdownSupport?[x.MarkupKind.Markdown,x.MarkupKind.PlainText]:[x.MarkupKind.PlainText]}get state(){return this._state}get id(){return this._id}get name(){return this._name}set state(e){let t=this.getPublicState();this._state=e;let i=this.getPublicState();i!==t&&this._stateChangeEmitter.fire({oldState:t,newState:i})}getPublicState(){return this.state===3?2:this.state===1?3:1}get initializeResult(){return this._initializeResult}sendRequest(e,...t){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{return this._resolvedConnection.sendRequest(e,...t)}catch(i){throw this.error(`Sending request ${Ee(e)?e:e.method} failed.`,i),i}}onRequest(e,t){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{return this._resolvedConnection.onRequest(e,t)}catch(i){throw this.error(`Registering request handler ${Ee(e)?e:e.method} failed.`,i),i}}sendNotification(e,t){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{this._resolvedConnection.sendNotification(e,t)}catch(i){throw this.error(`Sending notification ${Ee(e)?e:e.method} failed.`,i),i}}onNotification(e,t){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{return this._resolvedConnection.onNotification(e,t)}catch(i){throw this.error(`Registering notification handler ${Ee(e)?e:e.method} failed.`,i),i}}onProgress(e,t,i){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{if(e==x.WorkDoneProgress.type){let r=this._clientOptions.middleware.handleWorkDoneProgress;if(r!==void 0)return this._resolvedConnection.onProgress(e,t,o=>{r(t,o,()=>i(o))})}return this._resolvedConnection.onProgress(e,t,i)}catch(r){throw this.error(`Registering progress handler for token ${t} failed.`,r),r}}sendProgress(e,t,i){if(!this.isConnectionActive())throw new Error("Language client is not ready yet");try{this._resolvedConnection.sendProgress(e,t,i)}catch(r){throw this.error(`Sending progress for token ${t} failed.`,r),r}}get clientOptions(){return this._clientOptions}get onDidChangeState(){return this._stateChangeEmitter.event}get outputChannel(){if(!this._outputChannel){let{outputChannelName:e}=this._clientOptions;this._outputChannel=k.createOutputChannel(e||this._name)}return this._outputChannel}get diagnostics(){return this._diagnostics}createDefaultErrorHandler(e){return new ZG(this._id,e!=null?e:4)}set trace(e){this._trace=e,this.onReady().then(()=>{this.resolveConnection().then(t=>{t.trace(this._trace,this._tracer,{sendNotification:!1,traceFormat:this._traceFormat})})},()=>{})}logObjectTrace(e){e.isLSPMessage&&e.type?this.outputChannel.append(`[LSP - ${new Date().toLocaleTimeString()}] `):this.outputChannel.append(`[Trace - ${new Date().toLocaleTimeString()}] `),e&&this.outputChannel.appendLine(`${JSON.stringify(e)}`)}data2String(e){if(e instanceof x.ResponseError){let t=e;return` Message: ${t.message} - Code: ${t.code} ${t.data?` -`+t.data.toString():""}`}return e instanceof Error?Ee(e.stack)?e.stack:e.message:Ee(e)?e:e.toString()}_appendOutput(e,t,i){let r=3;switch(e){case"Info":r=1;break;case"Warn":r=2;break}this.outputChannel.appendLine(`[${e} - ${new Date().toLocaleTimeString()}] ${t}`);let o;i&&(o=this.data2String(i),this.outputChannel.appendLine(o)),this._clientOptions.revealOutputChannelOn<=r&&this.outputChannel.show(!0)}info(e,t){this._appendOutput("Info",e,t)}warn(e,t){this._appendOutput("Warn",e,t)}error(e,t){this._appendOutput("Error",e,t)}logTrace(e,t){this.outputChannel.appendLine(`[Trace - ${new Date().toLocaleTimeString()}] ${e}`),t&&this.outputChannel.appendLine(this.data2String(t))}needsStart(){return this.state===0||this.state===4||this.state===5}needsStop(){return this.state===1||this.state===3}onReady(){return this._onReady}get started(){return this.state!=0}isConnectionActive(){return this.state===3&&!!this._resolvedConnection}start(){if(this._rootPath=this.resolveRootPath(),this._rootPath===!1)return this.warn("Required root pattern not resolved, server won't start."),x.Disposable.create(()=>{});if(this._onReadyCallbacks.isUsed&&(this._onReady=new Promise((e,t)=>{this._onReadyCallbacks=new KP(e,t)})),this._listeners=[],this._providers=[],!this._diagnostics){let e=this._clientOptions,t=e.diagnosticCollectionName?e.diagnosticCollectionName:this._id;e.disabledFeatures.includes("diagnostics")||(this._diagnostics=A.createDiagnosticCollection(t))}return this.state=1,this.resolveConnection().then(e=>(e.onLogMessage(t=>{let i;switch(t.type){case x.MessageType.Error:i="error",this.error(t.message);break;case x.MessageType.Warning:i="warning",this.warn(t.message);break;case x.MessageType.Info:i="info",this.info(t.message);break;default:i="log",this.outputChannel.appendLine(t.message)}if(global.hasOwnProperty("__TEST__")){console.log(`[${i}] ${t.message}`);return}}),e.onShowMessage(t=>{switch(t.type){case x.MessageType.Error:k.showErrorMessage(t.message);break;case x.MessageType.Warning:k.showWarningMessage(t.message);break;case x.MessageType.Info:k.showInformationMessage(t.message);break;default:k.showInformationMessage(t.message)}}),e.onRequest(x.ShowMessageRequest.type,t=>{let i;switch(t.type){case x.MessageType.Error:i=k.showErrorMessage.bind(k);break;case x.MessageType.Warning:i=k.showWarningMessage.bind(k);break;case x.MessageType.Info:i=k.showInformationMessage.bind(k);break;default:i=k.showInformationMessage.bind(k)}let r=t.actions||[];return i(t.message,...r).then(o=>o==null?null:o)}),e.onRequest(x.ShowDocumentRequest.type,async t=>{var o;let i=async s=>{try{if(s.external===!0||/^https?:\/\//.test(s.uri))return await y.openResource(s.uri),{success:!0};{let{selection:a,takeFocus:l}=s;return l===!1?await y.loadFile(s.uri):(await y.jumpTo(s.uri,a==null?void 0:a.start),De(a.start,a.end)!=0&&await k.selectRange(a)),{success:!0}}}catch{return{success:!0}}},r=(o=this._clientOptions.middleware.window)==null?void 0:o.showDocument;return r!==void 0?r(t,i):i(t)}),e.onTelemetry(t=>{}),e.listen(),this.initialize(e))).then(void 0,e=>{this.state=2,this._onReadyCallbacks.reject(e),this.error("Starting client failed ",e)}),x.Disposable.create(()=>{this.needsStop()&&this.stop()})}resolveConnection(){return this._connectionPromise||(this._connectionPromise=this.createConnection()),this._connectionPromise}resolveRootPath(){if(this._clientOptions.workspaceFolder)return O.parse(this._clientOptions.workspaceFolder.uri).fsPath;let{ignoredRootPaths:e}=this._clientOptions,t=y.getConfiguration(this.id),i=t.get("rootPatterns",[]),r=t.get("requireRootPattern",!1),o;if(i&&i.length){let a=y.getDocument(y.bufnr);if(a&&a.schema=="file"){let l=GP.default.dirname(O.parse(a.uri).fsPath);o=mb(l,i,y.cwd)}}if(r&&!o)return!1;let s=o||y.rootPath||y.cwd;return ii(s,YG.default.homedir())||Array.isArray(e)&&e.some(a=>ii(s,a))?(this.warn(`Ignored rootPath ${s} of client "${this._id}"`),null):s}initialize(e){let{initializationOptions:t,progressOnInitialization:i}=this._clientOptions;this.refreshTrace(e,!1);let r=this._rootPath,o={processId:process.pid,rootPath:r||null,rootUri:r?qf(O.file(r)):null,capabilities:this.computeClientCapabilities(),initializationOptions:Qs(t)?t():t,trace:x.Trace.toString(this._trace),workspaceFolders:null,locale:this.getLocale(),clientInfo:{name:"coc.nvim",version:y.version}};if(this.fillInitializeParams(o),i){let s=qe();o.workDoneToken=s;let a=new Hf(this._id,e,s);return a.begin({title:`Initializing ${this.id}`,kind:"begin"}),this.doInitialize(e,o).then(l=>(a.done(),l),l=>{throw a.cancel(),l})}else return this.doInitialize(e,o)}doInitialize(e,t){return e.initialize(t).then(i=>{this._resolvedConnection=e,this._initializeResult=i,this.state=3;let r;return ib(i.capabilities.textDocumentSync)?i.capabilities.textDocumentSync===x.TextDocumentSyncKind.None?r={openClose:!1,change:x.TextDocumentSyncKind.None,save:void 0}:r={openClose:!0,change:i.capabilities.textDocumentSync,save:{includeText:!1}}:i.capabilities.textDocumentSync!=null&&i.capabilities.textDocumentSync!==void 0&&(r=i.capabilities.textDocumentSync),this._capabilities=Object.assign({},i.capabilities,{resolvedTextDocumentSync:r}),e.onDiagnostics(o=>this.handleDiagnostics(o)),e.onRequest(x.RegistrationRequest.type,o=>this.handleRegistrationRequest(o)),e.onRequest("client/registerFeature",o=>this.handleRegistrationRequest(o)),e.onRequest(x.UnregistrationRequest.type,o=>this.handleUnregistrationRequest(o)),e.onRequest("client/unregisterFeature",o=>this.handleUnregistrationRequest(o)),e.onRequest(x.ApplyWorkspaceEditRequest.type,o=>this.handleApplyWorkspaceEdit(o)),e.sendNotification(x.InitializedNotification.type,{}),this.hookFileEvents(e),this.hookConfigurationChanged(e),this.initializeFeatures(e),this._onReadyCallbacks.resolve(),i}).then(void 0,i=>{throw this._clientOptions.initializationFailedHandler?this._clientOptions.initializationFailedHandler(i)?this.initialize(e):(this.stop(),this._onReadyCallbacks.reject(i)):i instanceof x.ResponseError&&i.data&&i.data.retry?k.showPrompt(i.message+" Retry?").then(r=>{r?this.initialize(e):(this.stop(),this._onReadyCallbacks.reject(i))}):(i&&i.message&&k.showMessage(i.message,"error"),this.error("Server initialization failed.",i),this.stop(),this._onReadyCallbacks.reject(i)),i})}stop(){if(this._initializeResult=void 0,!this._connectionPromise)return this.state=5,Promise.resolve();if(this.state===4&&this._onStop)return this._onStop;this.state=4,this.cleanUp();let e=this.resolveConnection().then(t=>{let i=!1,r=setTimeout(()=>{i=!0,t.end(),t.dispose()},2e3);return t.shutdown().then(()=>(clearTimeout(r),t.exit(),t),o=>{if(!i)throw t.end(),t.dispose(),o})});return(this._onStop=e.then(t=>{t&&t.unlisten()},t=>{throw go.error("Stopping server failed:",t),this.error("Stopping server failed",t),t})).finally(()=>{this.state=5,this.cleanUpChannel(),this._onStop=void 0,this._connectionPromise=void 0,this._resolvedConnection=void 0})}cleanUp(e=!0,t=!0){this._listeners&&(this._listeners.forEach(i=>i.dispose()),this._listeners=void 0),this._providers&&(this._providers.forEach(i=>i.dispose()),this._providers=void 0);for(let i of this._features.values())typeof i.dispose=="function"?i.dispose():go.error("Feature can't be disposed",i);this._syncedDocuments&&this._syncedDocuments.clear(),e&&this.cleanUpChannel(),this._diagnostics&&(t?(this._diagnostics.dispose(),this._diagnostics=void 0):this._diagnostics.clear())}cleanUpChannel(){this._outputChannel&&(this._outputChannel.dispose(),this._outputChannel=void 0)}notifyFileEvent(e){var o;let t=this;function i(s){t._fileEvents.push(s),t._fileEventDelayer.trigger(()=>{t.onReady().then(()=>{t.resolveConnection().then(a=>{t.isConnectionActive()&&a.didChangeWatchedFiles({changes:t._fileEvents}),t._fileEvents=[]})},a=>{t.error("Notify file events failed.",a)})})}let r=(o=this.clientOptions.middleware)==null?void 0:o.workspace;r!=null&&r.didChangeWatchedFile?r.didChangeWatchedFile(e,i):i(e)}handleDiagnostics(e){if(!this._diagnostics)return;let{uri:t,diagnostics:i,version:r}=e;if(typeof r=="number"){let s=y.getDocument(t);if(!s||s.version!=r)return}let o=this.clientOptions.middleware.handleDiagnostics;o?o(t,i,(s,a)=>this.setDiagnostics(s,a)):this.setDiagnostics(t,i)}setDiagnostics(e,t){var r;if(!this._diagnostics)return;if(y.getConfiguration("diagnostic").get("separateRelatedInformationAsDiagnostics")&&t.length>0){let o=new Map;o.set(e,t);for(let s of t){if((r=s.relatedInformation)!=null&&r.length){let a=`${s.message} - -Related diagnostics: -`;for(let l of s.relatedInformation){let u=GP.default.basename(O.parse(l.location.uri).fsPath),c=l.location.range.start.line;a=`${a} -${u}(line ${c+1}): ${l.message}`;let h=o.get(l.location.uri)||[];h.push(x.Diagnostic.create(l.location.range,l.message,x.DiagnosticSeverity.Hint,s.code,s.source)),o.set(l.location.uri,h)}s.message=a}this._diagnostics.set(Array.from(o))}}else this._diagnostics.set(e,t)}createConnection(){let e=(i,r,o)=>{go.error("connection error:",i,r),this.handleConnectionError(i,r,o)},t=()=>{this.handleConnectionClosed()};return this.createMessageTransports(this._clientOptions.stdioEncoding||"utf8").then(i=>WSe(i.reader,i.writer,e,t,this._clientOptions.connectionOptions))}handleConnectionClosed(){if(this.state===5){go.debug(`client ${this._id} normal close`);return}try{this._resolvedConnection&&this._resolvedConnection.dispose()}catch{}let e=1;if(this.state!==4)try{e=this._clientOptions.errorHandler.closed()}catch{}this._connectionPromise=void 0,this._resolvedConnection=void 0,e===1?(this.error("Connection to server got closed. Server will not be restarted."),this.state===1?(this._onReadyCallbacks.reject(new Error("Connection to server got closed. Server will not be restarted.")),this.state=2):this.state=5,this.cleanUp(!1,!0)):e===2&&(this.info("Connection to server got closed. Server will restart."),this.cleanUp(!1,!0),this.state=0,this.start())}restart(){this.cleanUp(!0,!1),this.start()}handleConnectionError(e,t,i){this._clientOptions.errorHandler.error(e,t,i)===2&&(this.error("Connection to server is erroring. Shutting down server."),this.stop())}hookConfigurationChanged(e){y.onDidChangeConfiguration(t=>{t.affectsConfiguration(this._id)&&this.refreshTrace(e,!0)},null,this._listeners)}refreshTrace(e,t=!1){let i=y.getConfiguration(this._id),r=x.Trace.Off,o=x.TraceFormat.Text;if(i){let s=i.get("trace.server","off");typeof s=="string"?r=x.Trace.fromString(s):(r=x.Trace.fromString(i.get("trace.server.verbosity","off")),o=x.TraceFormat.fromString(i.get("trace.server.format","text")))}t&&this._trace==r&&this._traceFormat==o||(this._trace=r,this._traceFormat=o,e.trace(this._trace,this._tracer,{sendNotification:t,traceFormat:this._traceFormat}))}hookFileEvents(e){let t=this._clientOptions.synchronize.fileEvents;if(!t)return;let i;Array.isArray(t)?i=t:i=[t],i&&this._dynamicFeatures.get(x.DidChangeWatchedFilesNotification.type.method).registerRaw(qe(),i)}registerFeatures(e){for(let t of e)this.registerFeature(t)}registerFeature(e){if(this._features.push(e),QP.is(e)){let t=e.registrationType;this._dynamicFeatures.set(t.method,e)}}getFeature(e){return this._dynamicFeatures.get(e)}registerBuiltinFeatures(){let{disabledFeatures:e}=this._clientOptions;e.includes("configuration")||this.registerFeature(new m6(this)),this.registerFeature(new XG(this,this._syncedDocuments)),this.registerFeature(new GG(this)),this.registerFeature(new UG(this,this._syncedDocuments)),e.includes("willSave")||this.registerFeature(new QG(this)),e.includes("willSaveWaitUntil")||this.registerFeature(new KG(this)),e.includes("didSave")||this.registerFeature(new zG(this)),e.includes("fileSystemWatcher")||this.registerFeature(new VG(this,t=>this.notifyFileEvent(t))),e.includes("completion")||this.registerFeature(new t6(this)),e.includes("hover")||this.registerFeature(new i6(this)),e.includes("signatureHelp")||this.registerFeature(new n6(this)),e.includes("references")||this.registerFeature(new o6(this)),e.includes("definition")||this.registerFeature(new r6(this)),e.includes("documentHighlight")||this.registerFeature(new s6(this)),e.includes("documentSymbol")||this.registerFeature(new a6(this)),e.includes("codeAction")||this.registerFeature(new u6(this)),e.includes("workspaceSymbol")||this.registerFeature(new l6(this)),e.includes("codeLens")||this.registerFeature(new c6(this)),e.includes("documentFormatting")||this.registerFeature(new h6(this)),e.includes("documentRangeFormatting")||this.registerFeature(new d6(this)),e.includes("documentOnTypeFormatting")||this.registerFeature(new g6(this)),e.includes("rename")||this.registerFeature(new f6(this)),e.includes("documentLink")||this.registerFeature(new p6(this)),e.includes("executeCommand")||this.registerFeature(new b6(this))}fillInitializeParams(e){for(let t of this._features)Qs(t.fillInitializeParams)&&t.fillInitializeParams(e)}computeClientCapabilities(){let e={};U(e,"workspace").applyEdit=!0;let t=U(U(e,"workspace"),"workspaceEdit");t.documentChanges=!0,t.resourceOperations=[x.ResourceOperationKind.Create,x.ResourceOperationKind.Rename,x.ResourceOperationKind.Delete],t.failureHandling=x.FailureHandlingKind.Undo,t.normalizesLineEndings=!0,t.changeAnnotationSupport={groupsOnLabel:!1};let i=U(U(e,"textDocument"),"publishDiagnostics");i.relatedInformation=!0,i.versionSupport=!0,i.tagSupport={valueSet:[x.DiagnosticTag.Unnecessary,x.DiagnosticTag.Deprecated]},i.codeDescriptionSupport=!0,i.dataSupport=!0;let r=U(e,"window"),o=U(r,"showMessage");o.messageActionItem={additionalPropertiesSupport:!0};let s=U(r,"showDocument");s.support=!0;let a=U(e,"general");a.regularExpressions={engine:"ECMAScript",version:"ES2020"},a.markdown={parser:"marked",version:"4.0.10"};for(let l of this._features)l.fillClientCapabilities(e);return e}initializeFeatures(e){let t=this._clientOptions.documentSelector;for(let i of this._features)i.initialize(this._capabilities,t)}handleRegistrationRequest(e){return this.clientOptions.disableDynamicRegister?Promise.resolve():new Promise((t,i)=>{for(let r of e.registrations){let o=this._dynamicFeatures.get(r.method);if(!o){i(new Error(`No feature implementation for ${r.method} found. Registration failed.`));return}let s=r.registerOptions||{};s.documentSelector=s.documentSelector||this._clientOptions.documentSelector;let a={id:r.id,registerOptions:s};try{o.register(a)}catch(l){i(l);return}}t()})}handleUnregistrationRequest(e){return new Promise((t,i)=>{for(let r of e.unregisterations){let o=this._dynamicFeatures.get(r.method);if(!o){i(new Error(`No feature implementation for ${r.method} found. Unregistration failed.`));return}o.unregister(r.id)}t()})}handleApplyWorkspaceEdit(e){let t=e.edit,i=new Map;y.textDocuments.forEach(o=>i.set(o.uri.toString(),o));let r=!1;if(t.documentChanges){for(let o of t.documentChanges)if(x.TextDocumentEdit.is(o)&&o.textDocument.version&&o.textDocument.version>=0){let s=i.get(o.textDocument.uri);if(s&&s.version!==o.textDocument.version){r=!0;break}}}return r?Promise.resolve({applied:!1}):y.applyEdit(e.edit).then(o=>({applied:o}))}getLocale(){let e=process.env.LANG;return e?e.split(".")[0]:"en"}handleFailedRequest(e,t,i,r){if(i instanceof x.ResponseError){if(i.code===x.LSPErrorCodes.RequestCancelled){if(t!==void 0&&t.isCancellationRequested)return r}else if(i.code===x.LSPErrorCodes.ContentModified)return r}this.error(`Request ${e.method} failed.`,i)}logFailedRequest(e,t){t instanceof x.ResponseError&&t.code===x.LSPErrorCodes.RequestCancelled||this.error(`Request ${e.method} failed.`,t)}}});var Gl,i_,y6=_(()=>{"use strict";Gl=C(H());Ce();Dn();"use strict";i_=class extends Me{constructor(e){super(e,Gl.DocumentColorRequest.type)}fillClientCapabilities(e){U(U(e,"textDocument"),"colorProvider").dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.colorProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideColorPresentations:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d={color:u,textDocument:{uri:c.document.uri},range:c.range};return s.sendRequest(Gl.ColorPresentationRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(Gl.ColorPresentationRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.provideColorPresentations?l.provideColorPresentations(i,r,o,a):a(i,r,o)},provideDocumentColors:(i,r)=>{let o=this._client,s=(l,u)=>{let c={textDocument:{uri:l.uri}};return o.sendRequest(Gl.DocumentColorRequest.type,c,u).then(h=>h,h=>o.handleFailedRequest(Gl.ColorPresentationRequest.type,u,h,null))},a=o.clientOptions.middleware;return a.provideDocumentColors?a.provideDocumentColors(i,r,s):s(i,r)}};return[A.registerDocumentColorProvider(e.documentSelector,t),t]}}});function Wf(n){if(n){if(Array.isArray(n))return n.map(Wf);if(typeof n=="object"){let e=Object.create(null);for(let t in n)Object.prototype.hasOwnProperty.call(n,t)&&(e[t]=Wf(n[t]));return e}}return n}var v6,qWe,n_,w6=_(()=>{"use strict";v6=C(H());V();qWe=q()("languageclient-configuration"),n_=class{constructor(e){this._client=e;var i;let t=(i=this._client.clientOptions.synchronize)==null?void 0:i.configurationSection;typeof t=="string"&&t.startsWith("languageserver.")&&(this.languageserverSection=t)}fillClientCapabilities(e){e.workspace=e.workspace||{},e.workspace.configuration=!0}initialize(){let e=this._client;e.onRequest(v6.ConfigurationRequest.type,(t,i)=>{let r=s=>{let a=[];for(let l of s.items)a.push(this.getConfiguration(l.scopeUri,l.section));return a},o=e.clientOptions.middleware.workspace;return o&&o.configuration?o.configuration(t,i,r):r(t,i)})}getConfiguration(e,t){let i=null;if(t){this.languageserverSection&&(t=`${this.languageserverSection}.${t}`);let r=t.lastIndexOf(".");if(r===-1)i=Wf(y.getConfiguration(void 0,e).get(t));else{let o=y.getConfiguration(t.substr(0,r),e);o&&(i=Wf(o.get(t.substr(r+1))))}}else{let r=y.getConfiguration(this.languageserverSection,e);i={};for(let o of Object.keys(r))r.has(o)&&(i[o]=Wf(r.get(o)))}return i}dispose(){}}});var Sw,r_,D6=_(()=>{"use strict";Sw=C(H());Ce();Dn();_a();"use strict";r_=class extends Me{constructor(e){super(e,Sw.DeclarationRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"declaration");t.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.declarationProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideDeclaration:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(Sw.DeclarationRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(Sw.DeclarationRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideDeclaration?l.provideDeclaration(i,r,o,a):a(i,r,o)}};return[A.registerDeclarationProvider(e.documentSelector,t),t]}}});var Tw,o_,x6=_(()=>{"use strict";Tw=C(H());Ce();Dn();"use strict";o_=class extends Me{constructor(e){super(e,Tw.FoldingRangeRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"foldingRange");t.dynamicRegistration=!0,t.rangeLimit=5e3,t.lineFoldingOnly=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.foldingRangeProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideFoldingRanges:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d={textDocument:{uri:u.uri}};return s.sendRequest(Tw.FoldingRangeRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(Tw.FoldingRangeRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.provideFoldingRanges?l.provideFoldingRanges(i,r,o,a):a(i,r,o)}};return[A.registerFoldingRangeProvider(e.documentSelector,t),t]}}});var kw,s_,C6=_(()=>{"use strict";kw=C(H());Ce();Dn();_a();s_=class extends Me{constructor(e){super(e,kw.ImplementationRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"implementation");t.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.implementationProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideImplementation:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(kw.ImplementationRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(kw.ImplementationRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideImplementation?l.provideImplementation(i,r,o,a):a(i,r,o)}};return[A.registerImplementationProvider(e.documentSelector,t),t]}}});var S6,a_,T6=_(()=>{"use strict";S6=C(H());Dn();ZP();"use strict";a_=class{constructor(e){this._client=e;this.activeParts=new Set}fillClientCapabilities(e){U(e,"window").workDoneProgress=!0}initialize(){let e=this._client,t=r=>{this.activeParts.delete(r)},i=r=>{this.activeParts.add(new Hf(this._client.id,this._client,r.token,t))};e.onRequest(S6.WorkDoneProgressCreateRequest.type,i)}dispose(){for(let e of this.activeParts)e.done();this.activeParts.clear()}}});var Ew,l_,k6=_(()=>{"use strict";Ew=C(H());Ce();Dn();_a();l_=class extends Me{constructor(e){super(e,Ew.TypeDefinitionRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"typeDefinition");t.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.typeDefinitionProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideTypeDefinition:(i,r,o)=>{let s=this._client,a=(u,c,h)=>s.sendRequest(Ew.TypeDefinitionRequest.type,wn(u,c),h).then(d=>d,d=>s.handleFailedRequest(Ew.TypeDefinitionRequest.type,h,d,null)),l=s.clientOptions.middleware;return l.provideTypeDefinition?l.provideTypeDefinition(i,r,o,a):a(i,r,o)}};return[A.registerTypeDefinitionProvider(e.documentSelector,t),t]}}});function u_(n,e){if(n!==void 0)return n[e]}function E6(n,e){return n.filter(t=>!e.includes(t))}var Zf,cZe,c_,P6=_(()=>{"use strict";Zf=C(H());we();Je();V();ww();"use strict";cZe=q()("language-client-workspaceFolder");c_=class{constructor(e){this._client=e;this._listeners=new Map}get registrationType(){return Zf.DidChangeWorkspaceFoldersNotification.type}getValidWorkspaceFolders(){let{workspaceFolders:e}=y;if(!e||e.length==0)return;let{ignoredRootPaths:t}=this._client.clientOptions;Array.isArray(t)||(t=[]);let i=e.filter(r=>{let o=O.parse(r.uri).fsPath;return t.every(s=>!ii(s,o))});return i.length?i:void 0}asProtocol(e){return e==null?null:{uri:e.uri,name:e.name}}fillInitializeParams(e){let t=this.getValidWorkspaceFolders();this._initialFolders=t,t==null?(this._client.warn("No valid workspaceFolder exists"),e.workspaceFolders=null):e.workspaceFolders=t.map(i=>this.asProtocol(i))}fillClientCapabilities(e){e.workspace=e.workspace||{},e.workspace.workspaceFolders=!0}initialize(e){let t=this._client;t.onRequest(Zf.WorkspaceFoldersRequest.type,o=>{let s=()=>{let l=this.getValidWorkspaceFolders();return l===void 0?null:l.map(c=>this.asProtocol(c))},a=t.clientOptions.middleware.workspace;return a&&a.workspaceFolders?a.workspaceFolders(o,s):s(o)});let i=u_(u_(u_(e,"workspace"),"workspaceFolders"),"changeNotifications"),r;typeof i=="string"?r=i:i===!0&&(r=qe()),r&&this.register({id:r,registerOptions:void 0})}doSendEvent(e,t){let i={event:{added:e.map(r=>this.asProtocol(r)),removed:t.map(r=>this.asProtocol(r))}};this._client.sendNotification(Zf.DidChangeWorkspaceFoldersNotification.type,i)}sendInitialEvent(e){if(this._initialFolders&&e){let t=E6(this._initialFolders,e),i=E6(e,this._initialFolders);(i.length>0||t.length>0)&&this.doSendEvent(i,t)}else this._initialFolders?this.doSendEvent([],this._initialFolders):e&&this.doSendEvent(e,[])}register(e){let t=e.id,i=this._client,r=y.onDidChangeWorkspaceFolders(s=>{let a=u=>{this.doSendEvent(u.added,u.removed)},l=i.clientOptions.middleware.workspace;l&&l.didChangeWorkspaceFolders?l.didChangeWorkspaceFolders(s,a):a(s)});this._listeners.set(t,r);let o=this.getValidWorkspaceFolders();this.sendInitialEvent(o)}unregister(e){let t=this._listeners.get(e);t!==void 0&&(this._listeners.delete(e),t.dispose())}dispose(){for(let e of this._listeners.values())e.dispose();this._listeners.clear()}}});var Pw,h_,_6=_(()=>{"use strict";Pw=C(H());Ce();Dn();"use strict";h_=class extends Me{constructor(e){super(e,Pw.SelectionRangeRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"selectionRange");t.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.selectionRangeProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideSelectionRanges:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d={textDocument:{uri:u.uri},positions:c};return s.sendRequest(Pw.SelectionRangeRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(Pw.SelectionRangeRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.provideSelectionRanges?l.provideSelectionRanges(i,r,o,a):a(i,r,o)}};return[A.registerSelectionRangeProvider(e.documentSelector,t),t]}}});var po,d_,R6=_(()=>{"use strict";po=C(H());Ce();Dn();_a();"use strict";d_=class extends Me{constructor(e){super(e,po.CallHierarchyPrepareRequest.type)}fillClientCapabilities(e){let i=U(U(e,"textDocument"),"callHierarchy");i.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.callHierarchyProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={prepareCallHierarchy:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d=wn(u,c);return s.sendRequest(po.CallHierarchyPrepareRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(po.CallHierarchyPrepareRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.prepareCallHierarchy?l.prepareCallHierarchy(i,r,o,a):a(i,r,o)},provideCallHierarchyIncomingCalls:(i,r)=>{let o=this._client,s=(l,u)=>o.sendRequest(po.CallHierarchyIncomingCallsRequest.type,{item:l},u).then(c=>c,c=>o.handleFailedRequest(po.CallHierarchyIncomingCallsRequest.type,u,c,null)),a=o.clientOptions.middleware;return a.provideCallHierarchyIncomingCalls?a.provideCallHierarchyIncomingCalls(i,r,s):s(i,r)},provideCallHierarchyOutgoingCalls:(i,r)=>{let o=this._client,s=(l,u)=>o.sendRequest(po.CallHierarchyOutgoingCallsRequest.type,{item:l},u).then(c=>c,c=>o.handleFailedRequest(po.CallHierarchyOutgoingCallsRequest.type,u,c,null)),a=o.clientOptions.middleware;return a.provideCallHierarchyOutgoingCalls?a.provideCallHierarchyOutgoingCalls(i,r,s):s(i,r)}};return[A.registerCallHierarchyProvider(e.documentSelector,t),t]}}});var ue,sJe,g_,L6=_(()=>{"use strict";ue=C(H());Ce();In();Dn();_a();"use strict";sJe=q()("languageclient-semanticTokens"),g_=class extends Me{constructor(e){super(e,ue.SemanticTokensRegistrationType.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"semanticTokens");t.dynamicRegistration=!0,t.tokenTypes=[ue.SemanticTokenTypes.namespace,ue.SemanticTokenTypes.type,ue.SemanticTokenTypes.class,ue.SemanticTokenTypes.enum,ue.SemanticTokenTypes.interface,ue.SemanticTokenTypes.struct,ue.SemanticTokenTypes.typeParameter,ue.SemanticTokenTypes.parameter,ue.SemanticTokenTypes.variable,ue.SemanticTokenTypes.property,ue.SemanticTokenTypes.enumMember,ue.SemanticTokenTypes.event,ue.SemanticTokenTypes.function,ue.SemanticTokenTypes.method,ue.SemanticTokenTypes.macro,ue.SemanticTokenTypes.keyword,ue.SemanticTokenTypes.modifier,ue.SemanticTokenTypes.comment,ue.SemanticTokenTypes.string,ue.SemanticTokenTypes.number,ue.SemanticTokenTypes.regexp,ue.SemanticTokenTypes.operator],t.tokenModifiers=[ue.SemanticTokenModifiers.declaration,ue.SemanticTokenModifiers.definition,ue.SemanticTokenModifiers.readonly,ue.SemanticTokenModifiers.static,ue.SemanticTokenModifiers.deprecated,ue.SemanticTokenModifiers.abstract,ue.SemanticTokenModifiers.async,ue.SemanticTokenModifiers.modification,ue.SemanticTokenModifiers.documentation,ue.SemanticTokenModifiers.defaultLibrary],t.formats=[ue.TokenFormat.Relative],t.requests={range:!0,full:{delta:!0}},t.multilineTokenSupport=!1,t.overlappingTokenSupport=!1,U(U(e,"workspace"),"semanticTokens").refreshSupport=!0}initialize(e,t){this._client.onRequest(ue.SemanticTokensRefreshRequest.type,async()=>{for(let s of this.getAllProviders())s.onDidChangeSemanticTokensEmitter.fire()});let[r,o]=this.getRegistration(t,e.semanticTokensProvider);!r||!o||this.register({id:r,registerOptions:o})}registerLanguageProvider(e){let t=Kn(e.full)?e.full:e.full!==void 0,i=e.full!==void 0&&typeof e.full!="boolean"&&e.full.delta===!0,r=new ue.Emitter,o=t?{onDidChangeSemanticTokens:r.event,provideDocumentSemanticTokens:(u,c)=>{let h=this._client,d=h.clientOptions.middleware,g=(f,p)=>{let b={textDocument:Xl(f)};return h.sendRequest(ue.SemanticTokensRequest.type,b,p).then(v=>v,v=>h.handleFailedRequest(ue.SemanticTokensRequest.type,p,v,null))};return d.provideDocumentSemanticTokens?d.provideDocumentSemanticTokens(u,c,g):g(u,c)},provideDocumentSemanticTokensEdits:i?(u,c,h)=>{let d=this._client,g=d.clientOptions.middleware,f=(p,b,v)=>{let w={textDocument:Xl(p),previousResultId:b};return d.sendRequest(ue.SemanticTokensDeltaRequest.type,w,v).then(D=>D,D=>d.handleFailedRequest(ue.SemanticTokensDeltaRequest.type,v,D,null))};return g.provideDocumentSemanticTokensEdits?g.provideDocumentSemanticTokensEdits(u,c,h,f):f(u,c,h)}:void 0}:void 0,a=e.range===!0?{provideDocumentRangeSemanticTokens:(u,c,h)=>{let d=this._client,g=d.clientOptions.middleware,f=(p,b,v)=>{let w={textDocument:Xl(p),range:b};return d.sendRequest(ue.SemanticTokensRangeRequest.type,w,v).then(D=>D,D=>d.handleFailedRequest(ue.SemanticTokensRangeRequest.type,v,D,null))};return g.provideDocumentRangeSemanticTokens?g.provideDocumentRangeSemanticTokens(u,c,h,f):f(u,c,h)}}:void 0,l=[];return o!==void 0&&l.push(A.registerDocumentSemanticTokensProvider(e.documentSelector,o,e.legend)),a!==void 0&&l.push(A.registerDocumentRangeSemanticTokensProvider(e.documentSelector,a,e.legend)),[ue.Disposable.create(()=>l.forEach(u=>u.dispose())),{range:a,full:o,onDidChangeSemanticTokensEmitter:r}]}}});var _w,wJe,f_,F6=_(()=>{"use strict";_w=C(H());Ce();Dn();_a();wJe=q()("languageclient-linkedEditingRange"),f_=class extends Me{constructor(e){super(e,_w.LinkedEditingRangeRequest.type)}fillClientCapabilities(e){let t=U(U(e,"textDocument"),"linkedEditingRange");t.dynamicRegistration=!0}initialize(e,t){let[i,r]=this.getRegistration(t,e.linkedEditingRangeProvider);!i||!r||this.register({id:i,registerOptions:r})}registerLanguageProvider(e){let t={provideLinkedEditingRanges:(i,r,o)=>{let s=this._client,a=(u,c,h)=>{let d=wn(u,c);return s.sendRequest(_w.LinkedEditingRangeRequest.type,d,h).then(g=>g,g=>s.handleFailedRequest(_w.LinkedEditingRangeRequest.type,h,g,null))},l=s.clientOptions.middleware;return l.provideLinkedEditingRange?l.provideLinkedEditingRange(i,r,o,a):a(i,r,o)}};return[A.registerLinkedEditingRangeProvider(e.documentSelector,t),t]}}});function JSe(n,e){return n[e]}function I6(n,e,t){n[e]=t}function Rw(n){return{files:n.files.map(e=>({uri:e.toString()}))}}function A6(n){return{files:n.files.map(e=>({oldUri:e.oldUri.toString(),newUri:e.newUri.toString()}))}}var j6,Oi,KJe,Ql,Lw,p_,m_,b_,Fw,y_,v_,w_,O6=_(()=>{"use strict";j6=C(Vn()),Oi=C(H());Fr();Je();V();Dn();ww();KJe=q()("language-client-fileOperations");Ql=class{constructor(e,t,i,r,o){this._filters=new Map;this._client=e,this._event=t,this._registrationType=i,this._clientCapability=r,this._serverCapability=o}get registrationType(){return this._registrationType}fillClientCapabilities(e){let t=U(U(e,"workspace"),"fileOperations");I6(t,"dynamicRegistration",!0),I6(t,this._clientCapability,!0)}initialize(e){var r;let t=(r=e.workspace)==null?void 0:r.fileOperations,i=t!==void 0?JSe(t,this._serverCapability):void 0;if((i==null?void 0:i.filters)!==void 0)try{this.register({id:qe(),registerOptions:{filters:i.filters}})}catch(o){this._client.warn(`Ignoring invalid glob pattern for ${this._serverCapability} registration: ${o}`)}}register(e){this._listener||(this._listener=this._event(this.send,this));let t=e.registerOptions.filters.map(i=>{let r=new j6.Minimatch(i.pattern.glob,Ql.asMinimatchOptions(i.pattern.options));if(!r.makeRe())throw new Error(`Invalid pattern ${i.pattern.glob}!`);return{scheme:i.scheme,matcher:r,kind:i.pattern.matches}});this._filters.set(e.id,t)}unregister(e){this._filters.delete(e),this._filters.size===0&&this._listener&&(this._listener.dispose(),this._listener=void 0)}dispose(){this._filters.clear(),this._listener&&(this._listener.dispose(),this._listener=void 0)}async filter(e,t){let i=await Promise.all(e.files.map(async o=>{let s=t(o),a=s.fsPath.replace(/\\/g,"/");for(let l of this._filters.values())for(let u of l)if(!(u.scheme!==void 0&&u.scheme!==s.scheme)){if(u.matcher.match(a)){if(u.kind===void 0)return!0;let c=await Ql.getFileType(s);if(c===void 0)return this._client.error(`Failed to determine file type for ${s.toString()}.`),!0;if(c===1&&u.kind===Oi.FileOperationPatternKind.file||c===2&&u.kind===Oi.FileOperationPatternKind.folder)return!0}else if(u.kind===Oi.FileOperationPatternKind.folder&&await Ql.getFileType(s)===2&&u.matcher.match(`${a}/`))return!0}return!1})),r=e.files.filter((o,s)=>i[s]);return Ba(ge({},e),{files:r})}static async getFileType(e){try{let t=await Ht(e.fsPath);return t.isFile()?1:t.isDirectory()?2:t.isSymbolicLink()?64:0}catch{return}}static asMinimatchOptions(e){if(e!==void 0&&e.ignoreCase===!0)return{nocase:!0}}},Lw=class extends Ql{constructor(e,t,i,r,o,s,a){super(e,t,i,r,o);this._notificationType=i,this._accessUri=s,this._createParams=a}async send(e){let t=await this.filter(e,this._accessUri);if(t.files.length){let i=async r=>{this._client.sendNotification(this._notificationType,this._createParams(r))};this.doSend(t,i)}}},p_=class extends Lw{constructor(e){super(e,y.onDidCreateFiles,Oi.DidCreateFilesNotification.type,"didCreate","didCreate",t=>t,t=>Rw(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.didCreateFiles?i.didCreateFiles(e,t):t(e)}},m_=class extends Lw{constructor(e){super(e,y.onDidRenameFiles,Oi.DidRenameFilesNotification.type,"didRename","didRename",t=>t.oldUri,t=>A6(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.didRenameFiles?i.didRenameFiles(e,t):t(e)}},b_=class extends Lw{constructor(e){super(e,y.onDidDeleteFiles,Oi.DidDeleteFilesNotification.type,"didDelete","didDelete",t=>t,t=>Rw(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.didDeleteFiles?i.didDeleteFiles(e,t):t(e)}},Fw=class extends Ql{constructor(e,t,i,r,o,s,a){super(e,t,i,r,o);this._requestType=i,this._accessUri=s,this._createParams=a}async send(e){let t=this.waitUntil(e);e.waitUntil(t)}async waitUntil(e){let t=await this.filter(e,this._accessUri);if(t.files.length){let i=r=>this._client.sendRequest(this._requestType,this._createParams(r));return this.doSend(t,i)}else return}},y_=class extends Fw{constructor(e){super(e,y.onWillCreateFiles,Oi.WillCreateFilesRequest.type,"willCreate","willCreate",t=>t,t=>Rw(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.willCreateFiles?i.willCreateFiles(e,t):t(e)}},v_=class extends Fw{constructor(e){super(e,y.onWillRenameFiles,Oi.WillRenameFilesRequest.type,"willRename","willRename",t=>t.oldUri,t=>A6(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.willRenameFiles?i.willRenameFiles(e,t):t(e)}},w_=class extends Fw{constructor(e){super(e,y.onWillDeleteFiles,Oi.WillDeleteFilesRequest.type,"willDelete","willDelete",t=>t,t=>Rw(t))}doSend(e,t){var r;let i=(r=this._client.clientOptions.middleware)==null?void 0:r.workspace;return i!=null&&i.willDeleteFiles?i.willDeleteFiles(e,t):t(e)}}});var as,Iw,bh,ht,y$e,D_,x_,jw,yh,C_,S_,T_,Jf,k_,$Se,E_=_(()=>{"use strict";as=C(require("child_process")),Iw=C(require("fs")),bh=C(require("path")),ht=C(PG());Fr();z();In();RG();V();Dn();y6();w6();D6();x6();C6();T6();k6();P6();_6();R6();L6();F6();O6();Dn();y$e=as.default.ChildProcess,D_=q()("language-client-index");(e=>{function n(t){return Ee(t.command)}e.is=n})(x_||(x_={}));jw=(r=>(r[r.stdio=0]="stdio",r[r.ipc=1]="ipc",r[r.pipe=2]="pipe",r[r.socket=3]="socket",r))(jw||{});(e=>{function n(t){let i=t;return i&&i.kind===3&&ib(i.port)}e.isSocket=n})(yh||(yh={}));(e=>{function n(t){return Ee(t.module)}e.is=n})(C_||(C_={}));(e=>{function n(t){let i=t;return i&&i.writer!==void 0&&i.reader!==void 0}e.is=n})(S_||(S_={}));(e=>{function n(t){let i=t;return i&&i.process!==void 0&&typeof i.detached=="boolean"}e.is=n})(T_||(T_={}));Jf=class extends t_{constructor(e,t,i,r,o){let s,a,l,u,c;Ee(t)?(s=e,a=t,l=i,u=r,c=!!o):(s=e.toLowerCase(),a=e,l=t,u=i,c=r),c===void 0&&(c=!1);super(s,a,u);this._serverOptions=l,this._forceDebug=c,this.registerProposedFeatures()}stop(){return super.stop().then(()=>{if(this._serverProcess){let e=this._serverProcess;this._serverProcess=void 0,(this._isDetached===void 0||!this._isDetached)&&this.checkProcessDied(e),this._isDetached=void 0}})}get serviceState(){let e=this._state;switch(e){case 0:return 0;case 3:return 3;case 2:return 2;case 1:return 1;case 5:return 5;case 4:return 4;default:return D_.error(`Unknown state: ${e}`),5}}static stateName(e){switch(e){case 0:return"Initial";case 3:return"Running";case 2:return"StartFailed";case 1:return"Starting";case 5:return"Stopped";case 4:return"Stopping";default:return"Unknown"}}checkProcessDied(e){!e||global.__TEST__||setTimeout(()=>{try{process.kill(e.pid,0),_G(e)}catch{}},2e3)}handleConnectionClosed(){this._serverProcess=void 0,super.handleConnectionClosed()}createMessageTransports(e){function t(c,h){if(!c&&!h)return;let d=Object.create(null);return Object.keys(process.env).forEach(g=>d[g]=process.env[g]),c&&Object.keys(c).forEach(g=>d[g]=c[g]),d}let i=["--debug=","--debug-brk=","--inspect=","--inspect-brk="],r=["--debug","--debug-brk","--inspect","--inspect-brk"];function o(){let c=process.execArgv;return c?c.some(h=>i.some(d=>h.startsWith(d))||r.some(d=>h===d)):!1}function s(c){if(c.stdin===null||c.stdout===null||c.stderr===null)throw new Error("Process created without stdio streams")}let a=this._serverOptions;if(Qs(a))return a().then(c=>{if(mh.is(c))return this._isDetached=!!c.detached,c;if(S_.is(c))return this._isDetached=!!c.detached,{reader:new ht.StreamMessageReader(c.reader),writer:new ht.StreamMessageWriter(c.writer)};{let h;return T_.is(c)?(h=c.process,this._isDetached=c.detached):(h=c,this._isDetached=!1),h.stderr.on("data",d=>this.outputChannel.append(Ee(d)?d:d.toString(e))),{reader:new ht.StreamMessageReader(h.stdout),writer:new ht.StreamMessageWriter(h.stdin)}}});let l,u=a;return u.run||u.debug?typeof v8debug=="object"||this._forceDebug||o()?l=u.debug:l=u.run:l=a,this._getServerWorkingDir(l.options).then(c=>{if(C_.is(l)&&l.module){let h=l,d=h.transport||0;if(h.runtime){let g=[],f=h.options||Object.create(null);f.execArgv&&f.execArgv.forEach(w=>g.push(w)),g.push(h.module),h.args&&h.args.forEach(w=>g.push(w));let p=Object.create(null);p.cwd=c,p.env=t(f.env,!1);let b=this._getRuntimePath(h.runtime,c),v;if(d===1?(p.stdio=[null,null,null,"ipc"],g.push("--node-ipc")):d===0?g.push("--stdio"):d===2?(v=(0,ht.generateRandomPipeName)(),g.push(`--pipe=${v}`)):yh.isSocket(d)&&g.push(`--socket=${d.port}`),g.push(`--clientProcessId=${process.pid.toString()}`),d===1||d===0){let w=as.default.spawn(b,g,p);return!w||!w.pid?Promise.reject(`Launching server using runtime ${b} failed.`):(this._serverProcess=w,w.stderr.on("data",D=>this.outputChannel.append(Ee(D)?D:D.toString(e))),d===1?(w.stdout.on("data",D=>this.outputChannel.append(Ee(D)?D:D.toString(e))),Promise.resolve({reader:new ht.IPCMessageReader(w),writer:new ht.IPCMessageWriter(w)})):Promise.resolve({reader:new ht.StreamMessageReader(w.stdout),writer:new ht.StreamMessageWriter(w.stdin)}))}else{if(d===2)return(0,ht.createClientPipeTransport)(v).then(w=>{let D=as.default.spawn(b,g,p);return!D||!D.pid?Promise.reject(`Launching server using runtime ${b} failed.`):(this._serverProcess=D,D.stderr.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),D.stdout.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),w.onConnected().then(S=>({reader:S[0],writer:S[1]})))});if(yh.isSocket(d))return(0,ht.createClientSocketTransport)(d.port).then(w=>{let D=as.default.spawn(b,g,p);return!D||!D.pid?Promise.reject(`Launching server using runtime ${b} failed.`):(this._serverProcess=D,D.stderr.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),D.stdout.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),w.onConnected().then(S=>({reader:S[0],writer:S[1]})))})}}else{let g;return new Promise((f,p)=>{let b=h.args&&h.args.slice()||[];d===1?b.push("--node-ipc"):d===0?b.push("--stdio"):d===2?(g=(0,ht.generateRandomPipeName)(),b.push(`--pipe=${g}`)):yh.isSocket(d)&&b.push(`--socket=${d.port}`),b.push(`--clientProcessId=${process.pid.toString()}`);let v=h.options||Object.create(null);if(v.env=t(v.env,!0),v.execArgv=v.execArgv||[],v.cwd=c,v.silent=!0,d===1||d===0){let w=as.default.fork(h.module,b||[],v);s(w),this._serverProcess=w,w.stderr.on("data",D=>this.outputChannel.append(Ee(D)?D:D.toString(e))),d===1?(w.stdout.on("data",D=>this.outputChannel.append(Ee(D)?D:D.toString(e))),f({reader:new ht.IPCMessageReader(this._serverProcess),writer:new ht.IPCMessageWriter(this._serverProcess)})):f({reader:new ht.StreamMessageReader(w.stdout),writer:new ht.StreamMessageWriter(w.stdin)})}else d===2?(0,ht.createClientPipeTransport)(g).then(w=>{let D=as.default.fork(h.module,b||[],v);s(D),this._serverProcess=D,D.stderr.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),D.stdout.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),w.onConnected().then(S=>{f({reader:S[0],writer:S[1]})})}):yh.isSocket(d)&&(0,ht.createClientSocketTransport)(d.port).then(w=>{let D=as.default.fork(h.module,b||[],v);s(D),this._serverProcess=D,D.stderr.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),D.stdout.on("data",S=>this.outputChannel.append(Ee(S)?S:S.toString(e))),w.onConnected().then(S=>{f({reader:S[0],writer:S[1]})})})})}}else if(x_.is(l)&&l.command){let h=l,d=h.args||[],g=Object.assign({},h.options);g.env=g.env?Object.assign({},process.env,g.env):process.env,g.cwd=g.cwd||c;let f=y.expand(l.command),p=as.default.spawn(f,d,g);return p.on("error",b=>{this.error(b.message),D_.error(b)}),!p||!p.pid?Promise.reject(`Launching server "${this.id}" using command ${h.command} failed.`):(D_.info(`Language server "${this.id}" started with ${p.pid}`),p.on("exit",b=>{b!=0&&this.error(`${h.command} exited with code: ${b}`)}),p.stderr.on("data",b=>this.outputChannel.append(Ee(b)?b:b.toString(e))),this._serverProcess=p,this._isDetached=!!g.detached,Promise.resolve({reader:new ht.StreamMessageReader(p.stdout),writer:new ht.StreamMessageWriter(p.stdin)}))}return Promise.reject(`Unsupported server configuration ${JSON.stringify(a,null,2)}`)})}_getRuntimePath(e,t){if(bh.default.isAbsolute(e))return e;let i=this._mainGetRootPath();if(i!==void 0){let r=bh.default.join(i,e);if(Iw.default.existsSync(r))return r}if(t!==void 0){let r=bh.default.join(t,e);if(Iw.default.existsSync(r))return r}return e}_mainGetRootPath(){let e=y.workspaceFolders;return!e||e.length===0?void 0:e[0].uri}registerProposedFeatures(){this.registerFeatures($Se.createAll(this))}registerBuiltinFeatures(){super.registerBuiltinFeatures();let{disabledFeatures:e}=this.clientOptions;e.includes("pullConfiguration")||this.registerFeature(new n_(this)),e.includes("typeDefinition")||this.registerFeature(new l_(this)),e.includes("implementation")||this.registerFeature(new s_(this)),e.includes("declaration")||this.registerFeature(new r_(this)),e.includes("colorProvider")||this.registerFeature(new i_(this)),e.includes("foldingRange")||this.registerFeature(new o_(this)),e.includes("selectionRange")||this.registerFeature(new h_(this)),e.includes("callHierarchy")||this.registerFeature(new d_(this)),e.includes("progress")||this.registerFeature(new a_(this)),e.includes("linkedEditing")||this.registerFeature(new f_(this)),e.includes("fileEvents")||(this.registerFeature(new p_(this)),this.registerFeature(new m_(this)),this.registerFeature(new b_(this)),this.registerFeature(new y_(this)),this.registerFeature(new v_(this)),this.registerFeature(new w_(this))),e.includes("semanticTokens")||this.registerFeature(new g_(this)),e.includes("workspaceFolders")||this.registerFeature(new c_(this))}_getServerWorkingDir(e){let t=e&&e.cwd;return t&&!bh.default.isAbsolute(t)&&(t=bh.default.join(y.cwd,t)),t||(t=y.cwd),t?new Promise(i=>{Iw.default.lstat(t,(r,o)=>{i(!r&&o.isDirectory()?t:void 0)})}):Promise.resolve(void 0)}appendOutput(e,t){let i=Ee(e)?e:e.toString(t);this.outputChannel.append(i.endsWith(` -`)?i:i+` -`)}},k_=class{constructor(e,t){this._client=e;this._setting=t;this._listeners=[]}start(){return y.onDidChangeConfiguration(e=>{e.affectsConfiguration(this._setting)&&this.onDidChangeConfiguration()},null,this._listeners),this.onDidChangeConfiguration(),{dispose:()=>{Z(this._listeners),this._client.needsStop()&&this._client.stop()}}}onDidChangeConfiguration(){let e=this._setting.indexOf("."),t=e>=0?this._setting.substr(0,e):this._setting,i=e>=0?this._setting.substr(e+1):void 0,r=i?y.getConfiguration(t).get(i,!0):y.getConfiguration(t);r&&this._client.needsStart()?this._client.start():!r&&this._client.needsStop()&&this._client.stop()}},$Se={createAll:n=>[]}});function XSe(n){switch(n){case 0:return"init";case 3:return"running";case 1:return"starting";case 2:return"startFailed";case 4:return"stopping";case 5:return"stopped";default:return"unknown"}}function USe(n){let e=n.map(t=>typeof t=="string"?t:t.language);return e=e.filter(t=>typeof t=="string"),Array.from(new Set(e))}function GSe(n,e,t){let{command:i,module:r,port:o,args:s,filetypes:a}=t;if(s=s||[],!a)return k.showMessage(`Wrong configuration of LS "${e}", filetypes not found`,"error"),null;if(!i&&!r&&!o)return k.showMessage(`Wrong configuration of LS "${e}", no command or module specified.`,"error"),null;let l;if(r){if(r=y.expand(r),!B6.default.existsSync(r))return k.showMessage(`Module file "${r}" not found for LS "${e}"`,"error"),null;l={module:r,runtime:t.runtime||process.execPath,args:s,transport:KSe(t),options:zSe(t)}}else i?l={command:i,args:s,options:VSe(t)}:o&&(l=()=>new Promise((g,f)=>{let p=new H6.default.Socket,b=t.host||"127.0.0.1";Kl.info(`languageserver "${n}" connecting to ${b}:${o}`),p.connect(o,b,()=>{g({reader:p,writer:p})}),p.on("error",v=>{f(new Error(`Connection error for ${n}: ${v.message}`))})}));let u=Array.from(t.disabledFeatures||[]);for(let g of["disableWorkspaceFolders","disableCompletion","disableDiagnostics"])if(t[g]===!0){let f=g.slice(7);u.push(f[0].toLowerCase()+f.slice(1))}let c=!!t.disableSnippetCompletion;return[{ignoredRootPaths:(t.ignoredRootPaths||[]).map(g=>y.expand(g)),disableSnippetCompletion:c,disableDynamicRegister:!!t.disableDynamicRegister,disabledFeatures:u,formatterPriority:t.formatterPriority||0,documentSelector:Y6(t.filetypes,t.additionalSchemes),revealOutputChannelOn:QSe(t.revealOutputChannelOn),synchronize:{configurationSection:`${n}.settings`},diagnosticCollectionName:e,outputChannelName:n,stdioEncoding:t.stdioEncoding||"utf8",progressOnInitialization:t.progressOnInitialization===!0,initializationOptions:t.initializationOptions||{}},l]}function QSe(n){switch(n){case"info":return 1;case"warn":return 2;case"error":return 3;case"never":return 4;default:return 4}}function Y6(n,e){let t=[],i=["file","untitled"].concat(e||[]);return n?(n.forEach(r=>{t.push(...i.map(o=>({language:r,scheme:o})))}),t):i.map(r=>({scheme:r}))}function KSe(n){let{transport:e,transportPort:t}=n;return!e||e=="ipc"?1:e=="stdio"?0:e=="pipe"?2:{kind:3,port:t}}function zSe(n){return{cwd:n.cwd,execArgv:n.execArgv||[],env:n.env||void 0}}function VSe(n){return{cwd:n.cwd,detached:!!n.detached,shell:!!n.shell,env:n.env||void 0}}function M6(n){switch(n){case 2:return"running";case 3:return"starting";case 1:return"stopped";default:return"unknown"}}var N6,B6,H6,vh,Kl,q6,Mi,$f=_(()=>{"use strict";N6=require("events"),B6=C(require("fs")),H6=C(require("net")),vh=C(H());E_();Fr();z();ke();V();Kl=q()("services");q6=class extends N6.EventEmitter{constructor(){super(...arguments);this.registered=new Map;this.disposables=[]}init(){y.onDidOpenTextDocument(e=>{this.start(e)},null,this.disposables),y.onDidChangeConfiguration(e=>{e.affectsConfiguration("languageserver")&&this.createCustomServices()},null,this.disposables),this.createCustomServices()}dispose(){this.removeAllListeners(),Z(this.disposables);for(let e of this.registered.values())e.dispose()}regist(e){let{id:t}=e;if(t||Kl.error("invalid service configuration. ",e.name),!this.registered.get(t))return this.registered.set(t,e),Kl.info(`registered service "${t}"`),this.shouldStart(e)&&e.start(),e.state==3&&this.emit("ready",t),e.onServiceReady(()=>{Kl.info(`service ${t} started`),this.emit("ready",t)},null,this.disposables),vh.Disposable.create(()=>{e.stop(),e.dispose(),this.registered.delete(t)})}getService(e){let t=this.registered.get(e);return t||(t=this.registered.get(`languageserver.${e}`)),t}shouldStart(e){if(e.state!=0)return!1;let t=e.selector;for(let i of y.documents)if(y.match(t,i.textDocument))return!0;return!1}start(e){let t=this.getServices(e);for(let i of t)i.state==0&&i.start()}getServices(e){let t=[];for(let i of this.registered.values())y.match(i.selector,e)>0&&t.push(i);return t}stop(e){let t=this.registered.get(e);if(!t){k.showMessage(`Service ${e} not found`,"error");return}return Promise.resolve(t.stop())}stopAll(){for(let e of this.registered.values())e.stop()}async toggle(e){let t=this.registered.get(e);if(!t){k.showMessage(`Service ${e} not found`,"error");return}let{state:i}=t;try{i==3?await Promise.resolve(t.stop()):i==0?await t.start():i==5&&await t.restart()}catch(r){k.showMessage(`Service error: ${r}`,"error")}}getServiceStats(){let e=[];for(let[t,i]of this.registered)e.push({id:t,languageIds:USe(i.selector),state:XSe(i.state)});return e}createCustomServices(){let e=y.getConfiguration().get("languageserver",{});for(let t of Object.keys(e)){let i=e[t];!this.validServerConfig(t,i)||this.registLanguageClient(t,i)}}validServerConfig(e,t){let i=[];return t.module!=null&&typeof t.module!="string"&&i.push(`"module" field of languageserver ${e} should be string`),t.command!=null&&typeof t.command!="string"&&i.push(`"command" field of languageserver ${e} should be string`),t.transport!=null&&typeof t.transport!="string"&&i.push(`"transport" field of languageserver ${e} should be string`),t.transportPort!=null&&typeof t.transportPort!="number"&&i.push(`"transportPort" field of languageserver ${e} should be string`),(!Array.isArray(t.filetypes)||!t.filetypes.every(r=>typeof r=="string"))&&i.push(`"filetypes" field of languageserver ${e} should be array of string`),t.additionalSchemes&&(!Array.isArray(t.additionalSchemes)||t.additionalSchemes.some(r=>typeof r!="string"))&&i.push(`"additionalSchemes" field of languageserver ${e} should be array of string`),i.length?(k.showMessage(i.join(` -`),"error"),!1):!0}waitClient(e){let t=this.getService(e);return t&&t.state==3?Promise.resolve():t?new Promise(i=>{t.onServiceReady(()=>{i()})}):new Promise(i=>{let r=o=>{(o==e||o==`languageserver.${e}`)&&(this.off("ready",r),i())};this.on("ready",r)})}async registNotification(e,t){await this.waitClient(e);let i=this.getService(e);if(!i.client){k.showMessage(`Not a language client: ${e}`,"error");return}i.client.onNotification(t,async o=>{y.nvim.call("coc#do_notify",[e,t,o],!0)})}async sendNotification(e,t,i){if(!t)throw new Error("method required for ontification");let r=this.getService(e);if(!r||!r.client)throw new Error(`Language server ${e} not found`);if(r.state==1&&await r.client.onReady(),r.state!=3)throw new Error(`Language server ${e} not running`);await Promise.resolve(r.client.sendNotification(t,i))}async sendRequest(e,t,i,r){if(!t)throw new Error("method required for sendRequest");let o=this.getService(e);if(o||await bt(100),o=this.getService(e),!o||!o.client)throw new Error(`Language server ${e} not found`);if(o.state==1&&await o.client.onReady(),o.state!=3)throw new Error(`Language server ${e} not running`);return r||(r=new vh.CancellationTokenSource().token),await Promise.resolve(o.client.sendRequest(t,i,r))}registLanguageClient(e,t){let i=typeof e=="string"?`languageserver.${e}`:e.id,r=[],o=new vh.Emitter,s=typeof e=="string"?null:e;if(this.registered.has(i))return;let a=!1,l={id:i,client:s,name:typeof e=="string"?e:e.name,selector:typeof e=="string"?Y6(t.filetypes,t.additionalSchemes):e.clientOptions.documentSelector,state:0,onServiceReady:o.event,start:()=>{if(l.state==1||l.state==3||s&&!s.needsStart())return;if(a&&s)return s.restart(),Promise.resolve();if(!a){if(typeof e=="string"&&!s){let c=y.getConfiguration().get("languageserver",{})[e];if(!c||c.enable===!1)return;let h=GSe(i,e,c);if(!h)return;s=new Jf(i,e,h[1],h[0]),l.selector=h[0].documentSelector,l.client=s}s.onDidChangeState(c=>{let{oldState:h,newState:d}=c;d==3?l.state=1:d==2?l.state=3:d==1&&(l.state=5);let g=M6(h),f=M6(d);Kl.info(`${s.name} state change: ${g} => ${f}`)},null,r),a=!0}l.state=1,Kl.debug(`starting service: ${i}`);let u=s.start();return r.push(u),new Promise(c=>{s.onReady().then(()=>{o.fire(void 0),c()},h=>{k.showMessage(`Server ${i} failed to start: ${h}`,"error"),Kl.error(`Server ${i} failed to start:`,h),l.state=2,c()})})},dispose:async()=>{o.dispose(),Z(r)},stop:async()=>{!s||!s.needsStop()||await Promise.resolve(s.stop())},restart:async()=>{s?(l.state=1,s.restart()):await l.start()}};return this.regist(l)}};Mi=new q6});var W6,zl,wh,Aw=_(()=>{"use strict";V();ke();W6=require("events"),zl=["","","","","","","","","","","","","","","","","","","","<2-LeftMouse>","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],wh=class extends W6.EventEmitter{constructor(){super();this.configuration=y.getConfiguration("list"),this.disposable=y.onDidChangeConfiguration(e=>{e.affectsConfiguration("list")&&(this.configuration=y.getConfiguration("list"),this.emit("change"))})}get(e,t){return this.configuration.get(e,t)}get previousKey(){return this.fixKey(this.configuration.get("previousKeymap",""))}get nextKey(){return this.fixKey(this.configuration.get("nextKeymap",""))}dispose(){this.disposable.dispose(),this.removeAllListeners()}fixKey(e){if(zl.includes(e))return e;let t=zl.find(i=>i.toLowerCase()==e.toLowerCase());return t||(k.showMessage(`Configured key "${e}" not supported.`,"error"),null)}}});var J$e,Ow,Z6=_(()=>{"use strict";ke();Aw();J$e=q()("list-mappings"),Ow=class{constructor(e,t,i){this.manager=e;this.nvim=t;this.config=i;this.insertMappings=new Map;this.normalMappings=new Map;this.userInsertMappings=new Map;this.userNormalMappings=new Map;this.actions=new Map;let{prompt:r}=e;this.addAction("do:switch",async()=>{await e.switchMatcher()}),this.addAction("do:selectall",async()=>{var o;await((o=e.session)==null?void 0:o.ui.selectAll())}),this.addAction("do:help",async()=>{var o;await((o=e.session)==null?void 0:o.showHelp())}),this.addAction("do:refresh",async()=>{var o;await((o=e.session)==null?void 0:o.reloadItems())}),this.addAction("do:exit",async()=>{await e.cancel()}),this.addAction("do:stop",()=>{e.stop()}),this.addAction("do:cancel",async()=>{await e.cancel(!1)}),this.addAction("do:toggle",async()=>{var o;await((o=e.session)==null?void 0:o.ui.toggleSelection())}),this.addAction("do:jumpback",()=>{var o;(o=e.session)==null||o.jumpBack()}),this.addAction("do:previous",async()=>{await e.normal("k")}),this.addAction("do:next",async()=>{await e.normal("j")}),this.addAction("do:defaultaction",async()=>{await e.doAction()}),this.addAction("do:chooseaction",async()=>{await e.chooseAction()}),this.addAction("do:togglemode",()=>{e.toggleMode()}),this.addAction("do:previewtoggle",async()=>{await e.togglePreview()}),this.addAction("do:previewup",()=>{this.scrollPreview("up")}),this.addAction("do:previewdown",()=>{this.scrollPreview("down")}),this.addAction("do:command",async()=>{await e.cancel(!1),await t.eval('feedkeys(":")')}),this.addAction("prompt:previous",()=>{var o;(o=e.session)==null||o.history.previous()}),this.addAction("prompt:next",()=>{var o;(o=e.session)==null||o.history.next()}),this.addAction("prompt:start",()=>{r.moveToStart()}),this.addAction("prompt:end",()=>{r.moveToEnd()}),this.addAction("prompt:left",()=>{r.moveLeft()}),this.addAction("prompt:right",()=>{r.moveRight()}),this.addAction("prompt:deleteforward",()=>{r.onBackspace()}),this.addAction("prompt:deletebackward",()=>{r.removeNext()}),this.addAction("prompt:removetail",()=>{r.removeTail()}),this.addAction("prompt:removeahead",()=>{r.removeAhead()}),this.addAction("prompt:removeword",()=>{r.removeWord()}),this.addAction("prompt:insertregister",()=>{r.insertRegister()}),this.addAction("prompt:paste",async()=>{await r.paste()}),this.addAction("eval",async o=>{await r.eval(o)}),this.addAction("command",async o=>{await e.command(o)}),this.addAction("action",async o=>{await e.doAction(o)}),this.addAction("feedkeys",async o=>{await e.feedkeys(o)}),this.addAction("normal",async o=>{await e.normal(o,!1)}),this.addAction("normal!",async o=>{await e.normal(o,!0)}),this.addAction("call",async o=>{await e.call(o)}),this.addAction("expr",async o=>{let s=await e.call(o);s&&await e.doAction(s)}),this.addKeyMapping("insert","","do:switch"),this.addKeyMapping("insert","","prompt:next"),this.addKeyMapping("insert","","prompt:previous"),this.addKeyMapping("insert","","prompt:paste"),this.addKeyMapping("insert",["",""],"do:defaultaction"),this.addKeyMapping("insert",["",""," "],"do:chooseaction"),this.addKeyMapping("insert","","do:togglemode"),this.addKeyMapping("insert","","do:stop"),this.addKeyMapping("insert","","do:refresh"),this.addKeyMapping("insert","","prompt:left"),this.addKeyMapping("insert","","prompt:right"),this.addKeyMapping("insert",["",""],"prompt:end"),this.addKeyMapping("insert",["",""],"prompt:start"),this.addKeyMapping("insert",["","",""],"prompt:deleteforward"),this.addKeyMapping("insert","","prompt:removeword"),this.addKeyMapping("insert","","prompt:removeahead"),this.addKeyMapping("insert","","prompt:insertregister"),this.addKeyMapping("normal","t","action:tabe"),this.addKeyMapping("normal","s","action:split"),this.addKeyMapping("normal","d","action:drop"),this.addKeyMapping("normal",["","","\r"],"do:defaultaction"),this.addKeyMapping("normal","","do:selectall"),this.addKeyMapping("normal"," ","do:toggle"),this.addKeyMapping("normal","p","do:previewtoggle"),this.addKeyMapping("normal",[""," ",""],"do:chooseaction"),this.addKeyMapping("normal","","do:stop"),this.addKeyMapping("normal","","do:refresh"),this.addKeyMapping("normal","","do:jumpback"),this.addKeyMapping("normal","","do:previewdown"),this.addKeyMapping("normal","","do:previewup"),this.addKeyMapping("normal",["i","I","o","O","a","A"],"do:togglemode"),this.addKeyMapping("normal","?","do:help"),this.addKeyMapping("normal",":","do:command"),this.createMappings(),i.on("change",()=>{this.createMappings()})}createMappings(){let e=this.config.get("insertMappings",{});this.userInsertMappings=this.fixUserMappings(e,"list.insertMappings");let t=this.config.get("normalMappings",{});this.userNormalMappings=this.fixUserMappings(t,"list.normalMappings")}hasUserMapping(e,t){return(e=="insert"?this.userInsertMappings:this.userNormalMappings).has(t)}isValidAction(e){if(this.actions.has(e))return!0;let[t,i]=e.split(":",2);return!(!i||!this.actions.has(t))}fixUserMappings(e,t){let i=new Map;for(let[r,o]of Object.entries(e)){if(!this.isValidAction(o)){k.showMessage(`Invalid configuration - unable to support action "${o}" in "${t}"`,"warning");continue}if(r.length==1)i.set(r,o);else if(r.startsWith("<")&&r.endsWith(">"))if(r.toLowerCase()=="")i.set(" ",o);else if(r.toLowerCase()=="")i.set("",o);else if(zl.includes(r))i.set(r,o);else{let s=!1;for(let a=0;athis.doAction(e);let[t,i]=e.split(":",2);if(!i||!this.actions.has(t))throw new Error(`Invalid action ${e}`);return()=>this.doAction(t,i)}async doAction(e,t){let i=this.actions.get(e);if(!i)throw new Error(`Action ${e} doesn't exist`);await Promise.resolve(i(t))}scrollPreview(e){let{nvim:t}=this;t.pauseNotification(),t.call("coc#list#scroll_preview",[e],!0),t.command("redraw",!0),t.resumeNotification(!1,!0)}}});var J6,U$e,Mw,$6=_(()=>{"use strict";J6=C(H()),U$e=q()("list-prompt"),Mw=class{constructor(e,t){this.nvim=e;this.config=t;this.cusorIndex=0;this._input="";this._mode="insert";this.interactive=!1;this.requestInput=!1;this._onDidChangeInput=new J6.Emitter;this.onDidChangeInput=this._onDidChangeInput.event}get input(){return this._input}set input(e){this._input!=e&&(this.cusorIndex=e.length,this._input=e,this.drawPrompt(),this._onDidChangeInput.fire(this._input))}get mode(){return this._mode}set mode(e){e!=this._mode&&(this._mode=e,this.drawPrompt())}set matcher(e){this._matcher=e,this.drawPrompt()}start(e){e&&(this.interactive=e.interactive,this.cusorIndex=e.input.length,this._input=e.input,this._mode=e.mode,this._matcher=e.interactive?"":e.matcher),this.nvim.call("coc#prompt#start_prompt",["list"],!0),this.drawPrompt()}cancel(){let{nvim:e}=this;e.call("coc#prompt#stop_prompt",["list"],!0)}reset(){this._input="",this.cusorIndex=0}drawPrompt(){let e=this.config.get("indicator",">"),{cusorIndex:t,interactive:i,input:r,_matcher:o}=this,s=['echo ""'];if(this.mode=="insert")if(i?s.push("echohl MoreMsg | echon 'INTERACTIVE ' | echohl None"):o&&s.push(`echohl MoreMsg | echon '${o.toUpperCase()} ' | echohl None`),s.push(`echohl Special | echon '${e} ' | echohl None`),t==r.length)s.push(`echon '${r.replace(/'/g,"''")}'`),s.push("echohl Cursor | echon ' ' | echohl None");else{let l=r.slice(0,t);l&&s.push(`echon '${l.replace(/'/g,"''")}'`),s.push(`echohl Cursor | echon '${r[t].replace(/'/,"''")}' | echohl None`);let u=r.slice(t+1);s.push(`echon '${u.replace(/'/g,"''")}'`)}else s.push('echohl MoreMsg | echo "" | echohl None');s.push("redraw");let a=s.join("|");this.nvim.command(a,!0)}moveLeft(){this.cusorIndex!=0&&(this.cusorIndex=this.cusorIndex-1,this.drawPrompt())}moveRight(){this.cusorIndex!=this._input.length&&(this.cusorIndex=this.cusorIndex+1,this.drawPrompt())}moveToEnd(){this.cusorIndex!=this._input.length&&(this.cusorIndex=this._input.length,this.drawPrompt())}moveToStart(){this.cusorIndex!=0&&(this.cusorIndex=0,this.drawPrompt())}onBackspace(){let{cusorIndex:e,input:t}=this;if(e==0)return;let i=t.slice(0,e),r=t.slice(e);this.cusorIndex=e-1,this._input=`${i.slice(0,i.length-1)}${r}`,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}removeNext(){let{cusorIndex:e,input:t}=this;if(e==t.length-1)return;let i=t.slice(0,e),r=t.slice(e+1);this._input=`${i}${r}`,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}removeWord(){let{cusorIndex:e,input:t}=this;if(e==0)return;let i=t.slice(0,e),r=t.slice(e),o=i.replace(/[\w$]+([^\w$]+)?$/,"");this.cusorIndex=e-(i.length-o.length),this._input=`${o}${r}`,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}removeTail(){let{cusorIndex:e,input:t}=this;if(e==t.length)return;let i=t.slice(0,e);this._input=i,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}removeAhead(){let{cusorIndex:e,input:t}=this;if(e==0)return;let i=t.slice(e);this.cusorIndex=0,this._input=i,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}async acceptCharacter(e){if(this.requestInput){if(this.requestInput=!1,/^[0-9a-z"%#*+/:\-.]$/.test(e)){let t=await this.nvim.call("getreg",e);t=t.replace(/\n/g," "),this.addText(t)}}else this.addText(e)}insertRegister(){this.requestInput=!0}async paste(){let e=await this.nvim.eval("@*");e=e.replace(/\n/g,""),e&&this.addText(e)}async eval(e){let t=await this.nvim.call("eval",[e]);t=t.replace(/\n/g,""),this.addText(t)}addText(e){let{cusorIndex:t,input:i}=this;this.cusorIndex=t+e.length;let r=i.slice(0,t),o=i.slice(t);this._input=`${r}${e}${o}`,this.drawPrompt(),this._onDidChangeInput.fire(this._input)}}});function xn(n){let e=[];for(let t=0,i=n.length;t=97&&n<=122||n>=65&&n<=90}function Nw(n,e,t=!1){return!!(n==e||n>=97&&n<=122&&e+32===n||t&&n<=90&&n+32===e)}function Xf(n,e){let t=n.charCodeAt(0),i=e.charCodeAt(0);return t===i||t>=97&&t<=122&&i+32===t}function mo(n,e){let t=n.length;if(n.length>e.length)return!1;let i=0;for(let r=0;r=97&&s<=122&&o+32===s){i=i+1;continue}}return i===t}var ls=_(()=>{"use strict"});var V$e,Bw,U6=_(()=>{"use strict";ls();V();V$e=q()("list-history"),Bw=class{constructor(e,t){this.prompt=e;this.name=t;this.index=-1;this.loaded=[];this.current=[];this.db=y.createDatabase(`list-${t}-history`),this.key=Buffer.from(y.cwd).toString("base64")}filter(){let{input:e}=this.prompt;if(e==this.curr)return;this.historyInput="";let t=xn(e);this.current=this.loaded.filter(i=>mo(t,i)),this.index=-1}get curr(){return this.index==-1?null:this.current[this.index]}load(e){let{db:t}=this;e=e||"";let i=t.fetch(this.key);!i||!Array.isArray(i)?this.loaded=[]:this.loaded=i,this.index=-1,this.current=this.loaded.filter(r=>r.startsWith(e))}add(){let{loaded:e,db:t,prompt:i}=this,{input:r}=i;if(!r||r.length<2||r==this.historyInput)return;let o=e.indexOf(r);o!=-1&&e.splice(o,1),e.push(r),e.length>200&&(e=e.slice(-200)),t.push(this.key,e)}previous(){let{current:e,index:t}=this;!e||!e.length||(t<=0?this.index=e.length-1:this.index=t-1,this.historyInput=this.prompt.input=e[this.index]||"")}next(){let{current:e,index:t}=this;!e||!e.length||(t==e.length-1?this.index=0:this.index=t+1,this.historyInput=this.prompt.input=e[this.index]||"")}}});var G6,Dh,aXe,Hw,Q6=_(()=>{"use strict";G6=C(Ei()),Dh=C(H());le();z();io();V();aXe=q()("list-ui"),Hw=class{constructor(e,t,i,r){this.nvim=e;this.name=t;this.listOptions=i;this.config=r;this.newTab=!1;this.reversed=!1;this.currIndex=0;this.items=[];this.disposables=[];this.selected=new Set;this.mutex=new ei;this._onDidChangeLine=new Dh.Emitter;this._onDidOpen=new Dh.Emitter;this._onDidClose=new Dh.Emitter;this._onDidLineChange=new Dh.Emitter;this._onDoubleClick=new Dh.Emitter;this.onDidChangeLine=this._onDidChangeLine.event;this.onDidLineChange=this._onDidLineChange.event;this.onDidOpen=this._onDidOpen.event;this.onDidClose=this._onDidClose.event;this.onDidDoubleClick=this._onDoubleClick.event;this.signOffset=r.get("signOffset"),this.newTab=i.position=="tab",this.reversed=i.reverse===!0,E.on("BufWinLeave",async s=>{s!=this.bufnr||this.window==null||(this.window=null,this._onDidClose.fire(s))},null,this.disposables),E.on("CursorMoved",async(s,a)=>{if(s!=this.bufnr)return;let l=this.lnumToIndex(a[0]);this.onLineChange(l)},null,this.disposables);let o=(0,G6.default)(async s=>{if(s!=this.bufnr)return;let[a,l,u]=await e.eval('[win_getid(),line("w0"),line("w$")]');if(u<300||a!=this.winid)return;let c=u-l+1,h=this.lnumToIndex(l),d=this.lnumToIndex(l+c*2);e.pauseNotification(),this.doHighlight(h,d),e.command("redraw",!0),e.resumeNotification(!1,!0)},global.hasOwnProperty("__TEST__")?20:100);this.disposables.push({dispose:()=>{o.clear()}}),E.on("CursorMoved",o,null,this.disposables)}lnumToIndex(e){let{reversed:t,length:i}=this;return t?Math.max(0,i-e):e-1}indexToLnum(e){let{reversed:t,length:i}=this;return t?Math.max(Math.min(i,i-e),1):Math.min(e+1,i)}get bufnr(){var e;return(e=this.buffer)==null?void 0:e.id}get winid(){var e;return(e=this.window)==null?void 0:e.id}get limitLines(){return this.config.get("limitLines",1/0)}onLineChange(e){this.currIndex!=e&&(this.currIndex=e,this._onDidChangeLine.fire(e))}set index(e){if(e<0||e>=this.items.length)return;let{nvim:t}=this,i=this.indexToLnum(e);t.pauseNotification(),this.setCursor(i),t.command("redraw",!0),t.resumeNotification(!1,!0)}get index(){return this.currIndex}getItem(e){return this.items[e]}get item(){let{window:e}=this;return e?e.cursor.then(t=>(this.currIndex=this.lnumToIndex(t[0]),this.items[this.currIndex])):Promise.resolve(null)}async echoMessage(e){let{items:t}=this,r=`[${t.indexOf(e)+1}/${t.length}] ${e.label||""}`;this.nvim.callTimer("coc#ui#echo_lines",[[r]],!0)}updateItem(e,t,i){if(!this.buffer||t>=this.length)return;let r=this.items[t];if(Object.assign(r,e,{resolved:!0}),!i)return;let{nvim:o}=this,s=this.indexToLnum(t);o.pauseNotification(),this.buffer.setOption("modifiable",!0,!0),o.call("setbufline",[this.bufnr,s,r.label],!0),this.doHighlight(t,t+1),this.buffer.setOption("modifiable",!1,!0),o.resumeNotification(!0,!0)}async getItems(){if(this.length==0||!this.window)return[];let e=await this.nvim.call("mode");if(e=="v"||e=="V"){let[r,o]=await this.getSelectedRange(),s=[];for(let a=r;a<=o;a++){let l=this.lnumToIndex(a),u=this.items[l];u&&s.push(u)}return s}let{selectedItems:t}=this;if(t.length)return t;let i=await this.item;return i==null?[]:[i]}async onMouse(e){let{nvim:t,window:i}=this;if(!i)return;let[r,o,s]=await t.eval("[v:mouse_winid,v:mouse_lnum,v:mouse_col]");if(e=="mouseDown"){this.mouseDown={winid:r,lnum:o,col:s,current:r==i.id};return}let a=r==i.id;if(a&&e=="doubleClick"&&(this.setCursor(o),this._onDoubleClick.fire()),a&&e=="mouseDrag"){if(!this.mouseDown)return;await this.selectLines(this.mouseDown.lnum,o)}else if(a&&e=="mouseUp"){if(!this.mouseDown)return;this.mouseDown.lnum==o?(this.setCursor(o),t.command("redraw",!0)):await this.selectLines(this.mouseDown.lnum,o)}else!a&&e=="mouseUp"&&(t.pauseNotification(),t.call("win_gotoid",r,!0),t.call("cursor",[o,s],!0),t.command("redraw",!0),t.resumeNotification(!1,!0))}async resume(){var r;let{items:e,selected:t,nvim:i}=this;if(await this.drawItems(e,this.height,!0),!(!t.size||!this.buffer)){i.pauseNotification();for(let o of t)(r=this.buffer)==null||r.placeSign({lnum:o,id:this.signOffset+o,name:"CocSelected",group:"coc-list"});i.command("redraw",!0),i.resumeNotification(!1,!0)}}async toggleSelection(){let{nvim:e,reversed:t}=this;await e.call("win_gotoid",[this.winid]);let i=await e.call("line","."),r=await e.call("mode");if(r=="v"||r=="V"){let[o,s]=await this.getSelectedRange();o>s&&([o,s]=[s,o]);for(let l=o;l<=s;l++)this.toggleLine(l);this.setCursor(s),e.command("redraw",!0),await e.resumeNotification();return}e.pauseNotification(),this.toggleLine(i),this.setCursor(t?i-1:i+1),e.command("redraw",!0),await e.resumeNotification()}toggleLine(e){let{selected:t,buffer:i,signOffset:r}=this;t.has(e)?(t.delete(e),i.unplaceSign({id:r+e,group:"coc-list"})):(t.add(e),i.placeSign({lnum:e,id:r+e,name:"CocSelected",group:"coc-list"}))}async selectLines(e,t){let{nvim:i,signOffset:r,buffer:o,length:s}=this;this.clearSelection();let{selected:a}=this;i.pauseNotification(),e>t&&([e,t]=[t,e]);for(let u=e;u<=t&&!(u>s);u++)a.add(u),o.placeSign({lnum:u,id:r+u,name:"CocSelected",group:"coc-list"});this.setCursor(t),i.command("redraw",!0),await i.resumeNotification()}async selectAll(){let{length:e}=this;e>0&&await this.selectLines(1,e)}clearSelection(){let{selected:e,buffer:t}=this;e.size>0&&(t==null||t.unplaceSign({group:"coc-list"}),this.selected.clear())}get ready(){return this.window?Promise.resolve():new Promise(e=>{let t=this.onDidLineChange(()=>{t.dispose(),e()})})}async drawItems(e,t,i=!1){let{nvim:r,name:o,listOptions:s}=this;await this.mutex.use(async()=>{if(this.items=e.length>this.limitLines?e.slice(0,this.limitLines):e,!this.window){let{position:c,numberSelect:h}=s,[d,g,f]=await r.call("coc#list#create",[c,t,o,h]);this.tabnr=f,this.height=t,this.buffer=r.createBuffer(d);let p=this.window=r.createWindow(g),b=this.config.get("statusLineSegments");b&&p.setOption("statusline",b.join(" "),!0),this._onDidOpen.fire(this.bufnr)}let a=[],l=0;this.items.forEach((c,h)=>{a.push(c.label),!i&&l==0&&c.preselect&&(l=h)});let u=i?this.currIndex:l;this.setLines(a,0,u),this._onDidLineChange.fire()})}async appendItems(e){!this.window||e.length===0||await this.mutex.use(async()=>{let t=this.items.length,i=this.limitLines-t;if(i>0){let r=io.label),r.length,this.currIndex)}})}setLines(e,t,i){let{nvim:r,buffer:o,window:s,reversed:a,newTab:l}=this;if(!(!o||!s)){if(r.pauseNotification(),t||(r.call("coc#compat#clear_matches",[s.id],!0),e.length||(e=["No results, press ? on normal mode to get help."],r.call("coc#compat#matchaddpos",["Comment",[[1]],99,s.id],!0))),o.setOption("modifiable",!0,!0),a){let u=e.reverse();t?r.call("coc#compat#prepend_lines",[o.id,u],!0):o.setLines(u,{start:0,end:-1,strictIndexing:!1},!0)}else o.setLines(e,{start:t?-1:0,end:-1,strictIndexing:!1},!0);if(o.setOption("modifiable",!1,!0),a&&!l){let u=this.config.get("height",10);r.call("coc#window#set_height",[s.id,Math.max(Math.min(u,this.length),1)],!0)}if(i>this.items.length-1&&(i=0),i==0)if(t==0)this.doHighlight(0,299);else{let u=this.length-t-1;u<300&&this.doHighlight(u,Math.min(299,this.length-1))}else{let u=l?y.env.lines:this.height;this.doHighlight(Math.max(0,i-u),Math.min(i+u+1,this.length-1))}if(!t){this.currIndex=i;let u=this.indexToLnum(i);s.setCursor([u,0],!0),r.call("coc#list#select",[o.id,u],!0)}a&&r.command("normal! zb",!0),r.command("redraws",!0),r.resumeNotification(!0,!0)}}restoreWindow(){if(this.newTab)return;let{winid:e,height:t}=this;e&&t&&this.nvim.call("coc#window#set_height",[e,t],!0)}get length(){return this.items.length}get selectedItems(){let{selected:e,items:t}=this,i=[];for(let r of e){let o=this.lnumToIndex(r);t[r-1]&&i.push(t[o])}return i}doHighlight(e,t){let{items:i,reversed:r,length:o,buffer:s}=this;if(!s)return;let a=[],l=u=>{let c=this.indexToLnum(u)-1,{ansiHighlights:h,highlights:d}=i[u];if(h)for(let g of h){let{span:f,hlGroup:p}=g;a.push({hlGroup:p,lnum:c,colStart:f[0],colEnd:f[1]})}if(d&&Array.isArray(d.spans)){let{spans:g,hlGroup:f}=d;for(let p of g)f=f!=null?f:"CocListSearch",a.push({hlGroup:f,lnum:c,colStart:p[0],colEnd:p[1]})}};if(r)for(let u=Math.min(t,o-1);u>=e;u--)l(u);else for(let u=e;u<=Math.min(t,o-1);u++)l(u);e=this.indexToLnum(e)-1,t=this.indexToLnum(t)-1,e>t&&([e,t]=[t,e]),a.length!=0&&s.updateHighlights("list",a,{start:e,end:t+1,priority:99})}setCursor(e,t=0){var s;let{items:i}=this,r=i.length==0?1:i.length;if(e>r)return;let o=this.lnumToIndex(e);this.onLineChange(o),(s=this.window)==null||s.setCursor([e,t],!0),this.nvim.call("coc#list#select",[this.bufnr,e],!0)}moveUp(){let{index:e,reversed:t}=this;this.index=t?e+1:e-1}moveDown(){let{index:e,reversed:t}=this;this.index=t?e-1:e+1}async getSelectedRange(){let{nvim:e}=this;await e.call("coc#prompt#stop_prompt",["list"]),await e.eval('feedkeys("\\", "in")');let[,t]=await e.call("getpos","'<"),[,i]=await e.call("getpos","'>");return this.nvim.call("coc#prompt#start_prompt",["list"],!0),[t,i]}reset(){this.window&&(this.window=null,this.buffer=null,this.tabnr=void 0)}dispose(){Z(this.disposables),this.nvim.call("coc#window#close",[this.winid||-1],!0),this.window=null,this.buffer=null,this.items=[],this._onDidChangeLine.dispose(),this._onDidOpen.dispose(),this._onDidClose.dispose(),this._onDidLineChange.dispose(),this._onDoubleClick.dispose()}}});async function qw(n,e,t,i){if(n.length===0)return;let r=new z6,o=n.length;function s(l){let u=[];r.start();for(let c=l;c{setImmediate(()=>{l(s(a))})})}var K6,z6,V6=_(()=>{K6=15,z6=class{constructor(e=K6){this.yieldAfter=Math.max(e,K6),this.startTime=Date.now(),this.counter=0,this.total=0,this.counterInterval=1}start(){this.startTime=Date.now()}shouldYield(){if(++this.counter>=this.counterInterval){let e=Date.now()-this.startTime,t=Math.max(0,this.yieldAfter-e);if(this.total+=this.counter,this.counter=0,e>=this.yieldAfter||t<=1)return this.counterInterval=1,this.total=0,!0;switch(e){case 0:case 1:this.counterInterval=this.total*2;break}}return!1}}});function l0e(n){return n.toLowerCase()===n}function u0e(n){return n.toUpperCase()===n}function c0e(n){let e=n.length,t=new Array(e),i="/";for(let r=0;r1024)return xh;let r=new Array(t),o=new Array(t);return t4(n,e,r,o),o[t-1][i-1]}function i4(n){let e=[];for(let t=0;t1024)return r;let o=new Array(t),s=new Array(t);t4(n,e,o,s);let a=!1;for(let l=t-1,u=i-1;l>=0;l--)for(;u>=0;u--)if(o[l][u]!==xh&&(a||o[l][u]===s[l][u])){a=l&&u&&s[l][u]===o[l-1][u-1]+e4,r[l]=u--;break}return r}function Sh(n,e){n=n.toLowerCase(),e=e.toLowerCase();let t=n.length;for(let i=0,r=0;i{"use strict";xh=-1/0,e0e=1/0,t0e=-.005,i0e=-.005,n0e=-.01,e4=1,r0e=.9,o0e=.8,s0e=.7,a0e=.6});function n4(n,e,t=""){if(!n)return{score:0};if(!e)return{score:1};let i=[],r=xn(e),o=t?n.indexOf(t):-1,s=o!=-1&&mo(r,t),a=0,l=e[0],u=0,c=n[0];if(s){if(t.startsWith(l))a=a+2,u=o+1,i.push(o);else if(t[0].toLowerCase()==l)a=a+1.5,u=o+1,i.push(o);else for(let h=1;he.score&&(e=n[t]);return e}var P_,o4=_(()=>{"use strict";P_=require("path");ls()});function Yw(n){return n.filterText!=null?FY(n.filterText,n.label):n.label}function g0e(n){let e=[],t=0,i=0,r="";for(;io.replace(/\\\s/g," ").trim()).filter(o=>o.length>0)}function a4(n,e){let t=[];if(e&&e.length){let i=e.shift(),r=e.shift(),o=i;for(;r;){if(r==o+1){o=r,r=e.shift();continue}t.push([Ze(n,i),Ze(n,o)+1]),i=r,o=i,r=e.shift()}t.push([Ze(n,i),Ze(n,o)+1])}return{spans:t}}function __(n,e){let t=Yw(e),i=n4(t,n);return i!=null&&i.score?a4(t,i.matches):{spans:[]}}var Ra,s4,d0e,Ww,l4=_(()=>{"use strict";Ra=C(H());bc();V6();XT();Uf();io();o4();Pe();s4=q()("list-worker"),d0e="\x1B",Ww=class{constructor(e,t,i,r,o){this.nvim=e;this.list=t;this.prompt=i;this.listOptions=r;this.config=o;this._loading=!1;this._finished=!1;this.mutex=new ei;this.totalItems=[];this._onDidChangeItems=new Ra.Emitter;this._onDidChangeLoading=new Ra.Emitter;this.onDidChangeItems=this._onDidChangeItems.event;this.onDidChangeLoading=this._onDidChangeLoading.event}set loading(e){this._loading!=e&&(this._loading=e,this._onDidChangeLoading.fire(e))}get isLoading(){return this._loading}async loadItems(e,t=!1){this.cancelFilter(),this.filteredCount=0,this._finished=!1;let{list:i,listOptions:r}=this;this.loading=!0;let{interactive:o}=r;this.tokenSource=new Ra.CancellationTokenSource;let s=this.tokenSource.token,a=await i.loadItems(e,s);if(!s.isCancellationRequested)if(a=a!=null?a:[],Array.isArray(a)){this.tokenSource=null,this.totalItems=a,this.loading=!1,this._finished=!0;let l;if(o)l=this.convertToHighlightItems(a),this._onDidChangeItems.fire({items:l,reload:t,finished:!0});else{let u=this.filterTokenSource=new Ra.CancellationTokenSource;await this.mutex.use(async()=>{let c=u.token;c.isCancellationRequested||await this.filterItems(a,{reload:t},c)})}}else{let l=a,u=this.totalItems=[],c=0,h=e.input,d=!1;this.filterTokenSource=new Ra.CancellationTokenSource;let g=async w=>{d=!0,await this.mutex.use(async()=>{var L;if(this.input!=h&&(h=this.input,c=(L=this.filteredCount)!=null?L:0),c>=u.length)return;let S=c>0,F=u.slice(c);if(c=u.length,o){let j=this.convertToHighlightItems(F);this._onDidChangeItems.fire({items:j,append:S,reload:t,finished:w})}else{let j=this.filterTokenSource;j&&!j.token.isCancellationRequested&&await this.filterItems(F,{append:S,reload:t},j.token)}}),d=!1},f=Promise.resolve(),p=setInterval(()=>{d||(f=g())},50);l.on("data",w=>{s.isCancellationRequested||u.push(w)});let b=()=>{l!=null&&(this.tokenSource=null,l=null,this.loading=!1,this._finished=!0,v.dispose(),clearInterval(p),f.then(()=>{if(!s.isCancellationRequested){if(u.length==0){this._onDidChangeItems.fire({items:[],append:!1,reload:t,finished:!0});return}return g(!0)}}).catch(w=>{s4.error("Error on filter",w)}))},v=s.onCancellationRequested(()=>{l==null||l.dispose(),b()});l.on("error",async w=>{l!=null&&(l=null,this.tokenSource=null,this.loading=!1,v.dispose(),clearInterval(p),this.nvim.call("coc#prompt#stop_prompt",["list"],!0),this.nvim.echoError(`Task error: ${w.toString()}`),s4.error("Task error:",w))}),l.on("end",b)}}async drawItems(){let{totalItems:e}=this;if(e.length===0)return;this.cancelFilter();let t=this.filterTokenSource=new Ra.CancellationTokenSource,i=t.token;await this.mutex.use(async()=>{if(i.isCancellationRequested)return;let{totalItems:r}=this;this.filteredCount=r.length,await this.filterItems(r,{},t.token)})}cancelFilter(){this.filterTokenSource&&(this.filterTokenSource.cancel(),this.filterTokenSource=null)}stop(){this.cancelFilter(),this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource=null),this.loading=!1}get length(){return this.totalItems.length}get input(){return this.prompt.input}convertToHighlightItems(e){var r;let t=(r=this.input)!=null?r:"";return e.map(o=>{this.convertItemLabel(o);let s=t.length>0?__(t,o):void 0;return Object.assign({},o,{highlights:s})})}async filterItemsByInclude(e,t,i,r){let{ignorecase:o}=this.listOptions;o&&(e=e.map(s=>s.toLowerCase())),await qw(t,s=>{this.convertItemLabel(s);let a=[],l=Yw(s),u=!0;for(let c of e){let h=o?l.toLowerCase().indexOf(c):l.indexOf(c);if(h==-1){u=!1;break}a.push([Ze(l,h),Ze(l,h+Q(c))])}return u?{highlights:{spans:a}}:!1},r,i)}async filterItemsByRegex(e,t,i,r){let{ignorecase:o}=this.listOptions,s=o?"iu":"u",a=e.reduce((l,u)=>{try{l.push(new RegExp(u,s))}catch{}return l},[]);await qw(t,l=>{this.convertItemLabel(l);let u=[],c=Yw(l),h=!0;for(let d of a){let g=c.match(d);if(g==null){h=!1;break}u.push([Ze(c,g.index),Ze(c,g.index+Q(g[0]))])}return h?{highlights:{spans:u}}:!1},r,i)}async filterItemsByFuzzyMatch(e,t,i,r){let{sort:o}=this.listOptions,s=0;await qw(t,a=>{this.convertItemLabel(a);let l=a.filterText||a.label,u=0,c=[],h=Yw(a),d=!0;for(let g of e){if(!Sh(g,l)){d=!1;break}c.push(...Vl(g,h)),o&&(u+=Ch(g,l))}return s=s+1,d?{sortText:typeof a.sortText=="string"?a.sortText:String.fromCharCode(s),score:u,highlights:a4(h,c)}:!1},(a,l)=>{r(a,l,o)},i)}async filterItems(e,t,i){let{input:r}=this;if(r.length===0){let l=e.map(u=>this.convertItemLabel(u));this._onDidChangeItems.fire(ge({items:l,finished:this._finished},t));return}let o=this.config.extendedSearchMode?g0e(r):[r],s=!1,a=(l,u,c)=>{if(u=u&&this._finished,i.isCancellationRequested||!u&&l.length==0)return;c&&l.sort((d,g)=>d.score!=g.score?g.score-d.score:d.sortText>g.sortText?1:-1);let h=t.append===!0||s;s=!0,this._onDidChangeItems.fire({items:l,append:h,reload:t.reload,finished:u})};switch(this.listOptions.matcher){case"strict":await this.filterItemsByInclude(o,e,i,a);break;case"regex":await this.filterItemsByRegex(o,e,i,a);break;default:await this.filterItemsByFuzzyMatch(o,e,i,a)}}convertItemLabel(e){let{label:t,converted:i}=e;if(i)return e;if(t.includes(` -`)&&(t=e.label=t.replace(/\r?\n/g," ")),t.includes(d0e)){let{line:r,highlights:o}=mc(t);e.label=r,Array.isArray(e.ansiHighlights)||(e.ansiHighlights=o)}return e.converted=!0,e}dispose(){this.stop()}}});var R_,u4,f0e,LXe,Zw,c4=_(()=>{"use strict";R_=C(Ei()),u4=C(H());bo();oa();z();ke();V();U6();Q6();l4();f0e=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],LXe=q()("list-session"),Zw=class{constructor(e,t,i,r,o=[],s){this.nvim=e;this.prompt=t;this.list=i;this.listOptions=r;this.listArgs=o;this.config=s;this.loadingFrame="";this.hidden=!1;this.disposables=[];this.args=[];this.ui=new Hw(e,i.name,r,s),this.history=new Bw(t,i.name),this.worker=new Ww(e,i,t,r,{interactiveDebounceTime:s.get("interactiveDebounceTime",100),extendedSearchMode:s.get("extendedSearchMode",!0)}),this.interactiveDebounceTime=s.get("interactiveDebounceTime",100);let a=(0,R_.default)(async()=>{let[d,g,f]=await e.eval('[coc#list#has_preview(),win_getid(),line(".")]');if(d&&g==this.winid){let p=this.ui.lnumToIndex(f);await this.doPreview(p)}},50);this.disposables.push({dispose:()=>{a.clear()}}),this.ui.onDidChangeLine(a,null,this.disposables),this.ui.onDidChangeLine(this.resolveItem,this,this.disposables),this.ui.onDidLineChange(this.resolveItem,this,this.disposables);let l=(0,R_.default)(async()=>{this.updateStatus();let{autoPreview:d}=this.listOptions;if(!d){let[g,f]=await e.eval("[coc#list#has_preview(),mode()]");if(!g||f!="n")return}await this.doAction("preview")},50);this.disposables.push({dispose:()=>{l.clear()}}),this.ui.onDidLineChange(l,null,this.disposables),this.ui.onDidOpen(async()=>{typeof this.list.doHighlight=="function"&&this.list.doHighlight(),y.isVim&&this.prompt.drawPrompt(),this.listOptions.first&&await this.doAction()},null,this.disposables),this.ui.onDidClose(async()=>{await this.hide()},null,this.disposables),this.ui.onDidDoubleClick(async()=>{await this.doAction()},null,this.disposables),this.worker.onDidChangeItems(async({items:d,reload:g,append:f,finished:p})=>{if(!this.hidden)if(f)await this.ui.appendItems(d);else{let b=this.config.get("height",10);p&&!r.interactive&&r.input.length==0&&(b=Math.min(d.length,b)),await this.ui.drawItems(d,Math.max(1,b),g)}},null,this.disposables);let u=0,c,h;this.disposables.push(u4.Disposable.create(()=>{c&&clearTimeout(c),h&&clearInterval(h)})),this.worker.onDidChangeLoading(d=>{this.hidden||(c&&clearTimeout(c),d?(u=Date.now(),h=setInterval(()=>{let g=Math.floor((Date.now()-u)%1e3/100);this.loadingFrame=f0e[g],this.updateStatus()},100)):c=setTimeout(()=>{this.loadingFrame="",h&&clearInterval(h),h=null,this.updateStatus()},Math.max(0,200-(Date.now()-u))))},null,this.disposables)}async start(e){this.args=e,this.cwd=y.cwd,this.hidden=!1;let{listOptions:t,listArgs:i}=this,r=await this.nvim.eval('[win_getid(),bufnr("%"),winheight("%")]');this.listArgs=i,this.history.load(t.input||""),this.window=this.nvim.createWindow(r[0]),this.buffer=this.nvim.createBuffer(r[1]),this.savedHeight=r[2],await this.worker.loadItems(this.context)}async reloadItems(){!this.ui.winid||await this.worker.loadItems(this.context,!0)}async call(e){var o,s;await this.nvim.call("coc#prompt#stop_prompt",["list"]);let t=await this.ui.getItems(),i={name:this.name,args:this.listArgs,input:this.prompt.input,winid:(o=this.window)==null?void 0:o.id,bufnr:(s=this.buffer)==null?void 0:s.id,targets:t},r=await this.nvim.call(e,[i]);return this.prompt.start(),r}async chooseAction(){let{nvim:e,defaultAction:t}=this,{actions:i}=this.list,r=i.map(h=>h.name),o=r.indexOf(t.name);o!=-1&&(r.splice(o,1),r.unshift(t.name));let s=new Set,a=[],l=[],u=y.env.dialog&&this.config.get("menuAction",!1);for(let h of r){let d=0;for(let g of h){if(!s.has(g)){s.add(g),a.push(`${h.slice(0,d)}&${h.slice(d)}`);break}d++}d==h.length&&l.push(h)}l.length&&!u&&(r=r.filter(h=>!l.includes(h)));let c;u?(e.call("coc#prompt#stop_prompt",["list"],!0),c=await k.showMenuPicker(r,{title:"Choose action",shortcuts:!0}),c=c+1,y.isVim&&await bt(10),this.prompt.start()):(await e.call("coc#prompt#stop_prompt",["list"]),c=await e.call("confirm",["Choose action:",a.join(` -`)]),await bt(10),this.prompt.start()),c&&await this.doAction(r[c-1])}async doAction(e){let{list:t}=this,i;if(e!=null){if(i=t.actions.find(o=>o.name==e),!i){k.showErrorMessage(`Action ${e} not found`);return}}else i=this.defaultAction;let r;if(e=="preview"){let o=await this.ui.item;r=o?[o]:[]}else r=await this.ui.getItems();r.length&&await this.doItemAction(r,i)}async doPreview(e){let t=this.ui.getItem(e),i=this.list.actions.find(r=>r.name=="preview");!t||!i||await this.doItemAction([t],i)}async first(){await this.doDefaultAction(0)}async last(){await this.doDefaultAction(this.ui.length-1)}async previous(){await this.doDefaultAction(this.ui.index-1)}async next(){await this.doDefaultAction(this.ui.index+1)}async doDefaultAction(e){let{ui:t}=this,i=t.getItem(e);!i||(t.index=e,await this.doItemAction([i],this.defaultAction),await t.echoMessage(i))}get name(){return this.list.name}get winid(){return this.ui.winid}get length(){return this.ui.length}get defaultAction(){let{defaultAction:e,actions:t,name:i}=this.list,r=y.getConfiguration(`list.source.${i}`),o;if(r.defaultAction&&(o=t.find(s=>s.name==r.defaultAction)),o||(o=t.find(s=>s.name==e)),o||(o=t[0]),!o)throw new Error(`default action "${e}" not found`);return o}async hide(e=!1){if(this.hidden)return;let{nvim:t,timer:i,window:r}=this,{winid:o,tabnr:s}=this.ui;i&&clearTimeout(i),this.worker.stop(),this.history.add(),this.ui.reset(),this.hidden=!0;let{isVim:a}=y;if(t.pauseNotification(),a||t.call("coc#prompt#stop_prompt",["list"],!0),s&&t.call("coc#list#close_preview",[s],!0),r&&t.call("win_gotoid",[r.id],!0),o&&t.call("coc#window#close",[o],!0),r&&this.savedHeight&&this.listOptions.position!=="tab"&&t.call("coc#window#set_height",[r.id,this.savedHeight],!0),e)return t.resumeNotification(!1,!0);await t.resumeNotification(!1),a&&(await bt(10),t.call("feedkeys",["\x1B","int"],!0),t.command("redraw",!0))}toggleMode(){let e=this.prompt.mode=="normal"?"insert":"normal";this.prompt.mode=e,this.listOptions.mode=e,this.updateStatus()}stop(){this.worker.stop()}async resolveItem(){let e=this.ui.index,t=this.ui.getItem(e);if(!t||t.resolved)return;let{list:i}=this;if(typeof i.resolveItem=="function"){let r=t.label,o=await Promise.resolve(i.resolveItem(t));if(o&&e==this.ui.index){let s=__(this.prompt.input,o);this.ui.updateItem(Object.assign({highlights:s},o),e,r!=o.label)}}}async showHelp(){await this.hide();let{list:e,nvim:t}=this;if(!e)return;t.pauseNotification(),t.command("tabe +setl\\ previewwindow [LIST HELP]",!0),t.command("setl nobuflisted noswapfile buftype=nofile bufhidden=wipe",!0),await t.resumeNotification();let i=e.options&&e.options.length,r=await t.buffer,o=new Ri;if(o.addLine("NAME","Label"),o.addLine(` ${e.name} - ${e.description||""} -`),o.addLine("SYNOPSIS","Label"),o.addLine(` :CocList [LIST OPTIONS] ${e.name}${i?" [ARGUMENTS]":""} -`),e.detail){o.addLine("DESCRIPTION","Label");let a=e.detail.split(` -`).map(l=>" "+l);o.addLine(a.join(` -`)+` -`)}if(i){o.addLine("ARGUMENTS","Label"),o.addLine("");for(let a of e.options)o.addLine(a.name,"Special"),o.addLine(` ${a.description}`),o.addLine("");o.addLine("")}let s=y.getConfiguration(`list.source.${e.name}`);if(Object.keys(s).length){o.addLine("CONFIGURATIONS","Label"),o.addLine("");let a={};ye.all.forEach(l=>{let{packageJSON:u}=l,{contributes:c}=u;if(!c)return;let{configuration:h}=c;if(h){let{properties:d}=h;if(d)for(let g of Object.keys(d))a[g]=d[g]}});for(let l of Object.keys(s)){let u=s[l],c=`list.source.${e.name}.${l}`,h=a[c]&&a[c].description?a[c].description:l;o.addLine(` "${c}"`,"MoreMsg"),o.addText(` - ${h}, current value: `),o.addText(JSON.stringify(u),"Special")}o.addLine("")}o.addLine("ACTIONS","Label"),o.addLine(` ${e.actions.map(a=>a.name).join(", ")}`),o.addLine(""),o.addLine("see ':h coc-list-options' for available list options.","Comment"),t.pauseNotification(),o.render(r,0,-1),t.command("setl nomod",!0),t.command("setl nomodifiable",!0),t.command("normal! gg",!0),t.command("nnoremap q :bd!",!0),await t.resumeNotification()}async switchMatcher(){let{matcher:e,interactive:t}=this.listOptions;if(t)return;let i=["fuzzy","strict","regex"],r=i.indexOf(e)+1;r>=i.length&&(r=0),this.listOptions.matcher=i[r],this.prompt.matcher=i[r],await this.worker.drawItems()}updateStatus(){let{ui:e,list:t,nvim:i}=this;if(!e.bufnr)return;let r=i.createBuffer(e.bufnr),o={mode:this.prompt.mode.toUpperCase(),args:this.args.join(" "),name:t.name,cwd:this.cwd,loading:this.loadingFrame,total:this.worker.length};r.setVar("list_status",o,!0),i.command("redraws",!0)}get context(){let{winid:e}=this.ui;return{options:this.listOptions,args:this.listArgs,input:this.prompt.input,cwd:y.cwd,window:this.window,buffer:this.buffer,listWindow:e?this.nvim.createWindow(e):void 0}}onMouseEvent(e){switch(e){case"":return this.ui.onMouse("mouseDown");case"":return this.ui.onMouse("mouseDrag");case"":return this.ui.onMouse("mouseUp");case"<2-LeftMouse>":return this.ui.onMouse("doubleClick")}}async doNumberSelect(e){if(!this.listOptions.numberSelect)return!1;let t=e.charCodeAt(0);if(t>=48&&t<=57){let i=Number(e);if(i==0&&(i=10),this.ui.length>=i)return this.nvim.pauseNotification(),this.ui.setCursor(i),await this.nvim.resumeNotification(),await this.doAction(),!0}return!1}jumpBack(){let{window:e,nvim:t}=this;e&&(t.pauseNotification(),t.call("coc#prompt#stop_prompt",["list"],!0),this.nvim.call("win_gotoid",[e.id],!0),t.resumeNotification(!1,!0))}async resume(){this.winid&&await this.hide();let e=await this.nvim.eval('[win_getid(),bufnr("%"),winheight("%")]');this.hidden=!1,this.window=this.nvim.createWindow(e[0]),this.buffer=this.nvim.createBuffer(e[1]),this.savedHeight=e[2],this.prompt.start(),await this.ui.resume(),this.listOptions.autoPreview&&await this.doAction("preview")}async doItemAction(e,t){let{noQuit:i,position:r}=this.listOptions,{nvim:o}=this,s=t.persist===!0||t.name=="preview";r==="tab"&&t.tabPersist&&(s=!0);let a=this.winid&&(s||i);try{if(a?s||(o.pauseNotification(),o.call("coc#prompt#stop_prompt",["list"],!0),o.call("win_gotoid",[this.context.window.id],!0),await o.resumeNotification()):await this.hide(),t.multiple)await Promise.resolve(t.execute(e,this.context));else if(t.parallel)await Promise.all(e.map(l=>Promise.resolve(t.execute(l,this.context))));else for(let l of e)await Promise.resolve(t.execute(l,this.context));a&&this.ui.restoreWindow(),t.reload&&a?await this.reloadItems():a&&this.nvim.command("redraw",!0)}catch(l){this.nvim.echoError(l)}}onInputChange(){this.timer&&clearTimeout(this.timer),this.listOptions.input=this.prompt.input,this.listOptions.interactive?(this.worker.stop(),this.timer=setTimeout(async()=>{await this.worker.loadItems(this.context)},this.interactiveDebounceTime)):this.worker.drawItems()}dispose(){this.hide(!0),Z(this.disposables),this.worker.dispose(),this.ui.dispose()}}});var h4,d4,g4,p0e,Jw,f4=_(()=>{"use strict";h4=require("child_process"),d4=require("events"),g4=C(require("readline"));z();V();p0e=q()("list-commandTask"),Jw=class extends d4.EventEmitter{constructor(e){super();this.opt=e;this.disposables=[];this.start()}start(){let{cmd:e,args:t,cwd:i,onLine:r}=this.opt,o=(0,h4.spawn)(e,t,{cwd:i||y.cwd,windowsHide:!0});this.disposables.push({dispose:()=>{o.kill()}}),o.on("error",a=>{this.emit("error",a.message)}),o.stderr.on("data",a=>{p0e.error(`[${e} Error]`,a.toString("utf8"))});let s=g4.default.createInterface(o.stdout);s.on("line",a=>{let l=r(a);l&&this.emit("data",l)}),s.on("close",()=>{this.emit("end")})}dispose(){Z(this.disposables)}}});function m0e(n){switch(n){case"latex":return"tex";default:return n}}var p4,L_,m4,Cn,$Xe,Xt,yo=_(()=>{"use strict";p4=C(require("fs")),L_=C(require("path")),m4=C(require("readline")),Cn=C(H());we();z();Je();yt();V();f4();Aw();$Xe=q()("list-basic"),Xt=class{constructor(e){this.nvim=e;this.defaultAction="open";this.actions=[];this.options=[];this.disposables=[];this.config=new wh}get alignColumns(){return this.config.get("alignColumns",!1)}get hlGroup(){return this.config.get("previewHighlightGroup","Search")}get previewHeight(){return this.config.get("maxPreviewHeight",12)}get splitRight(){return this.config.get("previewSplitRight",!1)}get toplineStyle(){return this.config.get("previewToplineStyle","offset")}get toplineOffset(){return this.config.get("previewToplineOffset",3)}parseArguments(e){if(!this.optionMap){this.optionMap=new Map;for(let i of this.options){let r=i.name.split(/,\s*/g).map(s=>s.replace(/\s+.*/g,"")),o=i.key?i.key:r[r.length-1].replace(/^-/,"");for(let s of r)this.optionMap.set(s,{name:o,hasValue:i.hasValue})}}let t={};for(let i=0;i{let r=await this.convertLocation(t.location);await this.previewLocation(r,i)}});let{nvim:e}=this;this.createAction({name:"quickfix",multiple:!0,execute:async t=>{let i=await Promise.all(t.map(o=>this.convertLocation(o.location).then(s=>y.getQuickfixItem(s))));await e.call("setqflist",[i]);let r=await e.getVar("coc_quickfix_open_command");e.command(typeof r=="string"?r:"copen",!0)}});for(let t of["open","tabe","drop","vsplit","split"])this.createAction({name:t,execute:async(i,r)=>{await this.jumpTo(i.location,t=="open"?null:t,r)},tabPersist:t==="open"})}async convertLocation(e){if(typeof e=="string")return Cn.Location.create(e,Cn.Range.create(0,0,0,0));if(Cn.Location.is(e))return e;let t=O.parse(e.uri);if(t.scheme!="file")return Cn.Location.create(e.uri,Cn.Range.create(0,0,0,0));let i=m4.default.createInterface({input:p4.default.createReadStream(t.fsPath,{encoding:"utf8"})}),r=e.line,o=0,s=!1,a=await new Promise(l=>{i.on("line",u=>{if(!s){if(u.includes(r)){i.removeAllListeners(),i.close(),s=!0,l(u);return}o=o+1}}),i.on("error",u=>{this.nvim.errWriteLine(`Read ${t.fsPath} error: ${u.message}`),l(null)})});if(a!=null){let l=e.text?a.indexOf(e.text):0;l==0&&(l=a.match(/^\s*/)[0].length);let u=Cn.Position.create(o,l+(e.text?e.text.length:0));return Cn.Location.create(e.uri,Cn.Range.create(Cn.Position.create(o,l),u))}return Cn.Location.create(e.uri,Cn.Range.create(0,0,0,0))}async jumpTo(e,t,i){if(t==null&&i&&i.options.position==="tab"&&(t="tabe"),typeof e=="string"){await y.jumpTo(e,null,t);return}let{range:r,uri:o}=await this.convertLocation(e),s=r.start;s.line==0&&s.character==0&&De(s,r.end)==0&&(s=null),await y.jumpTo(o,s,t)}createAction(e){let{name:t}=e,i=this.actions.findIndex(r=>r.name==t);i!==-1&&this.actions.splice(i,1),this.actions.push(e)}async previewLocation(e,t){if(!t.listWindow)return;let{nvim:i}=this,{uri:r,range:o}=e,s=y.getDocument(e.uri),a=O.parse(r),l=[];if(s)l=s.getLines();else if(a.scheme=="file")try{l=(await xc(a.fsPath,"utf8")).split(/\r?\n/)}catch(c){`${a.fsPath}`,c.toString()}let u={winid:t.window.id,range:Ct(o)?null:o,lnum:o.start.line+1,name:a.scheme=="file"?a.fsPath:r,filetype:m0e(s?s.languageId:this.getLanguageId(a.fsPath)),position:t.options.position,maxHeight:this.previewHeight,splitRight:this.splitRight,hlGroup:this.hlGroup,scheme:a.scheme,toplineStyle:this.toplineStyle,toplineOffset:this.toplineOffset};await i.call("coc#list#preview",[l,u])}async preview(e,t){let{nvim:i}=this,{bufname:r,filetype:o,range:s,lines:a,lnum:l}=e,u={winid:t.window.id,lnum:s?s.start.line+1:l||1,filetype:o||"txt",position:t.options.position,maxHeight:this.previewHeight,splitRight:this.splitRight,hlGroup:this.hlGroup,toplineStyle:this.toplineStyle,toplineOffset:this.toplineOffset};r&&(u.name=r),s&&(u.range=s),await i.call("coc#list#preview",[a,u]),i.command("redraw",!0)}doHighlight(){}dispose(){Z(this.disposables)}getLanguageId(e){let t=L_.default.extname(e);if(!t)return"";for(let i of y.documents){let r=O.parse(i.uri).fsPath;if(L_.default.extname(r)==t)return i.languageId}return""}}});function Sn(n,e){if(e.length===0)return[];let t=[];if(n){let i=Array(Math.min(...e.map(r=>r.label.length))).fill(0);for(let r of e)for(let o=0;oBa(ge({},r),{label:r.label.map((o,s)=>o.padEnd(i[s])).join(" ")}))}else t=e.map(i=>Ba(ge({},i),{label:i.label.join(" ")}));return t}function b4(n,e){var t;if(n==="hidden")return"";if(n==="full")return e;if(n==="short"){let i=e.split($w.default.sep);return i.length<2?e:[...i.slice(0,i.length-2).filter(o=>o.length>0).map(o=>o[0]),i[i.length-1]].join($w.default.sep)}else{let i=e.split($w.default.sep);return(t=i[i.length-1])!=null?t:""}}var $w,La=_(()=>{"use strict";$w=C(require("path"))});function b0e(n,e){let t=n.indexOf(e);return t==-1?-1:n.length-t}var Xw,y4=_(()=>{"use strict";wi();V();yo();La();Xw=class extends Xt{constructor(e){super(e);this.defaultAction="run";this.description="registered commands of coc.nvim";this.name="commands";this.mru=y.createMru("commands"),this.addAction("run",async t=>{await oe.fireCommand(t.data.cmd)}),this.addAction("append",async t=>{let{cmd:i}=t.data;await e.feedKeys(`:CocCommand ${i} `,"n",!1)})}async loadItems(e){let t=[],i=await this.mru.load(),{commandList:r,onCommandList:o,titles:s}=oe,a=r.map(l=>l.id).concat(o);for(let l of[...new Set(a)])t.push({label:[l,...s.get(l)?[s.get(l)]:[]],filterText:l,data:{cmd:l,score:b0e(i,l)}});return t.sort((l,u)=>u.data.score-l.data.score),Sn(this.alignColumns,t)}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocCommandsTitle /\\t.*$/ contained containedin=CocCommandsLine",!0),e.command("highlight default link CocCommandsTitle Comment",!0),e.resumeNotification(!1,!0)}}});var Gf,lUe,vo,Qf=_(()=>{"use strict";Qr();Gf=C(require("path"));yo();V();wi();we();Je();Pe();lUe=q()("list-location"),vo=class extends Xt{constructor(e){super(e);this.defaultAction="open";this.description="show locations saved by g:coc_jump_locations variable";this.name="location";this.createAction({name:"refactor",multiple:!0,execute:async t=>{let i=t.map(r=>r.location);await oe.executeCommand("workspace.refactor",i)}}),this.addLocationActions()}async loadItems(e,t){let i=await this.nvim.getVar("coc_jump_locations");if(t.isCancellationRequested)return[];i=i||[],i.forEach(a=>{if(!a.uri){let l=Gf.default.isAbsolute(a.filename)?a.filename:Gf.default.join(e.cwd,a.filename);a.uri=O.file(l).toString()}if(!a.bufnr&&y.getDocument(a.uri)!=null&&(a.bufnr=y.getDocument(a.uri).bufnr),a.range)a.lnum=a.lnum||a.range.start.line+1,a.col=a.col||a.range.start.character+1;else{let{lnum:l,col:u}=a;a.range=Ne.create(l-1,u-1,l-1,u-1)}});let r=e.buffer.id,o=i.every(a=>a.bufnr&&r&&a.bufnr==r);return i.map(a=>{let l=o?"":a.filename,u=`${l}${a.text.trim()}`;Gf.default.isAbsolute(l)&&(l=Ae(e.cwd,l)?Gf.default.relative(e.cwd,l):l);let c=`${l} |${a.type?a.type+" ":""}${a.lnum} col ${a.col}| `,h;if(a.range&&a.range.start.line==a.range.end.line){let g=Q(c)+Q(a.text.slice(0,a.range.start.character)),f=Q(c)+Q(a.text.slice(0,a.range.end.character));h={hlGroup:"Search",span:[g,f]}}return{label:c+a.text,location:cn.create(a.uri,a.range),filterText:u,ansiHighlights:h?[h]:void 0}})}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocLocationName /\\v^[^|]+/ contained containedin=CocLocationLine",!0),e.command("syntax match CocLocationPosition /\\v\\|\\w*\\s?\\d+\\scol\\s\\d+\\|/ contained containedin=CocLocationLine",!0),e.command("syntax match CocLocationError /Error/ contained containedin=CocLocationPosition",!0),e.command("syntax match CocLocationWarning /Warning/ contained containedin=CocLocationPosition",!0),e.command("highlight default link CocLocationName Directory",!0),e.command("highlight default link CocLocationPosition LineNr",!0),e.command("highlight default link CocLocationError Error",!0),e.command("highlight default link CocLocationWarning WarningMsg",!0),e.resumeNotification(!1,!0)}}});var v4,mUe,Uw,w4=_(()=>{"use strict";v4=C(require("path"));eu();Je();La();Qf();mUe=q()("list-symbols"),Uw=class extends vo{constructor(e,t){super(e);this.defaultAction="open";this.description="diagnostics of current workspace";this.name="diagnostics";Ft.onDidRefresh(async()=>{let i=t.getSession("diagnostics");i&&await i.reloadItems()},null,this.disposables)}async loadItems(e){let t=await Ft.getDiagnosticList(),{cwd:i}=e,r=this.getConfig(),o=r.get("includeCode",!0),s=r.get("pathFormat","full"),a=t.map(l=>{let u=Ae(i,l.file)?v4.default.relative(i,l.file):l.file,c=b4(s,u),h=s!=="hidden"?[`${c}:${l.lnum}`]:[],d=o?[`[${l.source}${l.code?"":"]"}`,l.code?`${l.code}]`:""]:[];return{label:[...h,...d,l.severity,l.message],location:l.location}});return Sn(this.alignColumns,a)}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocDiagnosticsFile /\\v^\\s*\\S+/ contained containedin=CocDiagnosticsLine",!0),e.command("syntax match CocDiagnosticsError /\\tError\\s*\\t/ contained containedin=CocDiagnosticsLine",!0),e.command("syntax match CocDiagnosticsWarning /\\tWarning\\s*\\t/ contained containedin=CocDiagnosticsLine",!0),e.command("syntax match CocDiagnosticsInfo /\\tInformation\\s*\\t/ contained containedin=CocDiagnosticsLine",!0),e.command("syntax match CocDiagnosticsHint /\\tHint\\s*\\t/ contained containedin=CocDiagnosticsLine",!0),e.command("highlight default link CocDiagnosticsFile Comment",!0),e.command("highlight default link CocDiagnosticsError CocErrorSign",!0),e.command("highlight default link CocDiagnosticsWarning CocWarningSign",!0),e.command("highlight default link CocDiagnosticsInfo CocInfoSign",!0),e.command("highlight default link CocDiagnosticsHint CocHintSign",!0),e.resumeNotification(!1,!0)}}});function v0e(n){switch(n){case"unknown":return 2;case"activated":return 1;case"disabled":return-1;default:return 0}}var Th,D4,Gw,y0e,Qw,x4=_(()=>{"use strict";Th=C(Rn()),D4=C(require("os")),Gw=C(require("path"));we();bo();z();V();ke();yo();La();y0e=q()("list-extensions"),Qw=class extends Xt{constructor(e){super(e);this.defaultAction="toggle";this.description="manage coc extensions";this.name="extensions";this.addAction("toggle",async t=>{let{id:i,state:r}=t.data;r!="disabled"&&(r=="activated"?await ye.deactivate(i):await ye.activate(i),await bt(100))},{persist:!0,reload:!0,parallel:!0}),this.addAction("configuration",async t=>{let{root:i}=t.data,r=Gw.default.join(i,"package.json");if(Th.default.existsSync(r)){let s=Th.default.readFileSync(r,"utf8").split(/\r?\n/).findIndex(a=>a.includes('"contributes"'));await y.jumpTo(O.file(r).toString(),{line:s==-1?0:s,character:0})}}),this.addAction("open",async t=>{let{root:i}=t.data;y.env.isiTerm?e.call("coc#ui#iterm_open",[i],!0):e.call("coc#ui#open_url",[i],!0)}),this.addAction("disable",async t=>{let{id:i,state:r}=t.data;r!=="disabled"&&await ye.toggleExtension(i)},{persist:!0,reload:!0,parallel:!0}),this.addAction("enable",async t=>{let{id:i,state:r}=t.data;r=="disabled"&&await ye.toggleExtension(i)},{persist:!0,reload:!0,parallel:!0}),this.addAction("lock",async t=>{let{id:i}=t.data;await ye.lockExtension(i)},{persist:!0,reload:!0}),this.addAction("help",async t=>{let{root:i}=t.data,o=(await Th.default.readdir(i)).find(s=>/^readme/i.test(s));o&&await y.callAsync("coc#util#jump",["edit",Gw.default.join(i,o)])}),this.addAction("reload",async t=>{let{id:i}=t.data;await ye.reloadExtension(i)},{persist:!0,reload:!0}),this.addAction("fix",async t=>{let{root:i,isLocal:r}=t.data,{npm:o}=ye;if(r){k.showMessage("Can't fix for local extension.","warning");return}if(!o)return;let s=Gw.default.join(i,"node_modules");Th.default.existsSync(s)&&Th.default.removeSync(s);let a=await k.createTerminal({cwd:i});!await a.show(!1)||(y.nvim.command("startinsert",!0),a.sendText(`${o} install --production --ignore-scripts --no-lockfile`,!0))}),this.addMultipleAction("uninstall",async t=>{let i=[];for(let r of t)r.data.isLocal||i.push(r.data.id);ye.uninstallExtension(i).catch(r=>{y0e.error(r)})})}async loadItems(e){let t=[],i=await ye.getExtensionStates(),r=await ye.getLockedList();for(let o of i){let s="+";o.state=="disabled"?s="-":o.state=="activated"?s="*":o.state=="unknown"&&(s="?");let a=await this.nvim.call("resolve",o.root),l=r.includes(o.id);t.push({label:[`${s} ${o.id}${l?" \uE0A2":""}`,...o.isLocal?["[RTP]"]:[],o.version,a.replace(D4.default.homedir(),"~")],filterText:o.id,data:{id:o.id,root:a,state:o.state,isLocal:o.isLocal,priority:v0e(o.state)}})}return t.sort((o,s)=>o.data.priority!=s.data.priority?s.data.priority-o.data.priority:s.data.id-o.data.id?1:-1),Sn(this.alignColumns,t)}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocExtensionsActivited /\\v^\\*/ contained containedin=CocExtensionsLine",!0),e.command("syntax match CocExtensionsLoaded /\\v^\\+/ contained containedin=CocExtensionsLine",!0),e.command("syntax match CocExtensionsDisabled /\\v^-/ contained containedin=CocExtensionsLine",!0),e.command("syntax match CocExtensionsName /\\v%3c\\S+/ contained containedin=CocExtensionsLine",!0),e.command("syntax match CocExtensionsRoot /\\v\\t[^\\t]*$/ contained containedin=CocExtensionsLine",!0),e.command("syntax match CocExtensionsLocal /\\v\\[RTP\\]/ contained containedin=CocExtensionsLine",!0),e.command("highlight default link CocExtensionsActivited Special",!0),e.command("highlight default link CocExtensionsLoaded Normal",!0),e.command("highlight default link CocExtensionsDisabled Comment",!0),e.command("highlight default link CocExtensionsName String",!0),e.command("highlight default link CocExtensionsLocal MoreMsg",!0),e.command("highlight default link CocExtensionsRoot Comment",!0),e.resumeNotification(!1,!0)}}});var C4,S4,Kw,T4=_(()=>{"use strict";C4=C(require("path"));we();S4=C(Rn());Je();V();ke();yo();Kw=class extends Xt{constructor(e){super(e);this.defaultAction="edit";this.description="list of current workspace folders";this.name="folders";this.addAction("edit",async t=>{let i=await e.call("input",["Folder: ",t.label,"dir"]),r=await Ht(i);if(!r||!r.isDirectory()){k.showMessage(`invalid path: ${i}`,"error");return}y.workspaceFolderControl.renameWorkspaceFolder(t.label,i)}),this.addAction("delete",async t=>{y.workspaceFolderControl.removeWorkspaceFolder(t.label)},{reload:!0,persist:!0}),this.addAction("newfile",async(t,i)=>{let r=await k.requestInput("File name",t.label+"/");if(!r)return;let o=C4.default.dirname(r),s=await Ht(o);(!s||!s.isDirectory())&&S4.default.mkdirpSync(o),await y.createFile(r,{overwrite:!1,ignoreIfExists:!0}),await this.jumpTo(O.file(r).toString(),null,i)})}async loadItems(e){return y.folderPaths.map(t=>({label:t}))}}});function k4(n){if(!n.startsWith("file:"))return n;let e=O.parse(n).fsPath;return Ae(y.cwd,e)?E4.default.relative(y.cwd,e):e}var E4,zw,P4=_(()=>{"use strict";Ce();V();E4=C(require("path"));yo();Qr();we();Je();zw=class extends Xt{constructor(e){super(e);this.defaultAction="open";this.description="links of current buffer";this.name="links";this.addAction("open",async t=>{let{target:i}=t.data;O.parse(i).scheme.startsWith("http")?await e.call("coc#ui#open_url",i):await y.jumpTo(i)}),this.addAction("jump",async t=>{let{location:i}=t.data;await y.jumpTo(i.uri,i.range.start)})}async loadItems(e,t){let i=await e.window.buffer,r=y.getDocument(i.id);if(!r)return null;let o=[],s=await A.getDocumentLinks(r.textDocument,t);if(t.isCancellationRequested)return null;if(s==null)throw new Error("Links provider not found.");let a=[];for(let l of s)l.target?o.push({label:k4(l.target),data:{target:l.target,location:cn.create(r.uri,l.range)}}):(l=await A.resolveDocumentLink(l,t),l.target&&o.push({label:k4(l.target),data:{target:l.target,location:cn.create(r.uri,l.range)}}),a.push(l));return o}}});function w0e(n,e){let t=n.indexOf(e);return t==-1?-1:n.length-t}var Vw,_4=_(()=>{"use strict";yo();lf();La();Vw=class extends Xt{constructor(e,t){super(e);this.listMap=t;this.name="lists";this.defaultAction="open";this.description="registered lists of coc.nvim";this.mru=new oo("lists");this.addAction("open",async i=>{let{name:r}=i.data;await this.mru.add(r),e.command(`CocList ${r}`,!0)})}async loadItems(e){let t=[],i=await this.mru.load();for(let r of this.listMap.values())r.name!="lists"&&t.push({label:[r.name,...r.description?[r.description]:[]],data:{name:r.name,interactive:r.interactive,score:w0e(i,r.name)}});return t.sort((r,o)=>o.data.score-r.data.score),Sn(this.alignColumns,t)}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocListsDesc /\\t.*$/ contained containedin=CocListsLine",!0),e.command("highlight default link CocListsDesc Comment",!0),e.resumeNotification(!1,!0)}}});function wo(n){switch(n){case dt.SymbolKind.File:return"File";case dt.SymbolKind.Module:return"Module";case dt.SymbolKind.Namespace:return"Namespace";case dt.SymbolKind.Package:return"Package";case dt.SymbolKind.Class:return"Class";case dt.SymbolKind.Method:return"Method";case dt.SymbolKind.Property:return"Property";case dt.SymbolKind.Field:return"Field";case dt.SymbolKind.Constructor:return"Constructor";case dt.SymbolKind.Enum:return"Enum";case dt.SymbolKind.Interface:return"Interface";case dt.SymbolKind.Function:return"Function";case dt.SymbolKind.Variable:return"Variable";case dt.SymbolKind.Constant:return"Constant";case dt.SymbolKind.String:return"String";case dt.SymbolKind.Number:return"Number";case dt.SymbolKind.Boolean:return"Boolean";case dt.SymbolKind.Array:return"Array";case dt.SymbolKind.Object:return"Object";case dt.SymbolKind.Key:return"Key";case dt.SymbolKind.Null:return"Null";case dt.SymbolKind.EnumMember:return"EnumMember";case dt.SymbolKind.Struct:return"Struct";case dt.SymbolKind.Event:return"Event";case dt.SymbolKind.Operator:return"Operator";case dt.SymbolKind.TypeParameter:return"TypeParameter";default:return"Unknown"}}var dt,Kf=_(()=>{"use strict";dt=C(H())});function R4(n,e){return`${n.name}${e?` ${e}`:""}`}function D0e(n,e){let t=n.selectionRange,i=e.selectionRange;return t.start.line!=i.start.line?t.start.line-i.start.line:t.start.character-i.start.character}var L4,F4,o8e,eD,I4=_(()=>{"use strict";L4=C(require("path"));Qr();we();F4=C(rg());Ce();z();Je();V();Qf();Kf();La();o8e=q()("list-symbols");eD=class extends vo{constructor(){super(...arguments);this.description="symbols of current document";this.name="outline";this.options=[{name:"-k, -kind KIND",hasValue:!0,description:"filter symbol by kind"}]}async loadItems(e,t){let i=await e.window.buffer,r=y.getDocument(i.id);if(!r)return null;let s=this.getConfig().get("ctagsFilestypes",[]),a,l=this.parseArguments(e.args);if(s.includes(r.filetype)||(a=await A.getDocumentSymbol(r.textDocument,t)),t.isCancellationRequested)return[];if(!a)return await this.loadCtagsSymbols(r);if(a.length==0)return[];let u=l.kind?l.kind.toLowerCase():null,c=[];if(!a[0].hasOwnProperty("location")){let d=function(g,f=0){g.sort(D0e);for(let p of g){let b=wo(p.kind),v=cn.create(r.uri,p.selectionRange);c.push({label:[`${"| ".repeat(f)}${p.name}`,`[${b}]`,`${p.range.start.line+1}`],filterText:R4(p,l.kind==""?b:null),location:v,data:{kind:b}}),p.children&&p.children.length&&d(p.children,f+1)}};d(a),u&&(c=c.filter(g=>g.data.kind.toLowerCase().indexOf(u)==0))}else{a.sort((d,g)=>{let f=d.location.range.start,p=g.location.range.start,b=f.line-p.line;return b==0?f.character-p.character:b});for(let d of a){let g=wo(d.kind);d.name.endsWith(") callback")||u&&!g.toLowerCase().startsWith(u)||(d.location.uri===void 0&&(d.location.uri=r.uri),c.push({label:[d.name,`[${g}]`,`${d.location.range.start.line+1}`],filterText:R4(d,l.kind==""?g:null),location:d.location}))}}return Sn(this.alignColumns,c)}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocOutlineName /\\v\\s?[^\\t]+\\s/ contained containedin=CocOutlineLine",!0),e.command("syntax match CocOutlineIndentLine /\\v\\|/ contained containedin=CocOutlineLine,CocOutlineName",!0),e.command("syntax match CocOutlineKind /\\[\\w\\+\\]/ contained containedin=CocOutlineLine",!0),e.command("syntax match CocOutlineLine /\\d\\+$/ contained containedin=CocOutlineLine",!0),e.command("highlight default link CocOutlineName Normal",!0),e.command("highlight default link CocOutlineIndentLine Comment",!0),e.command("highlight default link CocOutlineKind Typedef",!0),e.command("highlight default link CocOutlineLine Comment",!0),e.resumeNotification(!1,!0)}async loadCtagsSymbols(e){if(!F4.default.sync("ctags",{nothrow:!0}))return[];let t=O.parse(e.uri),i=L4.default.extname(t.fsPath),r="",s=`${await this.nvim.call("tempname")}.${i}`,a=await this.nvim.call("fnameescape",s);await bb(a,e.getDocumentContent());try{r=await Vr(`ctags -f - --excmd=number --language-force=${e.filetype} ${a}`)}catch{}if(r.trim().length||(r=await Vr(`ctags -f - --excmd=number ${a}`)),r=r.trim(),!r)return[];let l=r.split(/\r?\n/),u=[];for(let c of l){let h=c.split(" ");if(h.length<4)continue;let d=Number(h[2].replace(/;"$/,"")),g=e.getline(d-1);if(!g)continue;let f=g.indexOf(h[0]),p=f==-1?0:f,b=Ne.create(d-1,p,d-1,p+h[0].length);u.push({label:`${h[0]} [${h[3]}] ${d}`,filterText:h[0],location:cn.create(e.uri,b),data:{line:d}})}return u.sort((c,h)=>c.data.line-h.data.line),u}}});var tD,j4=_(()=>{"use strict";$f();yo();z();La();tD=class extends Xt{constructor(e){super(e);this.defaultAction="toggle";this.description="registered services of coc.nvim";this.name="services";this.addAction("toggle",async t=>{let{id:i}=t.data;await Mi.toggle(i),await bt(100)},{persist:!0,reload:!0})}async loadItems(e){let t=Mi.getServiceStats();return t.sort((i,r)=>i.id>r.id?-1:1),Sn(this.alignColumns,t.map(i=>({label:[i.state=="running"?"*":" ",i.id,`[${i.state}]`,i.languageIds.join(", ")],data:{id:i.id}})))}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocServicesPrefix /\\v^./ contained containedin=CocServicesLine",!0),e.command("syntax match CocServicesName /\\v%3c\\S+/ contained containedin=CocServicesLine",!0),e.command("syntax match CocServicesStat /\\v\\t\\[\\w+\\]/ contained containedin=CocServicesLine",!0),e.command("syntax match CocServicesLanguages /\\v(\\])@<=.*$/ contained containedin=CocServicesLine",!0),e.command("highlight default link CocServicesPrefix Special",!0),e.command("highlight default link CocServicesName Type",!0),e.command("highlight default link CocServicesStat Statement",!0),e.command("highlight default link CocServicesLanguages Comment",!0),e.resumeNotification(!1,!0)}}});function iD(n,e){return n.length>e?n.slice(0,e-1)+".":n+" ".repeat(e-n.length)}var m8e,nD,A4=_(()=>{"use strict";Qr();we();Ul();yo();m8e=q()("list-sources"),nD=class extends Xt{constructor(e){super(e);this.defaultAction="toggle";this.description="registered completion sources";this.name="sources";this.addAction("toggle",async t=>{let{name:i}=t.data;Lt.toggleSource(i)},{persist:!0,reload:!0}),this.addAction("refresh",async t=>{let{name:i}=t.data;await Lt.refresh(i)},{persist:!0,reload:!0}),this.addAction("open",async(t,i)=>{let{location:r}=t;r&&await this.jumpTo(r,null,i)})}async loadItems(e){let t=Lt.sourceStats();return t.sort((i,r)=>i.type!=r.type?i.typer.name?-1:1),t.map(i=>{let r=i.disabled?" ":"*",o;return i.filepath&&(o=cn.create(O.file(i.filepath).toString(),Ne.create(0,0,0,0))),{label:`${r} ${iD(i.name,22)} ${iD("["+i.shortcut+"]",10)} ${iD(i.triggerCharacters.join(""),10)} ${iD(i.priority.toString(),3)} ${i.filetypes.join(",")}`,location:o,data:{name:i.name}}})}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocSourcesPrefix /\\v^./ contained containedin=CocSourcesLine",!0),e.command("syntax match CocSourcesName /\\v%3c\\S+/ contained containedin=CocSourcesLine",!0),e.command("syntax match CocSourcesType /\\v%25v.*%36v/ contained containedin=CocSourcesLine",!0),e.command("syntax match CocSourcesPriority /\\v%46v.*%50v/ contained containedin=CocSourcesLine",!0),e.command("syntax match CocSourcesFileTypes /\\v\\S+$/ contained containedin=CocSourcesLine",!0),e.command("highlight default link CocSourcesPrefix Special",!0),e.command("highlight default link CocSourcesName Type",!0),e.command("highlight default link CocSourcesPriority Number",!0),e.command("highlight default link CocSourcesFileTypes Comment",!0),e.command("highlight default link CocSourcesType Statement",!0),e.resumeNotification(!1,!0)}}});var F_,O4,M4,P8e,rD,N4=_(()=>{"use strict";F_=C(require("path")),O4=C(Vn());we();Ce();V();Qf();Kf();Je();Uf();M4=C(H());La();P8e=q()("list-symbols"),rD=class extends vo{constructor(){super(...arguments);this.interactive=!0;this.description="search workspace symbols";this.detail="Symbols list is provided by server, it works on interactive mode only.";this.name="symbols";this.options=[{name:"-k, -kind KIND",description:"Filter symbols by kind.",hasValue:!0}]}async loadItems(e,t){let{input:i}=e;this.cwd=e.cwd;let r=this.parseArguments(e.args),o=r.kind?r.kind.toLowerCase():"";if(!e.options.interactive)throw new Error("Symbols only works on interactive mode");let s=await A.getWorkspaceSymbols(i,t);if(!s)throw new Error("No workspace symbols provider registered");let l=this.getConfig().get("excludes",[]),u=[];for(let c of s){let h=wo(c.kind);if(o&&h.toLowerCase()!=o)continue;let d=O.parse(c.location.uri).fsPath;Ae(y.cwd,d)&&(d=F_.default.relative(y.cwd,d)),!l.some(g=>(0,O4.default)(d,g))&&u.push({label:[c.name,`[${h}]`,d],filterText:`${c.name}`,location:c.location,data:{original:c,kind:c.kind,file:d,score:Ch(i,c.name)}})}return u.sort((c,h)=>c.data.score!=h.data.score?h.data.score-c.data.score:c.data.kind!=h.data.kind?c.data.kind-h.data.kind:c.data.file.length-h.data.file.length),Sn(this.alignColumns,u)}async resolveItem(e){let t=e.data.original;if(!t)return null;let i=new M4.CancellationTokenSource,r=await A.resolveWorkspaceSymbol(t,i.token);if(!r)return null;let o=wo(r.kind),s=O.parse(r.location.uri).fsPath;return Ae(this.cwd,s)&&(s=F_.default.relative(this.cwd,s)),{label:`${t.name} [${o}] ${s}`,filterText:`${t.name}`,location:t.location}}doHighlight(){let{nvim:e}=this;e.pauseNotification(),e.command("syntax match CocSymbolsName /\\v^\\s*\\S+/ contained containedin=CocSymbolsLine",!0),e.command("syntax match CocSymbolsKind /\\[\\w\\+\\]\\s*\\t/ contained containedin=CocSymbolsLine",!0),e.command("syntax match CocSymbolsFile /\\S\\+$/ contained containedin=CocSymbolsLine",!0),e.command("highlight default link CocSymbolsName Normal",!0),e.command("highlight default link CocSymbolsKind Typedef",!0),e.command("highlight default link CocSymbolsFile Comment",!0),e.resumeNotification(!1,!0)}}});var H4,oD,q4,x0e,B4,Y4,Di,sD=_(()=>{"use strict";H4=C(Ei()),oD=C(H());le();bo();z();V();ke();Aw();Z6();$6();c4();y4();w4();x4();T4();P4();_4();Qf();I4();j4();A4();N4();q4=C(dg()),x0e=q()("list-manager"),B4=["","","","<2-LeftMouse>"],Y4=class{constructor(){this.plugTs=0;this.sessionsMap=new Map;this.disposables=[];this.listMap=new Map}init(e){this.nvim=e,this.config=new wh,this.prompt=new Mw(e,this.config),this.mappings=new Ow(this,e,this.config);let t=this.config.get("selectedSignText","*");e.command(`sign define CocSelected text=${t} texthl=CocSelectedText linehl=CocSelectedLine`,!0),E.on("InputChar",this.onInputChar,this,this.disposables);let i=(0,H4.default)(async()=>{await this.getCurrentSession()&&this.prompt.drawPrompt()},100);E.on("FocusGained",i,null,this.disposables),E.on("WinEnter",o=>{let s=this.getSessionByWinid(o);s&&this.prompt.start(s.listOptions)},null,this.disposables);let r;E.on("WinLeave",o=>{r&&clearTimeout(r),this.getSessionByWinid(o)&&setTimeout(()=>{this.prompt.cancel()},y.isVim?50:0)},null,this.disposables),this.disposables.push({dispose:()=>{i.clear()}}),this.prompt.onDidChangeInput(()=>{let{session:o}=this;!o||(o.onInputChange(),o.history.filter())}),this.registerList(new zw(e)),this.registerList(new vo(e)),this.registerList(new rD(e)),this.registerList(new eD(e)),this.registerList(new Xw(e)),this.registerList(new Qw(e)),this.registerList(new Uw(e,this)),this.registerList(new nD(e)),this.registerList(new tD(e)),this.registerList(new Vw(e,this.listMap)),this.registerList(new Kw(e))}async start(e){let t=this.parseArgs(e);if(!t)return;let{name:i}=t.list,r=this.sessionsMap.get(i);r&&r.dispose(),this.prompt.start(t.options);let o=new Zw(this.nvim,this.prompt,t.list,t.options,t.listArgs,this.config);this.sessionsMap.set(i,o),this.lastSession=o;try{await o.start(e)}catch(s){this.nvim.call("coc#prompt#stop_prompt",["list"],!0);let a=s instanceof Error?s.message:s.toString();k.showMessage(`Error on "CocList ${i}": ${a}`,"error"),x0e.error(s)}}getSessionByWinid(e){for(let t of this.sessionsMap.values())if(t&&t.winid==e)return this.lastSession=t,t;return null}async getCurrentSession(){let{id:e}=await this.nvim.window;for(let t of this.sessionsMap.values())if(t&&t.winid==e)return this.lastSession=t,t;return null}async resume(e){var t;if(!e)await((t=this.session)==null?void 0:t.resume());else{let i=this.sessionsMap.get(e);if(!i){k.showMessage(`Can't find exists ${e} list`);return}await i.resume()}}async doAction(e){let t=this.lastSession;!t||await t.doAction(e)}async first(e){let t=this.getSession(e);t&&await t.first()}async last(e){let t=this.getSession(e);t&&await t.last()}async previous(e){let t=this.getSession(e);t&&await t.previous()}async next(e){let t=this.getSession(e);t&&await t.next()}getSession(e){return e?this.sessionsMap.get(e):this.session}async cancel(e=!0){this.prompt.cancel(),!!e&&this.session&&await this.session.hide()}reset(){this.prompt.cancel(),this.lastSession=void 0;for(let e of this.sessionsMap.values())e.dispose();this.sessionsMap.clear(),this.nvim.call("coc#prompt#stop_prompt",["list"],!0)}async switchMatcher(){var e;await((e=this.session)==null?void 0:e.switchMatcher())}async togglePreview(){let{nvim:e}=this,t=await e.call("coc#list#get_preview",[0]);t!=-1?(await e.call("coc#window#close",[t]),await e.command("redraw")):await this.doAction("preview")}async chooseAction(){let{lastSession:e}=this;e&&await e.chooseAction()}parseArgs(e){let t=[],i=!1,r=!1,o=!1,s=!1,a=!1,l=!1,u,c="",h="fuzzy",d="bottom",g=[],f=[];for(let v of e)if(!u&&v.startsWith("-"))f.push(v);else if(u)g.push(v);else{if(!/^\w+$/.test(v))return k.showMessage(`Invalid list option: "${v}"`,"error"),null;u=v}u=u||"lists";let p=y.getConfiguration(`list.source.${u}`);!f.length&&!g.length&&(f=p.get("defaultOptions",[])),g.length||(g=p.get("defaultArgs",[]));for(let v of f)if(v.startsWith("--input"))c=v.slice(8);else if(v=="--number-select"||v=="-N")o=!0;else if(v=="--auto-preview"||v=="-A")r=!0;else if(v=="--regex"||v=="-R")h="regex";else if(v=="--strict"||v=="-S")h="strict";else if(v=="--interactive"||v=="-I")i=!0;else if(v=="--top")d="top";else if(v=="--tab")d="tab";else if(v=="--ignore-case"||v=="--normal"||v=="--no-sort")t.push(v.slice(2));else if(v=="--first")a=!0;else if(v=="--reverse")l=!0;else if(v=="--no-quit")s=!0;else return k.showMessage(`Invalid option "${v}" of list`,"error"),null;let b=this.listMap.get(u);return b?i&&!b.interactive?(k.showMessage(`Interactive mode of "${u}" list not supported`,"error"),null):{list:b,listArgs:g,options:{numberSelect:o,autoPreview:r,reverse:l,noQuit:s,first:a,input:c,interactive:i,matcher:h,position:d,ignorecase:!!t.includes("ignore-case"),mode:t.includes("normal")?"normal":"insert",sort:!t.includes("no-sort")}}:(k.showMessage(`List ${u} not found`,"error"),null)}async onInputChar(e,t,i){if(e!="list")return;let{mode:r}=this.prompt,o=Date.now();if(t==""||this.plugTs&&o-this.plugTs<20){this.plugTs=o;return}if(!!t){if(t==""){await this.cancel();return}r=="insert"?await this.onInsertInput(t,i):await this.onNormalInput(t,i)}}async onInsertInput(e,t){let{session:i}=this;if(!i)return;if(B4.includes(e)){await this.onMouseEvent(e);return}if(!(await i.doNumberSelect(e)||await this.mappings.doInsertKeymap(e)||t)){if(e.startsWith("<")&&e.endsWith(">")){await this.feedkeys(e,!1);return}for(let s of e){let a=s.codePointAt(0);if(a==65533||a<32||a>=127&&a<=159)return;await this.prompt.acceptCharacter(s)}}}async onNormalInput(e,t){if(B4.includes(e)){await this.onMouseEvent(e);return}await this.mappings.doNormalKeymap(e)||await this.feedkeys(e)}onMouseEvent(e){if(this.session)return this.session.onMouseEvent(e)}async feedkeys(e,t=!0){let{nvim:i}=this;e=e.startsWith("<")&&e.endsWith(">")?`\\${e}`:e,await i.call("coc#prompt#stop_prompt",["list"]),await i.call("eval",[`feedkeys("${e}", "${t?"i":"in"}")`]),this.prompt.start()}async command(e){let{nvim:t}=this;await t.call("coc#prompt#stop_prompt",["list"]),await t.command(e),this.prompt.start()}async normal(e,t=!0){let{nvim:i}=this;await i.call("coc#prompt#stop_prompt",["list"]),await i.command(`normal${t?"!":""} ${e}`),this.prompt.start()}async call(e){if(this.session)return await this.session.call(e)}get session(){return this.lastSession}registerList(e){let{name:t}=e,i=this.listMap.get(t);return this.listMap.has(t)&&(i&&(typeof i.dispose=="function"&&i.dispose(),this.listMap.delete(t)),k.showMessage(`list "${t}" recreated.`)),this.listMap.set(t,e),ye.addSchemeProperty(`list.source.${t}.defaultAction`,{type:"string",default:null,description:`Default action of "${t}" list.`}),ye.addSchemeProperty(`list.source.${t}.defaultOptions`,{type:"array",default:e.interactive?["--interactive"]:[],description:`Default list options of "${t}" list, only used when both list option and argument are empty.`,uniqueItems:!0,items:{type:"string",enum:["--top","--normal","--no-sort","--input","--tab","--strict","--regex","--ignore-case","--number-select","--interactive","--auto-preview","--first","--no-quit"]}}),ye.addSchemeProperty(`list.source.${t}.defaultArgs`,{type:"array",default:[],description:`Default argument list of "${t}" list, only used when list argument is empty.`,uniqueItems:!0,items:{type:"string"}}),oD.Disposable.create(()=>{typeof e.dispose=="function"&&e.dispose(),this.listMap.delete(t)})}get names(){return Array.from(this.listMap.keys())}get descriptions(){let e={};for(let t of this.listMap.keys()){let i=this.listMap.get(t);e[t]=i.description}return e}async loadItems(e){let t=[e],i=this.parseArgs(t);if(!i)return;let{list:r,options:o,listArgs:s}=i,l=new oD.CancellationTokenSource().token,u=await this.nvim.eval('[win_getid(),bufnr("%")]'),c=await r.loadItems({options:o,args:s,input:"",cwd:y.cwd,window:this.nvim.createWindow(u[0]),buffer:this.nvim.createBuffer(u[1]),listWindow:null},l);if(!c||Array.isArray(c))return c;let h=c;return await new Promise((g,f)=>{let p=[];h.on("data",b=>{b.label=(0,q4.default)(b.label),p.push(b)}),h.on("end",()=>{g(p)}),h.on("error",b=>{f(b)})})}toggleMode(){let e=this.lastSession;e&&e.toggleMode()}get isActivated(){var e;return((e=this.session)==null?void 0:e.winid)!=null}stop(){let e=this.lastSession;e&&e.stop()}dispose(){for(let e of this.sessionsMap.values())e.dispose();this.sessionsMap.clear(),this.config&&this.config.dispose(),this.lastSession=void 0,Z(this.disposables)}},Di=new Y4});var Z4=m((K8e,W4)=>{W4.exports=["\0","","","","","","","\x07","\b"," ",` -`,"\v","\f","\r","","","","","","","","","","","","","","\x1B","","","",""," ","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","\x7F","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""," ","!","C/","PS","$?","Y=","|","SS",'"',"(c)","a","<<","!","","(r)","-","deg","+-","2","3","'","u","P","*",",","1","o",">>","1/4","1/2","3/4","?","A","A","A","A","A","A","AE","C","E","E","E","E","I","I","I","I","D","N","O","O","O","O","O","x","O","U","U","U","U","U","Th","ss","a","a","a","a","a","a","ae","c","e","e","e","e","i","i","i","i","d","n","o","o","o","o","o","/","o","u","u","u","u","y","th","y"]});var $4=m((z8e,J4)=>{J4.exports=["A","a","A","a","A","a","C","c","C","c","C","c","C","c","D","d","D","d","E","e","E","e","E","e","E","e","E","e","G","g","G","g","G","g","G","g","H","h","H","h","I","i","I","i","I","i","I","i","I","i","IJ","","J","j","K","k","k","L","l","L","l","L","l","L","l","L","l","N","n","N","n","N","n","'n","ng","NG","O","o","O","o","O","o","OE","oe","R","r","R","r","R","r","S","s","S","s","S","s","S","s","T","t","T","t","T","t","U","u","U","u","U","u","U","u","U","u","U","u","W","w","Y","y","Y","Z","z","Z","z","Z","z","s","b","B","B","b","6","6","O","C","c","D","D","D","d","d","3","@","E","F","f","G","G","hv","I","I","K","k","l","l","W","N","n","O","O","o","OI","oi","P","p","YR","2","2","SH","sh","t","T","t","T","U","u","Y","V","Y","y","Z","z","ZH","ZH","zh","zh","2","5","5","ts","w","|","||","|=","!","DZ","Dz","dz","LJ","Lj","lj","NJ","Nj","nj","A","a","I","i","O","o","U","u","U","u","U","u","U","u","U","u","@","A","a","A","a","AE","ae","G","g","G","g","K","k","O","o","O","o","ZH","zh","j","DZ","D","dz","G","g","HV","W","N","n","A","a","AE","ae","O","o"]});var U4=m((V8e,X4)=>{X4.exports=["A","a","A","a","E","e","E","e","I","i","I","i","O","o","O","o","R","r","R","r","U","u","U","u","S","s","T","t","Y","y","H","h","[?]","[?]","OU","ou","Z","z","A","a","E","e","O","o","O","o","O","o","O","o","Y","y","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","a","a","a","b","o","c","d","d","e","@","@","e","e","e","e","j","g","g","g","g","u","Y","h","h","i","i","I","l","l","l","lZ","W","W","m","n","n","n","o","OE","O","F","R","R","R","R","r","r","R","R","R","s","S","j","S","S","t","t","U","U","v","^","W","Y","Y","z","z","Z","Z","?","?","?","C","@","B","E","G","H","j","k","L","q","?","?","dz","dZ","dz","ts","tS","tC","fN","ls","lz","WW","]]","[?]","[?]","k","h","j","r","r","r","r","w","y","'",'"',"`","'","`","`","'","?","?","<",">","^","V","^","V","'","-","/","\\",",","_","\\","/",":",".","`","'","^","V","+","-","V",".","@",",","~",'"',"R","X","G","l","s","x","?","","","","","","","","V","=",'"',"[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var Q4=m((eGe,G4)=>{G4.exports=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","'",",","[?]","[?]","[?]","[?]","","[?]","[?]","[?]","?","[?]","[?]","[?]","[?]","[?]","","","A",";","E","E","I","[?]","O","[?]","U","O","I","A","B","G","D","E","Z","E","Th","I","K","L","M","N","Ks","O","P","R","[?]","S","T","U","Ph","Kh","Ps","O","I","U","a","e","e","i","u","a","b","g","d","e","z","e","th","i","k","l","m","n","x","o","p","r","s","s","t","u","ph","kh","ps","o","i","u","o","u","o","[?]","b","th","U","U","U","ph","p","&","[?]","[?]","St","st","W","w","Q","q","Sp","sp","Sh","sh","F","f","Kh","kh","H","h","G","g","CH","ch","Ti","ti","k","r","c","j","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var z4=m((tGe,K4)=>{K4.exports=["Ie","Io","Dj","Gj","Ie","Dz","I","Yi","J","Lj","Nj","Tsh","Kj","I","U","Dzh","A","B","V","G","D","Ie","Zh","Z","I","I","K","L","M","N","O","P","R","S","T","U","F","Kh","Ts","Ch","Sh","Shch","","Y","'","E","Iu","Ia","a","b","v","gh","d","ie","zh","z","i","i","k","l","m","n","o","p","r","s","t","u","f","kh","ts","ch","sh","shch","","y","'","e","iu","ia","ie","io","dj","gj","ie","dz","i","yi","j","lj","nj","tsh","kj","i","u","dzh","O","o","E","e","Ie","ie","E","e","Ie","ie","O","o","Io","io","Ks","ks","Ps","ps","F","f","Y","y","Y","y","u","u","O","o","O","o","Ot","ot","Q","q","*1000*","","","","","[?]","*100.000*","*1.000.000*","[?]","[?]",'"','"',"R'","r'","G'","g'","G'","g'","G'","g'","Zh'","zh'","Z'","z'","K'","k'","K'","k'","K'","k'","K'","k'","N'","n'","Ng","ng","P'","p'","Kh","kh","S'","s'","T'","t'","U","u","U'","u'","Kh'","kh'","Tts","tts","Ch'","ch'","Ch'","ch'","H","h","Ch","ch","Ch'","ch'","`","Zh","zh","K'","k'","[?]","[?]","N'","n'","[?]","[?]","Ch","ch","[?]","[?]","[?]","a","a","A","a","Ae","ae","Ie","ie","@","@","@","@","Zh","zh","Z","z","Dz","dz","I","i","I","i","O","o","O","o","O","o","E","e","U","u","U","u","U","u","Ch","ch","[?]","[?]","Y","y","[?]","[?]","[?]","[?]","[?]"]});var eQ=m((iGe,V4)=>{V4.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","A","B","G","D","E","Z","E","E","T`","Zh","I","L","Kh","Ts","K","H","Dz","Gh","Ch","M","Y","N","Sh","O","Ch`","P","J","Rh","S","V","T","R","Ts`","W","P`","K`","O","F","[?]","[?]","<","'","/","!",",","?",".","[?]","a","b","g","d","e","z","e","e","t`","zh","i","l","kh","ts","k","h","dz","gh","ch","m","y","n","sh","o","ch`","p","j","rh","s","v","t","r","ts`","w","p`","k`","o","f","ew","[?]",".","-","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","[?]","","","","","","","","","","","","","","@","e","a","o","i","e","e","a","a","o","[?]","u","'","","","","","","",":","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","b","g","d","h","v","z","kh","t","y","k","k","l","m","m","n","n","s","`","p","p","ts","ts","q","r","sh","t","[?]","[?]","[?]","[?]","[?]","V","oy","i","'",'"',"[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var iQ=m((nGe,tQ)=>{tQ.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]",",","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]",";","[?]","[?]","[?]","?","[?]","","a","'","w'","","y'","","b","@","t","th","j","H","kh","d","dh","r","z","s","sh","S","D","T","Z","aa","G","[?]","[?]","[?]","[?]","[?]","","f","q","k","l","m","n","h","w","~","y","an","un","in","a","u","i","W","","","'","'","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","%",".",",","*","[?]","[?]","","'","'","'","","'","'w","'u","'y","tt","tth","b","t","T","p","th","bh","'h","H","ny","dy","H","ch","cch","dd","D","D","Dt","dh","ddh","d","D","D","rr","R","R","R","R","R","R","j","R","S","S","S","S","S","T","GH","F","F","F","v","f","ph","Q","Q","kh","k","K","K","ng","K","g","G","N","G","G","G","L","L","L","L","N","N","N","N","N","h","Ch","hy","h","H","@","W","oe","oe","u","yu","yu","W","v","y","Y","Y","W","","","y","y'",".","ae","","","","","","","","@","#","","","","","","","","","","","^","","","","","[?]","[?]","0","1","2","3","4","5","6","7","8","9","Sh","D","Gh","&","+m"]});var rQ=m((rGe,nQ)=>{nQ.exports=["//","/",",","!","!","-",",",",",";","?","~","{","}","*","[?]","","'","","b","g","g","d","d","h","w","z","H","t","t","y","yh","k","l","m","n","s","s","`","p","p","S","q","r","sh","t","[?]","[?]","[?]","a","a","a","A","A","A","e","e","e","E","i","i","u","u","u","o","","`","'","","","X","Q","@","@","|","+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","h","sh","n","r","b","L","k","'","v","m","f","dh","th","l","g","ny","s","d","z","t","y","p","j","ch","tt","hh","kh","th","z","sh","s","d","t","z","`","gh","q","w","a","aa","i","ee","u","oo","e","ey","o","oa","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var sQ=m((oGe,oQ)=>{oQ.exports=["[?]","N","N","H","[?]","a","aa","i","ii","u","uu","R","L","eN","e","e","ai","oN","o","o","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","nnn","p","ph","b","bh","m","y","r","rr","l","l","lll","v","sh","ss","s","h","[?]","[?]","'","'","aa","i","ii","u","uu","R","RR","eN","e","e","ai","oN","o","o","au","","[?]","[?]","AUM","'","'","`","'","[?]","[?]","[?]","q","khh","ghh","z","dddh","rh","f","yy","RR","LL","L","LL"," / "," // ","0","1","2","3","4","5","6","7","8","9",".","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","N","N","H","[?]","a","aa","i","ii","u","uu","R","RR","[?]","[?]","e","ai","[?]","[?]","o","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","y","r","[?]","l","[?]","[?]","[?]","sh","ss","s","h","[?]","[?]","'","[?]","aa","i","ii","u","uu","R","RR","[?]","[?]","e","ai","[?]","[?]","o","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","[?]","[?]","[?]","[?]","rr","rh","[?]","yy","RR","LL","L","LL","[?]","[?]","0","1","2","3","4","5","6","7","8","9","r'","r`","Rs","Rs","1/","2/","3/","4/"," 1 - 1/","/16","","[?]","[?]","[?]","[?]"]});var lQ=m((sGe,aQ)=>{aQ.exports=["[?]","[?]","N","[?]","[?]","a","aa","i","ii","u","uu","[?]","[?]","[?]","[?]","ee","ai","[?]","[?]","oo","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bb","m","y","r","[?]","l","ll","[?]","v","sh","[?]","s","h","[?]","[?]","'","[?]","aa","i","ii","u","uu","[?]","[?]","[?]","[?]","ee","ai","[?]","[?]","oo","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","khh","ghh","z","rr","[?]","f","[?]","[?]","[?]","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","N","H","","","G.E.O.","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","N","N","H","[?]","a","aa","i","ii","u","uu","R","[?]","eN","[?]","e","ai","oN","[?]","o","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","ya","r","[?]","l","ll","[?]","v","sh","ss","s","h","[?]","[?]","'","'","aa","i","ii","u","uu","R","RR","eN","[?]","e","ai","oN","[?]","o","au","","[?]","[?]","AUM","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","RR","[?]","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var cQ=m((aGe,uQ)=>{uQ.exports=["[?]","N","N","H","[?]","a","aa","i","ii","u","uu","R","L","[?]","[?]","e","ai","[?]","[?]","o","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","y","r","[?]","l","ll","[?]","","sh","ss","s","h","[?]","[?]","'","'","aa","i","ii","u","uu","R","[?]","[?]","[?]","e","ai","[?]","[?]","o","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","+","[?]","[?]","[?]","[?]","rr","rh","[?]","yy","RR","LL","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","N","H","[?]","a","aa","i","ii","u","uu","[?]","[?]","[?]","e","ee","ai","[?]","o","oo","au","k","[?]","[?]","[?]","ng","c","[?]","j","[?]","ny","tt","[?]","[?]","[?]","nn","t","[?]","[?]","[?]","n","nnn","p","[?]","[?]","[?]","m","y","r","rr","l","ll","lll","v","[?]","ss","s","h","[?]","[?]","[?]","[?]","aa","i","ii","u","uu","[?]","[?]","[?]","e","ee","ai","[?]","o","oo","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","+10+","+100+","+1000+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var dQ=m((lGe,hQ)=>{hQ.exports=["[?]","N","N","H","[?]","a","aa","i","ii","u","uu","R","L","[?]","e","ee","ai","[?]","o","oo","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","y","r","rr","l","ll","[?]","v","sh","ss","s","h","[?]","[?]","[?]","[?]","aa","i","ii","u","uu","R","RR","[?]","e","ee","ai","[?]","o","oo","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","RR","LL","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","N","H","[?]","a","aa","i","ii","u","uu","R","L","[?]","e","ee","ai","[?]","o","oo","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","y","r","rr","l","ll","[?]","v","sh","ss","s","h","[?]","[?]","[?]","[?]","aa","i","ii","u","uu","R","RR","[?]","e","ee","ai","[?]","o","oo","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","lll","[?]","RR","LL","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var fQ=m((uGe,gQ)=>{gQ.exports=["[?]","[?]","N","H","[?]","a","aa","i","ii","u","uu","R","L","[?]","e","ee","ai","[?]","o","oo","au","k","kh","g","gh","ng","c","ch","j","jh","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","[?]","p","ph","b","bh","m","y","r","rr","l","ll","lll","v","sh","ss","s","h","[?]","[?]","[?]","[?]","aa","i","ii","u","uu","R","[?]","[?]","e","ee","ai","","o","oo","au","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","RR","LL","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","N","H","[?]","a","aa","ae","aae","i","ii","u","uu","R","RR","L","LL","e","ee","ai","o","oo","au","[?]","[?]","[?]","k","kh","g","gh","ng","nng","c","ch","j","jh","ny","jny","nyj","tt","tth","dd","ddh","nn","nndd","t","th","d","dh","n","[?]","nd","p","ph","b","bh","m","mb","y","r","[?]","l","[?]","[?]","v","sh","ss","s","h","ll","f","[?]","[?]","[?]","","[?]","[?]","[?]","[?]","aa","ae","aae","i","ii","u","[?]","uu","[?]","R","e","ee","ai","o","oo","au","L","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","RR","LL"," . ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var mQ=m((cGe,pQ)=>{pQ.exports=["[?]","k","kh","kh","kh","kh","kh","ng","cch","ch","ch","ch","ch","y","d","t","th","th","th","n","d","t","th","th","th","n","b","p","ph","f","ph","f","ph","m","y","r","R","l","L","w","s","s","s","h","l","`","h","~","a","a","aa","am","i","ii","ue","uue","u","uu","'","[?]","[?]","[?]","[?]","Bh.","e","ae","o","ai","ai","ao","+","","","","","","","M",""," * ","0","1","2","3","4","5","6","7","8","9"," // "," /// ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","k","kh","[?]","kh","[?]","[?]","ng","ch","[?]","s","[?]","[?]","ny","[?]","[?]","[?]","[?]","[?]","[?]","d","h","th","th","[?]","n","b","p","ph","f","ph","f","[?]","m","y","r","[?]","l","[?]","w","[?]","[?]","s","h","[?]","`","","~","a","","aa","am","i","ii","y","yy","u","uu","[?]","o","l","ny","[?]","[?]","e","ei","o","ay","ai","[?]","+","[?]","","","","","","M","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","hn","hm","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var yQ=m((hGe,bQ)=>{bQ.exports=["AUM","","","","","","",""," // "," * ","","-"," / "," / "," // "," -/ "," +/ "," X/ "," /XX/ "," /X/ ",", ","","","","","","","","","","","","0","1","2","3","4","5","6","7","8","9",".5","1.5","2.5","3.5","4.5","5.5","6.5","7.5","8.5","-.5","+","*","^","_","","~","[?]","]","[[","]]","","","k","kh","g","gh","ng","c","ch","j","[?]","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","p","ph","b","bh","m","ts","tsh","dz","dzh","w","zh","z","'","y","r","l","sh","ssh","s","h","a","kss","r","[?]","[?]","[?]","[?]","[?]","[?]","aa","i","ii","u","uu","R","RR","L","LL","e","ee","o","oo","M","H","i","ii","","","","","","","","","","","[?]","[?]","[?]","[?]","k","kh","g","gh","ng","c","ch","j","[?]","ny","tt","tth","dd","ddh","nn","t","th","d","dh","n","p","ph","b","bh","m","ts","tsh","dz","dzh","w","zh","z","'","y","r","l","sh","ss","s","h","a","kss","w","y","r","[?]","X"," :X: "," /O/ "," /o/ "," \\o\\ "," (O) ","","","","","","","","","","[?]","[?]","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var wQ=m((dGe,vQ)=>{vQ.exports=["k","kh","g","gh","ng","c","ch","j","jh","ny","nny","tt","tth","dd","ddh","nn","tt","th","d","dh","n","p","ph","b","bh","m","y","r","l","w","s","h","ll","a","[?]","i","ii","u","uu","e","[?]","o","au","[?]","aa","i","ii","u","uu","e","ai","[?]","[?]","[?]","N","'",":","","[?]","[?]","[?]","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9"," / "," // ","n*","r*","l*","e*","sh","ss","R","RR","L","LL","R","RR","L","LL","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","A","B","G","D","E","V","Z","T`","I","K","L","M","N","O","P","Zh","R","S","T","U","P`","K`","G'","Q","Sh","Ch`","C`","Z'","C","Ch","X","J","H","E","Y","W","Xh","OE","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","a","b","g","d","e","v","z","t`","i","k","l","m","n","o","p","zh","r","s","t","u","p`","k`","g'","q","sh","ch`","c`","z'","c","ch","x","j","h","e","y","w","xh","oe","f","[?]","[?]","[?]","[?]"," // ","[?]","[?]","[?]"]});var xQ=m((gGe,DQ)=>{DQ.exports=["g","gg","n","d","dd","r","m","b","bb","s","ss","","j","jj","c","k","t","p","h","ng","nn","nd","nb","dg","rn","rr","rh","rN","mb","mN","bg","bn","","bs","bsg","bst","bsb","bss","bsj","bj","bc","bt","bp","bN","bbN","sg","sn","sd","sr","sm","sb","sbg","sss","s","sj","sc","sk","st","sp","sh","","","","","Z","g","d","m","b","s","Z","","j","c","t","p","N","j","","","","","ck","ch","","","pb","pN","hh","Q","[?]","[?]","[?]","[?]","[?]","","","a","ae","ya","yae","eo","e","yeo","ye","o","wa","wae","oe","yo","u","weo","we","wi","yu","eu","yi","i","a-o","a-u","ya-o","ya-yo","eo-o","eo-u","eo-eu","yeo-o","yeo-u","o-eo","o-e","o-ye","o-o","o-u","yo-ya","yo-yae","yo-yeo","yo-o","yo-i","u-a","u-ae","u-eo-eu","u-ye","u-u","yu-a","yu-eo","yu-e","yu-yeo","yu-ye","yu-u","yu-i","eu-u","eu-eu","yi-u","i-a","i-ya","i-o","i-u","i-eu","i-U","U","U-eo","U-u","U-i","UU","[?]","[?]","[?]","[?]","[?]","g","gg","gs","n","nj","nh","d","l","lg","lm","lb","ls","lt","lp","lh","m","b","bs","s","ss","ng","j","c","k","t","p","h","gl","gsg","ng","nd","ns","nZ","nt","dg","tl","lgs","ln","ld","lth","ll","lmg","lms","lbs","lbh","rNp","lss","lZ","lk","lQ","mg","ml","mb","ms","mss","mZ","mc","mh","mN","bl","bp","ph","pN","sg","sd","sl","sb","Z","g","ss","","kh","N","Ns","NZ","pb","pN","hn","hl","hm","hb","Q","[?]","[?]","[?]","[?]","[?]"]});var SQ=m((fGe,CQ)=>{CQ.exports=["ha","hu","hi","haa","hee","he","ho","[?]","la","lu","li","laa","lee","le","lo","lwa","hha","hhu","hhi","hhaa","hhee","hhe","hho","hhwa","ma","mu","mi","maa","mee","me","mo","mwa","sza","szu","szi","szaa","szee","sze","szo","szwa","ra","ru","ri","raa","ree","re","ro","rwa","sa","su","si","saa","see","se","so","swa","sha","shu","shi","shaa","shee","she","sho","shwa","qa","qu","qi","qaa","qee","qe","qo","[?]","qwa","[?]","qwi","qwaa","qwee","qwe","[?]","[?]","qha","qhu","qhi","qhaa","qhee","qhe","qho","[?]","qhwa","[?]","qhwi","qhwaa","qhwee","qhwe","[?]","[?]","ba","bu","bi","baa","bee","be","bo","bwa","va","vu","vi","vaa","vee","ve","vo","vwa","ta","tu","ti","taa","tee","te","to","twa","ca","cu","ci","caa","cee","ce","co","cwa","xa","xu","xi","xaa","xee","xe","xo","[?]","xwa","[?]","xwi","xwaa","xwee","xwe","[?]","[?]","na","nu","ni","naa","nee","ne","no","nwa","nya","nyu","nyi","nyaa","nyee","nye","nyo","nywa","'a","'u","[?]","'aa","'ee","'e","'o","'wa","ka","ku","ki","kaa","kee","ke","ko","[?]","kwa","[?]","kwi","kwaa","kwee","kwe","[?]","[?]","kxa","kxu","kxi","kxaa","kxee","kxe","kxo","[?]","kxwa","[?]","kxwi","kxwaa","kxwee","kxwe","[?]","[?]","wa","wu","wi","waa","wee","we","wo","[?]","`a","`u","`i","`aa","`ee","`e","`o","[?]","za","zu","zi","zaa","zee","ze","zo","zwa","zha","zhu","zhi","zhaa","zhee","zhe","zho","zhwa","ya","yu","yi","yaa","yee","ye","yo","[?]","da","du","di","daa","dee","de","do","dwa","dda","ddu","ddi","ddaa","ddee","dde","ddo","ddwa"]});var kQ=m((pGe,TQ)=>{TQ.exports=["ja","ju","ji","jaa","jee","je","jo","jwa","ga","gu","gi","gaa","gee","ge","go","[?]","gwa","[?]","gwi","gwaa","gwee","gwe","[?]","[?]","gga","ggu","ggi","ggaa","ggee","gge","ggo","[?]","tha","thu","thi","thaa","thee","the","tho","thwa","cha","chu","chi","chaa","chee","che","cho","chwa","pha","phu","phi","phaa","phee","phe","pho","phwa","tsa","tsu","tsi","tsaa","tsee","tse","tso","tswa","tza","tzu","tzi","tzaa","tzee","tze","tzo","[?]","fa","fu","fi","faa","fee","fe","fo","fwa","pa","pu","pi","paa","pee","pe","po","pwa","rya","mya","fya","[?]","[?]","[?]","[?]","[?]","[?]"," ",".",",",";",":",":: ","?","//","1","2","3","4","5","6","7","8","9","10+","20+","30+","40+","50+","60+","70+","80+","90+","100+","10,000+","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","a","e","i","o","u","v","ga","ka","ge","gi","go","gu","gv","ha","he","hi","ho","hu","hv","la","le","li","lo","lu","lv","ma","me","mi","mo","mu","na","hna","nah","ne","ni","no","nu","nv","qua","que","qui","quo","quu","quv","sa","s","se","si","so","su","sv","da","ta","de","te","di","ti","do","du","dv","dla","tla","tle","tli","tlo","tlu","tlv","tsa","tse","tsi","tso","tsu","tsv","wa","we","wi","wo","wu","wv","ya","ye","yi","yo","yu","yv","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var PQ=m((mGe,EQ)=>{EQ.exports=["[?]","e","aai","i","ii","o","oo","oo","ee","i","a","aa","we","we","wi","wi","wii","wii","wo","wo","woo","woo","woo","wa","wa","waa","waa","waa","ai","w","'","t","k","sh","s","n","w","n","[?]","w","c","?","l","en","in","on","an","pe","paai","pi","pii","po","poo","poo","hee","hi","pa","paa","pwe","pwe","pwi","pwi","pwii","pwii","pwo","pwo","pwoo","pwoo","pwa","pwa","pwaa","pwaa","pwaa","p","p","h","te","taai","ti","tii","to","too","too","dee","di","ta","taa","twe","twe","twi","twi","twii","twii","two","two","twoo","twoo","twa","twa","twaa","twaa","twaa","t","tte","tti","tto","tta","ke","kaai","ki","kii","ko","koo","koo","ka","kaa","kwe","kwe","kwi","kwi","kwii","kwii","kwo","kwo","kwoo","kwoo","kwa","kwa","kwaa","kwaa","kwaa","k","kw","keh","kih","koh","kah","ce","caai","ci","cii","co","coo","coo","ca","caa","cwe","cwe","cwi","cwi","cwii","cwii","cwo","cwo","cwoo","cwoo","cwa","cwa","cwaa","cwaa","cwaa","c","th","me","maai","mi","mii","mo","moo","moo","ma","maa","mwe","mwe","mwi","mwi","mwii","mwii","mwo","mwo","mwoo","mwoo","mwa","mwa","mwaa","mwaa","mwaa","m","m","mh","m","m","ne","naai","ni","nii","no","noo","noo","na","naa","nwe","nwe","nwa","nwa","nwaa","nwaa","nwaa","n","ng","nh","le","laai","li","lii","lo","loo","loo","la","laa","lwe","lwe","lwi","lwi","lwii","lwii","lwo","lwo","lwoo","lwoo","lwa","lwa","lwaa","lwaa","l","l","l","se","saai","si","sii","so","soo","soo","sa","saa","swe","swe","swi","swi","swii","swii","swo","swo","swoo","swoo"]});var RQ=m((bGe,_Q)=>{_Q.exports=["swa","swa","swaa","swaa","swaa","s","s","sw","s","sk","skw","sW","spwa","stwa","skwa","scwa","she","shi","shii","sho","shoo","sha","shaa","shwe","shwe","shwi","shwi","shwii","shwii","shwo","shwo","shwoo","shwoo","shwa","shwa","shwaa","shwaa","sh","ye","yaai","yi","yii","yo","yoo","yoo","ya","yaa","ywe","ywe","ywi","ywi","ywii","ywii","ywo","ywo","ywoo","ywoo","ywa","ywa","ywaa","ywaa","ywaa","y","y","y","yi","re","re","le","raai","ri","rii","ro","roo","lo","ra","raa","la","rwaa","rwaa","r","r","r","fe","faai","fi","fii","fo","foo","fa","faa","fwaa","fwaa","f","the","the","thi","thi","thii","thii","tho","thoo","tha","thaa","thwaa","thwaa","th","tthe","tthi","ttho","ttha","tth","tye","tyi","tyo","tya","he","hi","hii","ho","hoo","ha","haa","h","h","hk","qaai","qi","qii","qo","qoo","qa","qaa","q","tlhe","tlhi","tlho","tlha","re","ri","ro","ra","ngaai","ngi","ngii","ngo","ngoo","nga","ngaa","ng","nng","she","shi","sho","sha","the","thi","tho","tha","th","lhi","lhii","lho","lhoo","lha","lhaa","lh","the","thi","thii","tho","thoo","tha","thaa","th","b","e","i","o","a","we","wi","wo","wa","ne","ni","no","na","ke","ki","ko","ka","he","hi","ho","ha","ghu","gho","ghe","ghee","ghi","gha","ru","ro","re","ree","ri","ra","wu","wo","we","wee","wi","wa","hwu","hwo","hwe","hwee","hwi","hwa","thu","tho","the","thee","thi","tha","ttu","tto","tte","ttee","tti","tta","pu","po","pe","pee","pi","pa","p","gu","go","ge","gee","gi","ga","khu","kho","khe","khee","khi","kha","kku","kko","kke","kkee","kki"]});var FQ=m((yGe,LQ)=>{LQ.exports=["kka","kk","nu","no","ne","nee","ni","na","mu","mo","me","mee","mi","ma","yu","yo","ye","yee","yi","ya","ju","ju","jo","je","jee","ji","ji","ja","jju","jjo","jje","jjee","jji","jja","lu","lo","le","lee","li","la","dlu","dlo","dle","dlee","dli","dla","lhu","lho","lhe","lhee","lhi","lha","tlhu","tlho","tlhe","tlhee","tlhi","tlha","tlu","tlo","tle","tlee","tli","tla","zu","zo","ze","zee","zi","za","z","z","dzu","dzo","dze","dzee","dzi","dza","su","so","se","see","si","sa","shu","sho","she","shee","shi","sha","sh","tsu","tso","tse","tsee","tsi","tsa","chu","cho","che","chee","chi","cha","ttsu","ttso","ttse","ttsee","ttsi","ttsa","X",".","qai","ngai","nngi","nngii","nngo","nngoo","nnga","nngaa","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"," ","b","l","f","s","n","h","d","t","c","q","m","g","ng","z","r","a","o","u","e","i","ch","th","ph","p","x","p","<",">","[?]","[?]","[?]","f","v","u","yr","y","w","th","th","a","o","ac","ae","o","o","o","oe","on","r","k","c","k","g","ng","g","g","w","h","h","h","h","n","n","n","i","e","j","g","ae","a","eo","p","z","s","s","s","c","z","t","t","d","b","b","p","p","e","m","m","m","l","l","ng","ng","d","o","ear","ior","qu","qu","qu","s","yr","yr","yr","q","x",".",":","+","17","18","19","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var jQ=m((vGe,IQ)=>{IQ.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","k","kh","g","gh","ng","c","ch","j","jh","ny","t","tth","d","ddh","nn","t","th","d","dh","n","p","ph","b","bh","m","y","r","l","v","sh","ss","s","h","l","q","a","aa","i","ii","u","uk","uu","uuv","ry","ryy","ly","lyy","e","ai","oo","oo","au","a","aa","aa","i","ii","y","yy","u","uu","ua","oe","ya","ie","e","ae","ai","oo","au","M","H","a`","","","","r","","!","","","","","","."," // ",":","+","++"," * "," /// ","KR","'","[?]","[?]","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var OQ=m((wGe,AQ)=>{AQ.exports=[" @ "," ... ",", ",". ",": "," // ","","-",", ",". ","","","","","","[?]","0","1","2","3","4","5","6","7","8","9","[?]","[?]","[?]","[?]","[?]","[?]","a","e","i","o","u","O","U","ee","n","ng","b","p","q","g","m","l","s","sh","t","d","ch","j","y","r","w","f","k","kha","ts","z","h","zr","lh","zh","ch","-","e","i","o","u","O","U","ng","b","p","q","g","m","t","d","ch","j","ts","y","w","k","g","h","jy","ny","dz","e","i","iy","U","u","ng","k","g","h","p","sh","t","d","j","f","g","h","ts","z","r","ch","zh","i","k","r","f","zh","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","H","X","W","M"," 3 "," 333 ","a","i","k","ng","c","tt","tth","dd","nn","t","d","p","ph","ss","zh","z","a","t","zh","gh","ng","c","jh","tta","ddh","t","dh","ss","cy","zh","z","u","y","bh","'","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var NQ=m((DGe,MQ)=>{MQ.exports=["A","a","B","b","B","b","B","b","C","c","D","d","D","d","D","d","D","d","D","d","E","e","E","e","E","e","E","e","E","e","F","f","G","g","H","h","H","h","H","h","H","h","H","h","I","i","I","i","K","k","K","k","K","k","L","l","L","l","L","l","L","l","M","m","M","m","M","m","N","n","N","n","N","n","N","n","O","o","O","o","O","o","O","o","P","p","P","p","R","r","R","r","R","r","R","r","S","s","S","s","S","s","S","s","S","s","T","t","T","t","T","t","T","t","U","u","U","u","U","u","U","u","U","u","V","v","V","v","W","w","W","w","W","w","W","w","W","w","X","x","X","x","Y","y","Z","z","Z","z","Z","z","h","t","w","y","a","S","[?]","[?]","[?]","[?]","A","a","A","a","A","a","A","a","A","a","A","a","A","a","A","a","A","a","A","a","A","a","A","a","E","e","E","e","E","e","E","e","E","e","E","e","E","e","E","e","I","i","I","i","O","o","O","o","O","o","O","o","O","o","O","o","O","o","O","o","O","o","O","o","O","o","O","o","U","u","U","u","U","u","U","u","U","u","U","u","U","u","Y","y","Y","y","Y","y","Y","y","[?]","[?]","[?]","[?]","[?]"]});var HQ=m((xGe,BQ)=>{BQ.exports=["a","a","a","a","a","a","a","a","A","A","A","A","A","A","A","A","e","e","e","e","e","e","[?]","[?]","E","E","E","E","E","E","[?]","[?]","e","e","e","e","e","e","e","e","E","E","E","E","E","E","E","E","i","i","i","i","i","i","i","i","I","I","I","I","I","I","I","I","o","o","o","o","o","o","[?]","[?]","O","O","O","O","O","O","[?]","[?]","u","u","u","u","u","u","u","u","[?]","U","[?]","U","[?]","U","[?]","U","o","o","o","o","o","o","o","o","O","O","O","O","O","O","O","O","a","a","e","e","e","e","i","i","o","o","u","u","o","o","[?]","[?]","a","a","a","a","a","a","a","a","A","A","A","A","A","A","A","A","e","e","e","e","e","e","e","e","E","E","E","E","E","E","E","E","o","o","o","o","o","o","o","o","O","O","O","O","O","O","O","O","a","a","a","a","a","[?]","a","a","A","A","A","A","A","'","i","'","~",'"~',"e","e","e","[?]","e","e","E","E","E","E","E","'`","''","'~","i","i","i","i","[?]","[?]","i","i","I","I","I","I","[?]","`'","`'","`~","u","u","u","u","R","R","u","u","U","U","U","U","R",'"`',`"'`,"`","[?]","[?]","o","o","o","[?]","o","o","O","O","O","O","O","'","`"]});var YQ=m((CGe,qQ)=>{qQ.exports=[" "," "," "," "," "," "," "," "," "," "," "," ","","","","","-","-","-","-","--","--","||","_","'","'",",","'",'"','"',",,",'"',"+","++","*","*>",".","..","...",".",` -`,` - -`,"","","","",""," ","%0","%00","'","''","'''","`","``","```","^","<",">","*","!!","!?","-","_","-","^","***","--","/","-[","]-","[?]","?!","!?","7","PP","(]","[)","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","0","","","","4","5","6","7","8","9","+","-","=","(",")","n","0","1","2","3","4","5","6","7","8","9","+","-","=","(",")","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","ECU","CL","Cr","FF","L","mil","N","Pts","Rs","W","NS","D","EU","K","T","Dr","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var ZQ=m((SGe,WQ)=>{WQ.exports=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"," 1/3 "," 2/3 "," 1/5 "," 2/5 "," 3/5 "," 4/5 "," 1/6 "," 5/6 "," 1/8 "," 3/8 "," 5/8 "," 7/8 "," 1/","I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII","L","C","D","M","i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","l","c","d","m","(D","D)","((|))",")","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","-","|","-","|","-","|","\\","/","\\","/","-","-","~","~","-","|","-","|","-","-","-","|","-","|","|","-","-","-","-","-","-","|","|","|","|","|","|","|","^","V","\\","=","V","^","-","-","|","|","-","-","|","|","=","|","=","=","|","=","|","=","=","=","=","=","=","|","=","|","=","|","\\","/","\\","/","=","=","~","~","|","|","-","|","-","|","-","-","-","|","-","|","|","|","|","|","|","|","-","\\","\\","|","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var $Q=m((TGe,JQ)=>{JQ.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var UQ=m((kGe,XQ)=>{XQ.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var QQ=m((EGe,GQ)=>{GQ.exports=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var zQ=m((PGe,KQ)=>{KQ.exports=["-","-","|","|","-","-","|","|","-","-","|","|","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","-","-","|","|","-","|","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","+","/","\\","X","-","|","-","|","-","|","-","|","-","|","-","|","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","-","|","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","#","^","^","^","^",">",">",">",">",">",">","V","V","V","V","<","<","<","<","<","<","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","*","#","#","#","#","#","^","^","^","O","#","#","#","#","#","#","#","#","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var eK=m((_Ge,VQ)=>{VQ.exports=["","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var iK=m((RGe,tK)=>{tK.exports=["[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var rK=m((LGe,nK)=>{nK.exports=[" ","a","1","b","'","k","2","l","@","c","i","f","/","m","s","p",'"',"e","3","h","9","o","6","r","^","d","j","g",">","n","t","q",",","*","5","<","-","u","8","v",".","%","[","$","+","x","!","&",";",":","4","\\","0","z","7","(","_","?","w","]","#","y",")","=","[d7]","[d17]","[d27]","[d127]","[d37]","[d137]","[d237]","[d1237]","[d47]","[d147]","[d247]","[d1247]","[d347]","[d1347]","[d2347]","[d12347]","[d57]","[d157]","[d257]","[d1257]","[d357]","[d1357]","[d2357]","[d12357]","[d457]","[d1457]","[d2457]","[d12457]","[d3457]","[d13457]","[d23457]","[d123457]","[d67]","[d167]","[d267]","[d1267]","[d367]","[d1367]","[d2367]","[d12367]","[d467]","[d1467]","[d2467]","[d12467]","[d3467]","[d13467]","[d23467]","[d123467]","[d567]","[d1567]","[d2567]","[d12567]","[d3567]","[d13567]","[d23567]","[d123567]","[d4567]","[d14567]","[d24567]","[d124567]","[d34567]","[d134567]","[d234567]","[d1234567]","[d8]","[d18]","[d28]","[d128]","[d38]","[d138]","[d238]","[d1238]","[d48]","[d148]","[d248]","[d1248]","[d348]","[d1348]","[d2348]","[d12348]","[d58]","[d158]","[d258]","[d1258]","[d358]","[d1358]","[d2358]","[d12358]","[d458]","[d1458]","[d2458]","[d12458]","[d3458]","[d13458]","[d23458]","[d123458]","[d68]","[d168]","[d268]","[d1268]","[d368]","[d1368]","[d2368]","[d12368]","[d468]","[d1468]","[d2468]","[d12468]","[d3468]","[d13468]","[d23468]","[d123468]","[d568]","[d1568]","[d2568]","[d12568]","[d3568]","[d13568]","[d23568]","[d123568]","[d4568]","[d14568]","[d24568]","[d124568]","[d34568]","[d134568]","[d234568]","[d1234568]","[d78]","[d178]","[d278]","[d1278]","[d378]","[d1378]","[d2378]","[d12378]","[d478]","[d1478]","[d2478]","[d12478]","[d3478]","[d13478]","[d23478]","[d123478]","[d578]","[d1578]","[d2578]","[d12578]","[d3578]","[d13578]","[d23578]","[d123578]","[d4578]","[d14578]","[d24578]","[d124578]","[d34578]","[d134578]","[d234578]","[d1234578]","[d678]","[d1678]","[d2678]","[d12678]","[d3678]","[d13678]","[d23678]","[d123678]","[d4678]","[d14678]","[d24678]","[d124678]","[d34678]","[d134678]","[d234678]","[d1234678]","[d5678]","[d15678]","[d25678]","[d125678]","[d35678]","[d135678]","[d235678]","[d1235678]","[d45678]","[d145678]","[d245678]","[d1245678]","[d345678]","[d1345678]","[d2345678]","[d12345678]"]});var sK=m((FGe,oK)=>{oK.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?]","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var lK=m((IGe,aK)=>{aK.exports=["[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?]","[?]","[?]"]});var cK=m((jGe,uK)=>{uK.exports=[" ",", ",". ",'"',"[JIS]",'"',"/","0","<","> ","<<",">> ","[","] ","{","} ","[(",")] ","@","X ","[","] ","[[","]] ","((",")) ","[[","]] ","~ ","``","''",",,","@","1","2","3","4","5","6","7","8","9","","","","","","","~","+","+","+","+","","@"," // ","+10+","+20+","+30+","[?]","[?]","[?]","","","[?]","a","a","i","i","u","u","e","e","o","o","ka","ga","ki","gi","ku","gu","ke","ge","ko","go","sa","za","si","zi","su","zu","se","ze","so","zo","ta","da","ti","di","tu","tu","du","te","de","to","do","na","ni","nu","ne","no","ha","ba","pa","hi","bi","pi","hu","bu","pu","he","be","pe","ho","bo","po","ma","mi","mu","me","mo","ya","ya","yu","yu","yo","yo","ra","ri","ru","re","ro","wa","wa","wi","we","wo","n","vu","[?]","[?]","[?]","[?]","","","","",'"','"',"[?]","[?]","a","a","i","i","u","u","e","e","o","o","ka","ga","ki","gi","ku","gu","ke","ge","ko","go","sa","za","si","zi","su","zu","se","ze","so","zo","ta","da","ti","di","tu","tu","du","te","de","to","do","na","ni","nu","ne","no","ha","ba","pa","hi","bi","pi","hu","bu","pu","he","be","pe","ho","bo","po","ma","mi","mu","me","mo","ya","ya","yu","yu","yo","yo","ra","ri","ru","re","ro","wa","wa","wi","we","wo","n","vu","ka","ke","va","vi","ve","vo","","",'"','"']});var dK=m((AGe,hK)=>{hK.exports=["[?]","[?]","[?]","[?]","[?]","B","P","M","F","D","T","N","L","G","K","H","J","Q","X","ZH","CH","SH","R","Z","C","S","A","O","E","EH","AI","EI","AU","OU","AN","EN","ANG","ENG","ER","I","U","IU","V","NG","GN","[?]","[?]","[?]","[?]","g","gg","gs","n","nj","nh","d","dd","r","lg","lm","lb","ls","lt","lp","rh","m","b","bb","bs","s","ss","","j","jj","c","k","t","p","h","a","ae","ya","yae","eo","e","yeo","ye","o","wa","wae","oe","yo","u","weo","we","wi","yu","eu","yi","i","","nn","nd","ns","nZ","lgs","ld","lbs","lZ","lQ","mb","ms","mZ","mN","bg","","bsg","bst","bj","bt","bN","bbN","sg","sn","sd","sb","sj","Z","","N","Ns","NZ","pN","hh","Q","yo-ya","yo-yae","yo-i","yu-yeo","yu-ye","yu-i","U","U-i","[?]","","","","","","","","","","","","","","","","","BU","ZI","JI","GU","EE","ENN","OO","ONN","IR","ANN","INN","UNN","IM","NGG","AINN","AUNN","AM","OM","ONG","INNN","P","T","K","H","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var fK=m((OGe,gK)=>{gK.exports=["(g)","(n)","(d)","(r)","(m)","(b)","(s)","()","(j)","(c)","(k)","(t)","(p)","(h)","(ga)","(na)","(da)","(ra)","(ma)","(ba)","(sa)","(a)","(ja)","(ca)","(ka)","(ta)","(pa)","(ha)","(ju)","[?]","[?]","[?]","(1) ","(2) ","(3) ","(4) ","(5) ","(6) ","(7) ","(8) ","(9) ","(10) ","(Yue) ","(Huo) ","(Shui) ","(Mu) ","(Jin) ","(Tu) ","(Ri) ","(Zhu) ","(You) ","(She) ","(Ming) ","(Te) ","(Cai) ","(Zhu) ","(Lao) ","(Dai) ","(Hu) ","(Xue) ","(Jian) ","(Qi) ","(Zi) ","(Xie) ","(Ji) ","(Xiu) ","<<",">>","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","(g)","(n)","(d)","(r)","(m)","(b)","(s)","()","(j)","(c)","(k)","(t)","(p)","(h)","(ga)","(na)","(da)","(ra)","(ma)","(ba)","(sa)","(a)","(ja)","(ca)","(ka)","(ta)","(pa)","(ha)","[?]","[?]","[?]","KIS ","(1) ","(2) ","(3) ","(4) ","(5) ","(6) ","(7) ","(8) ","(9) ","(10) ","(Yue) ","(Huo) ","(Shui) ","(Mu) ","(Jin) ","(Tu) ","(Ri) ","(Zhu) ","(You) ","(She) ","(Ming) ","(Te) ","(Cai) ","(Zhu) ","(Lao) ","(Mi) ","(Nan) ","(Nu) ","(Shi) ","(You) ","(Yin) ","(Zhu) ","(Xiang) ","(Xiu) ","(Xie) ","(Zheng) ","(Shang) ","(Zhong) ","(Xia) ","(Zuo) ","(You) ","(Yi) ","(Zong) ","(Xue) ","(Jian) ","(Qi) ","(Zi) ","(Xie) ","(Ye) ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","1M","2M","3M","4M","5M","6M","7M","8M","9M","10M","11M","12M","[?]","[?]","[?]","[?]","a","i","u","u","o","ka","ki","ku","ke","ko","sa","si","su","se","so","ta","ti","tu","te","to","na","ni","nu","ne","no","ha","hi","hu","he","ho","ma","mi","mu","me","mo","ya","yu","yo","ra","ri","ru","re","ro","wa","wi","we","wo"]});var mK=m((MGe,pK)=>{pK.exports=["apartment","alpha","ampere","are","inning","inch","won","escudo","acre","ounce","ohm","kai-ri","carat","calorie","gallon","gamma","giga","guinea","curie","guilder","kilo","kilogram","kilometer","kilowatt","gram","gram ton","cruzeiro","krone","case","koruna","co-op","cycle","centime","shilling","centi","cent","dozen","desi","dollar","ton","nano","knot","heights","percent","parts","barrel","piaster","picul","pico","building","farad","feet","bushel","franc","hectare","peso","pfennig","hertz","pence","page","beta","point","volt","hon","pound","hall","horn","micro","mile","mach","mark","mansion","micron","milli","millibar","mega","megaton","meter","yard","yard","yuan","liter","lira","rupee","ruble","rem","roentgen","watt","0h","1h","2h","3h","4h","5h","6h","7h","8h","9h","10h","11h","12h","13h","14h","15h","16h","17h","18h","19h","20h","21h","22h","23h","24h","HPA","da","AU","bar","oV","pc","[?]","[?]","[?]","[?]","Heisei","Syouwa","Taisyou","Meiji","Inc.","pA","nA","microamp","mA","kA","kB","MB","GB","cal","kcal","pF","nF","microFarad","microgram","mg","kg","Hz","kHz","MHz","GHz","THz","microliter","ml","dl","kl","fm","nm","micrometer","mm","cm","km","mm^2","cm^2","m^2","km^2","mm^4","cm^3","m^3","km^3","m/s","m/s^2","Pa","kPa","MPa","GPa","rad","rad/s","rad/s^2","ps","ns","microsecond","ms","pV","nV","microvolt","mV","kV","MV","pW","nW","microwatt","mW","kW","MW","kOhm","MOhm","a.m.","Bq","cc","cd","C/kg","Co.","dB","Gy","ha","HP","in","K.K.","KM","kt","lm","ln","log","lx","mb","mil","mol","pH","p.m.","PPM","PR","sr","Sv","Wb","[?]","[?]","1d","2d","3d","4d","5d","6d","7d","8d","9d","10d","11d","12d","13d","14d","15d","16d","17d","18d","19d","20d","21d","22d","23d","24d","25d","26d","27d","28d","29d","30d","31d"]});var yK=m((NGe,bK)=>{bK.exports=["[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?] ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var wK=m((BGe,vK)=>{vK.exports=["Yi ","Ding ","Kao ","Qi ","Shang ","Xia ","[?] ","Mo ","Zhang ","San ","Shang ","Xia ","Ji ","Bu ","Yu ","Mian ","Gai ","Chou ","Chou ","Zhuan ","Qie ","Pi ","Shi ","Shi ","Qiu ","Bing ","Ye ","Cong ","Dong ","Si ","Cheng ","Diu ","Qiu ","Liang ","Diu ","You ","Liang ","Yan ","Bing ","Sang ","Gun ","Jiu ","Ge ","Ya ","Qiang ","Zhong ","Ji ","Jie ","Feng ","Guan ","Chuan ","Chan ","Lin ","Zhuo ","Zhu ","Ha ","Wan ","Dan ","Wei ","Zhu ","Jing ","Li ","Ju ","Pie ","Fu ","Yi ","Yi ","Nai ","Shime ","Jiu ","Jiu ","Zhe ","Yao ","Yi ","[?] ","Zhi ","Wu ","Zha ","Hu ","Fa ","Le ","Zhong ","Ping ","Pang ","Qiao ","Hu ","Guai ","Cheng ","Cheng ","Yi ","Yin ","[?] ","Mie ","Jiu ","Qi ","Ye ","Xi ","Xiang ","Gai ","Diu ","Hal ","[?] ","Shu ","Twul ","Shi ","Ji ","Nang ","Jia ","Kel ","Shi ","[?] ","Ol ","Mai ","Luan ","Cal ","Ru ","Xue ","Yan ","Fu ","Sha ","Na ","Gan ","Sol ","El ","Cwul ","[?] ","Gan ","Chi ","Gui ","Gan ","Luan ","Lin ","Yi ","Jue ","Liao ","Ma ","Yu ","Zheng ","Shi ","Shi ","Er ","Chu ","Yu ","Yu ","Yu ","Yun ","Hu ","Qi ","Wu ","Jing ","Si ","Sui ","Gen ","Gen ","Ya ","Xie ","Ya ","Qi ","Ya ","Ji ","Tou ","Wang ","Kang ","Ta ","Jiao ","Hai ","Yi ","Chan ","Heng ","Mu ","[?] ","Xiang ","Jing ","Ting ","Liang ","Xiang ","Jing ","Ye ","Qin ","Bo ","You ","Xie ","Dan ","Lian ","Duo ","Wei ","Ren ","Ren ","Ji ","La ","Wang ","Yi ","Shi ","Ren ","Le ","Ding ","Ze ","Jin ","Pu ","Chou ","Ba ","Zhang ","Jin ","Jie ","Bing ","Reng ","Cong ","Fo ","San ","Lun ","Sya ","Cang ","Zi ","Shi ","Ta ","Zhang ","Fu ","Xian ","Xian ","Tuo ","Hong ","Tong ","Ren ","Qian ","Gan ","Yi ","Di ","Dai ","Ling ","Yi ","Chao ","Chang ","Sa ","[?] ","Yi ","Mu ","Men ","Ren ","Jia ","Chao ","Yang ","Qian ","Zhong ","Pi ","Wan ","Wu ","Jian ","Jie ","Yao ","Feng ","Cang ","Ren ","Wang ","Fen ","Di ","Fang "]});var xK=m((HGe,DK)=>{DK.exports=["Zhong ","Qi ","Pei ","Yu ","Diao ","Dun ","Wen ","Yi ","Xin ","Kang ","Yi ","Ji ","Ai ","Wu ","Ji ","Fu ","Fa ","Xiu ","Jin ","Bei ","Dan ","Fu ","Tang ","Zhong ","You ","Huo ","Hui ","Yu ","Cui ","Chuan ","San ","Wei ","Chuan ","Che ","Ya ","Xian ","Shang ","Chang ","Lun ","Cang ","Xun ","Xin ","Wei ","Zhu ","[?] ","Xuan ","Nu ","Bo ","Gu ","Ni ","Ni ","Xie ","Ban ","Xu ","Ling ","Zhou ","Shen ","Qu ","Si ","Beng ","Si ","Jia ","Pi ","Yi ","Si ","Ai ","Zheng ","Dian ","Han ","Mai ","Dan ","Zhu ","Bu ","Qu ","Bi ","Shao ","Ci ","Wei ","Di ","Zhu ","Zuo ","You ","Yang ","Ti ","Zhan ","He ","Bi ","Tuo ","She ","Yu ","Yi ","Fo ","Zuo ","Kou ","Ning ","Tong ","Ni ","Xuan ","Qu ","Yong ","Wa ","Qian ","[?] ","Ka ","[?] ","Pei ","Huai ","He ","Lao ","Xiang ","Ge ","Yang ","Bai ","Fa ","Ming ","Jia ","Er ","Bing ","Ji ","Hen ","Huo ","Gui ","Quan ","Tiao ","Jiao ","Ci ","Yi ","Shi ","Xing ","Shen ","Tuo ","Kan ","Zhi ","Gai ","Lai ","Yi ","Chi ","Kua ","Guang ","Li ","Yin ","Shi ","Mi ","Zhu ","Xu ","You ","An ","Lu ","Mou ","Er ","Lun ","Tong ","Cha ","Chi ","Xun ","Gong ","Zhou ","Yi ","Ru ","Jian ","Xia ","Jia ","Zai ","Lu ","Ko ","Jiao ","Zhen ","Ce ","Qiao ","Kuai ","Chai ","Ning ","Nong ","Jin ","Wu ","Hou ","Jiong ","Cheng ","Zhen ","Zuo ","Chou ","Qin ","Lu ","Ju ","Shu ","Ting ","Shen ","Tuo ","Bo ","Nan ","Hao ","Bian ","Tui ","Yu ","Xi ","Cu ","E ","Qiu ","Xu ","Kuang ","Ku ","Wu ","Jun ","Yi ","Fu ","Lang ","Zu ","Qiao ","Li ","Yong ","Hun ","Jing ","Xian ","San ","Pai ","Su ","Fu ","Xi ","Li ","Fu ","Ping ","Bao ","Yu ","Si ","Xia ","Xin ","Xiu ","Yu ","Ti ","Che ","Chou ","[?] ","Yan ","Lia ","Li ","Lai ","[?] ","Jian ","Xiu ","Fu ","He ","Ju ","Xiao ","Pai ","Jian ","Biao ","Chu ","Fei ","Feng ","Ya ","An ","Bei ","Yu ","Xin ","Bi ","Jian "]});var SK=m((qGe,CK)=>{CK.exports=["Chang ","Chi ","Bing ","Zan ","Yao ","Cui ","Lia ","Wan ","Lai ","Cang ","Zong ","Ge ","Guan ","Bei ","Tian ","Shu ","Shu ","Men ","Dao ","Tan ","Jue ","Chui ","Xing ","Peng ","Tang ","Hou ","Yi ","Qi ","Ti ","Gan ","Jing ","Jie ","Sui ","Chang ","Jie ","Fang ","Zhi ","Kong ","Juan ","Zong ","Ju ","Qian ","Ni ","Lun ","Zhuo ","Wei ","Luo ","Song ","Leng ","Hun ","Dong ","Zi ","Ben ","Wu ","Ju ","Nai ","Cai ","Jian ","Zhai ","Ye ","Zhi ","Sha ","Qing ","[?] ","Ying ","Cheng ","Jian ","Yan ","Nuan ","Zhong ","Chun ","Jia ","Jie ","Wei ","Yu ","Bing ","Ruo ","Ti ","Wei ","Pian ","Yan ","Feng ","Tang ","Wo ","E ","Xie ","Che ","Sheng ","Kan ","Di ","Zuo ","Cha ","Ting ","Bei ","Ye ","Huang ","Yao ","Zhan ","Chou ","Yan ","You ","Jian ","Xu ","Zha ","Ci ","Fu ","Bi ","Zhi ","Zong ","Mian ","Ji ","Yi ","Xie ","Xun ","Si ","Duan ","Ce ","Zhen ","Ou ","Tou ","Tou ","Bei ","Za ","Lu ","Jie ","Wei ","Fen ","Chang ","Gui ","Sou ","Zhi ","Su ","Xia ","Fu ","Yuan ","Rong ","Li ","Ru ","Yun ","Gou ","Ma ","Bang ","Dian ","Tang ","Hao ","Jie ","Xi ","Shan ","Qian ","Jue ","Cang ","Chu ","San ","Bei ","Xiao ","Yong ","Yao ","Tan ","Suo ","Yang ","Fa ","Bing ","Jia ","Dai ","Zai ","Tang ","[?] ","Bin ","Chu ","Nuo ","Can ","Lei ","Cui ","Yong ","Zao ","Zong ","Peng ","Song ","Ao ","Chuan ","Yu ","Zhai ","Cou ","Shang ","Qiang ","Jing ","Chi ","Sha ","Han ","Zhang ","Qing ","Yan ","Di ","Xi ","Lu ","Bei ","Piao ","Jin ","Lian ","Lu ","Man ","Qian ","Xian ","Tan ","Ying ","Dong ","Zhuan ","Xiang ","Shan ","Qiao ","Jiong ","Tui ","Zun ","Pu ","Xi ","Lao ","Chang ","Guang ","Liao ","Qi ","Deng ","Chan ","Wei ","Ji ","Fan ","Hui ","Chuan ","Jian ","Dan ","Jiao ","Jiu ","Seng ","Fen ","Xian ","Jue ","E ","Jiao ","Jian ","Tong ","Lin ","Bo ","Gu ","[?] ","Su ","Xian ","Jiang ","Min ","Ye ","Jin ","Jia ","Qiao ","Pi ","Feng ","Zhou ","Ai ","Sai "]});var kK=m((YGe,TK)=>{TK.exports=["Yi ","Jun ","Nong ","Chan ","Yi ","Dang ","Jing ","Xuan ","Kuai ","Jian ","Chu ","Dan ","Jiao ","Sha ","Zai ","[?] ","Bin ","An ","Ru ","Tai ","Chou ","Chai ","Lan ","Ni ","Jin ","Qian ","Meng ","Wu ","Ning ","Qiong ","Ni ","Chang ","Lie ","Lei ","Lu ","Kuang ","Bao ","Du ","Biao ","Zan ","Zhi ","Si ","You ","Hao ","Chen ","Chen ","Li ","Teng ","Wei ","Long ","Chu ","Chan ","Rang ","Shu ","Hui ","Li ","Luo ","Zan ","Nuo ","Tang ","Yan ","Lei ","Nang ","Er ","Wu ","Yun ","Zan ","Yuan ","Xiong ","Chong ","Zhao ","Xiong ","Xian ","Guang ","Dui ","Ke ","Dui ","Mian ","Tu ","Chang ","Er ","Dui ","Er ","Xin ","Tu ","Si ","Yan ","Yan ","Shi ","Shi ","Dang ","Qian ","Dou ","Fen ","Mao ","Shen ","Dou ","Bai ","Jing ","Li ","Huang ","Ru ","Wang ","Nei ","Quan ","Liang ","Yu ","Ba ","Gong ","Liu ","Xi ","[?] ","Lan ","Gong ","Tian ","Guan ","Xing ","Bing ","Qi ","Ju ","Dian ","Zi ","Ppwun ","Yang ","Jian ","Shou ","Ji ","Yi ","Ji ","Chan ","Jiong ","Mao ","Ran ","Nei ","Yuan ","Mao ","Gang ","Ran ","Ce ","Jiong ","Ce ","Zai ","Gua ","Jiong ","Mao ","Zhou ","Mou ","Gou ","Xu ","Mian ","Mi ","Rong ","Yin ","Xie ","Kan ","Jun ","Nong ","Yi ","Mi ","Shi ","Guan ","Meng ","Zhong ","Ju ","Yuan ","Ming ","Kou ","Lam ","Fu ","Xie ","Mi ","Bing ","Dong ","Tai ","Gang ","Feng ","Bing ","Hu ","Chong ","Jue ","Hu ","Kuang ","Ye ","Leng ","Pan ","Fu ","Min ","Dong ","Xian ","Lie ","Xia ","Jian ","Jing ","Shu ","Mei ","Tu ","Qi ","Gu ","Zhun ","Song ","Jing ","Liang ","Qing ","Diao ","Ling ","Dong ","Gan ","Jian ","Yin ","Cou ","Yi ","Li ","Cang ","Ming ","Zhuen ","Cui ","Si ","Duo ","Jin ","Lin ","Lin ","Ning ","Xi ","Du ","Ji ","Fan ","Fan ","Fan ","Feng ","Ju ","Chu ","Tako ","Feng ","Mok ","Ci ","Fu ","Feng ","Ping ","Feng ","Kai ","Huang ","Kai ","Gan ","Deng ","Ping ","Qu ","Xiong ","Kuai ","Tu ","Ao ","Chu ","Ji ","Dang ","Han ","Han ","Zao "]});var PK=m((WGe,EK)=>{EK.exports=["Dao ","Diao ","Dao ","Ren ","Ren ","Chuang ","Fen ","Qie ","Yi ","Ji ","Kan ","Qian ","Cun ","Chu ","Wen ","Ji ","Dan ","Xing ","Hua ","Wan ","Jue ","Li ","Yue ","Lie ","Liu ","Ze ","Gang ","Chuang ","Fu ","Chu ","Qu ","Ju ","Shan ","Min ","Ling ","Zhong ","Pan ","Bie ","Jie ","Jie ","Bao ","Li ","Shan ","Bie ","Chan ","Jing ","Gua ","Gen ","Dao ","Chuang ","Kui ","Ku ","Duo ","Er ","Zhi ","Shua ","Quan ","Cha ","Ci ","Ke ","Jie ","Gui ","Ci ","Gui ","Kai ","Duo ","Ji ","Ti ","Jing ","Lou ","Gen ","Ze ","Yuan ","Cuo ","Xue ","Ke ","La ","Qian ","Cha ","Chuang ","Gua ","Jian ","Cuo ","Li ","Ti ","Fei ","Pou ","Chan ","Qi ","Chuang ","Zi ","Gang ","Wan ","Bo ","Ji ","Duo ","Qing ","Yan ","Zhuo ","Jian ","Ji ","Bo ","Yan ","Ju ","Huo ","Sheng ","Jian ","Duo ","Duan ","Wu ","Gua ","Fu ","Sheng ","Jian ","Ge ","Zha ","Kai ","Chuang ","Juan ","Chan ","Tuan ","Lu ","Li ","Fou ","Shan ","Piao ","Kou ","Jiao ","Gua ","Qiao ","Jue ","Hua ","Zha ","Zhuo ","Lian ","Ju ","Pi ","Liu ","Gui ","Jiao ","Gui ","Jian ","Jian ","Tang ","Huo ","Ji ","Jian ","Yi ","Jian ","Zhi ","Chan ","Cuan ","Mo ","Li ","Zhu ","Li ","Ya ","Quan ","Ban ","Gong ","Jia ","Wu ","Mai ","Lie ","Jin ","Keng ","Xie ","Zhi ","Dong ","Zhu ","Nu ","Jie ","Qu ","Shao ","Yi ","Zhu ","Miao ","Li ","Jing ","Lao ","Lao ","Juan ","Kou ","Yang ","Wa ","Xiao ","Mou ","Kuang ","Jie ","Lie ","He ","Shi ","Ke ","Jing ","Hao ","Bo ","Min ","Chi ","Lang ","Yong ","Yong ","Mian ","Ke ","Xun ","Juan ","Qing ","Lu ","Pou ","Meng ","Lai ","Le ","Kai ","Mian ","Dong ","Xu ","Xu ","Kan ","Wu ","Yi ","Xun ","Weng ","Sheng ","Lao ","Mu ","Lu ","Piao ","Shi ","Ji ","Qin ","Qiang ","Jiao ","Quan ","Yang ","Yi ","Jue ","Fan ","Juan ","Tong ","Ju ","Dan ","Xie ","Mai ","Xun ","Xun ","Lu ","Li ","Che ","Rang ","Quan ","Bao ","Shao ","Yun ","Jiu ","Bao ","Gou ","Wu "]});var RK=m((ZGe,_K)=>{_K.exports=["Yun ","Mwun ","Nay ","Gai ","Gai ","Bao ","Cong ","[?] ","Xiong ","Peng ","Ju ","Tao ","Ge ","Pu ","An ","Pao ","Fu ","Gong ","Da ","Jiu ","Qiong ","Bi ","Hua ","Bei ","Nao ","Chi ","Fang ","Jiu ","Yi ","Za ","Jiang ","Kang ","Jiang ","Kuang ","Hu ","Xia ","Qu ","Bian ","Gui ","Qie ","Zang ","Kuang ","Fei ","Hu ","Tou ","Gui ","Gui ","Hui ","Dan ","Gui ","Lian ","Lian ","Suan ","Du ","Jiu ","Qu ","Xi ","Pi ","Qu ","Yi ","Qia ","Yan ","Bian ","Ni ","Qu ","Shi ","Xin ","Qian ","Nian ","Sa ","Zu ","Sheng ","Wu ","Hui ","Ban ","Shi ","Xi ","Wan ","Hua ","Xie ","Wan ","Bei ","Zu ","Zhuo ","Xie ","Dan ","Mai ","Nan ","Dan ","Ji ","Bo ","Shuai ","Bu ","Kuang ","Bian ","Bu ","Zhan ","Qia ","Lu ","You ","Lu ","Xi ","Gua ","Wo ","Xie ","Jie ","Jie ","Wei ","Ang ","Qiong ","Zhi ","Mao ","Yin ","Wei ","Shao ","Ji ","Que ","Luan ","Shi ","Juan ","Xie ","Xu ","Jin ","Que ","Wu ","Ji ","E ","Qing ","Xi ","[?] ","Han ","Zhan ","E ","Ting ","Li ","Zhe ","Han ","Li ","Ya ","Ya ","Yan ","She ","Zhi ","Zha ","Pang ","[?] ","He ","Ya ","Zhi ","Ce ","Pang ","Ti ","Li ","She ","Hou ","Ting ","Zui ","Cuo ","Fei ","Yuan ","Ce ","Yuan ","Xiang ","Yan ","Li ","Jue ","Sha ","Dian ","Chu ","Jiu ","Qin ","Ao ","Gui ","Yan ","Si ","Li ","Chang ","Lan ","Li ","Yan ","Yan ","Yuan ","Si ","Gong ","Lin ","Qiu ","Qu ","Qu ","Uk ","Lei ","Du ","Xian ","Zhuan ","San ","Can ","Can ","Can ","Can ","Ai ","Dai ","You ","Cha ","Ji ","You ","Shuang ","Fan ","Shou ","Guai ","Ba ","Fa ","Ruo ","Shi ","Shu ","Zhuo ","Qu ","Shou ","Bian ","Xu ","Jia ","Pan ","Sou ","Gao ","Wei ","Sou ","Die ","Rui ","Cong ","Kou ","Gu ","Ju ","Ling ","Gua ","Tao ","Kou ","Zhi ","Jiao ","Zhao ","Ba ","Ding ","Ke ","Tai ","Chi ","Shi ","You ","Qiu ","Po ","Xie ","Hao ","Si ","Tan ","Chi ","Le ","Diao ","Ji ","[?] ","Hong "]});var FK=m((JGe,LK)=>{LK.exports=["Mie ","Xu ","Mang ","Chi ","Ge ","Xuan ","Yao ","Zi ","He ","Ji ","Diao ","Cun ","Tong ","Ming ","Hou ","Li ","Tu ","Xiang ","Zha ","Xia ","Ye ","Lu ","A ","Ma ","Ou ","Xue ","Yi ","Jun ","Chou ","Lin ","Tun ","Yin ","Fei ","Bi ","Qin ","Qin ","Jie ","Bu ","Fou ","Ba ","Dun ","Fen ","E ","Han ","Ting ","Hang ","Shun ","Qi ","Hong ","Zhi ","Shen ","Wu ","Wu ","Chao ","Ne ","Xue ","Xi ","Chui ","Dou ","Wen ","Hou ","Ou ","Wu ","Gao ","Ya ","Jun ","Lu ","E ","Ge ","Mei ","Ai ","Qi ","Cheng ","Wu ","Gao ","Fu ","Jiao ","Hong ","Chi ","Sheng ","Ne ","Tun ","Fu ","Yi ","Dai ","Ou ","Li ","Bai ","Yuan ","Kuai ","[?] ","Qiang ","Wu ","E ","Shi ","Quan ","Pen ","Wen ","Ni ","M ","Ling ","Ran ","You ","Di ","Zhou ","Shi ","Zhou ","Tie ","Xi ","Yi ","Qi ","Ping ","Zi ","Gu ","Zi ","Wei ","Xu ","He ","Nao ","Xia ","Pei ","Yi ","Xiao ","Shen ","Hu ","Ming ","Da ","Qu ","Ju ","Gem ","Za ","Tuo ","Duo ","Pou ","Pao ","Bi ","Fu ","Yang ","He ","Zha ","He ","Hai ","Jiu ","Yong ","Fu ","Que ","Zhou ","Wa ","Ka ","Gu ","Ka ","Zuo ","Bu ","Long ","Dong ","Ning ","Tha ","Si ","Xian ","Huo ","Qi ","Er ","E ","Guang ","Zha ","Xi ","Yi ","Lie ","Zi ","Mie ","Mi ","Zhi ","Yao ","Ji ","Zhou ","Ge ","Shuai ","Zan ","Xiao ","Ke ","Hui ","Kua ","Huai ","Tao ","Xian ","E ","Xuan ","Xiu ","Wai ","Yan ","Lao ","Yi ","Ai ","Pin ","Shen ","Tong ","Hong ","Xiong ","Chi ","Wa ","Ha ","Zai ","Yu ","Di ","Pai ","Xiang ","Ai ","Hen ","Kuang ","Ya ","Da ","Xiao ","Bi ","Yue ","[?] ","Hua ","Sasou ","Kuai ","Duo ","[?] ","Ji ","Nong ","Mou ","Yo ","Hao ","Yuan ","Long ","Pou ","Mang ","Ge ","E ","Chi ","Shao ","Li ","Na ","Zu ","He ","Ku ","Xiao ","Xian ","Lao ","Bo ","Zhe ","Zha ","Liang ","Ba ","Mie ","Le ","Sui ","Fou ","Bu ","Han ","Heng ","Geng ","Shuo ","Ge "]});var jK=m(($Ge,IK)=>{IK.exports=["You ","Yan ","Gu ","Gu ","Bai ","Han ","Suo ","Chun ","Yi ","Ai ","Jia ","Tu ","Xian ","Huan ","Li ","Xi ","Tang ","Zuo ","Qiu ","Che ","Wu ","Zao ","Ya ","Dou ","Qi ","Di ","Qin ","Ma ","Mal ","Hong ","Dou ","Kes ","Lao ","Liang ","Suo ","Zao ","Huan ","Lang ","Sha ","Ji ","Zuo ","Wo ","Feng ","Yin ","Hu ","Qi ","Shou ","Wei ","Shua ","Chang ","Er ","Li ","Qiang ","An ","Jie ","Yo ","Nian ","Yu ","Tian ","Lai ","Sha ","Xi ","Tuo ","Hu ","Ai ","Zhou ","Nou ","Ken ","Zhuo ","Zhuo ","Shang ","Di ","Heng ","Lan ","A ","Xiao ","Xiang ","Tun ","Wu ","Wen ","Cui ","Sha ","Hu ","Qi ","Qi ","Tao ","Dan ","Dan ","Ye ","Zi ","Bi ","Cui ","Chuo ","He ","Ya ","Qi ","Zhe ","Pei ","Liang ","Xian ","Pi ","Sha ","La ","Ze ","Qing ","Gua ","Pa ","Zhe ","Se ","Zhuan ","Nie ","Guo ","Luo ","Yan ","Di ","Quan ","Tan ","Bo ","Ding ","Lang ","Xiao ","[?] ","Tang ","Chi ","Ti ","An ","Jiu ","Dan ","Ke ","Yong ","Wei ","Nan ","Shan ","Yu ","Zhe ","La ","Jie ","Hou ","Han ","Die ","Zhou ","Chai ","Wai ","Re ","Yu ","Yin ","Zan ","Yao ","Wo ","Mian ","Hu ","Yun ","Chuan ","Hui ","Huan ","Huan ","Xi ","He ","Ji ","Kui ","Zhong ","Wei ","Sha ","Xu ","Huang ","Du ","Nie ","Xuan ","Liang ","Yu ","Sang ","Chi ","Qiao ","Yan ","Dan ","Pen ","Can ","Li ","Yo ","Zha ","Wei ","Miao ","Ying ","Pen ","Phos ","Kui ","Xi ","Yu ","Jie ","Lou ","Ku ","Sao ","Huo ","Ti ","Yao ","He ","A ","Xiu ","Qiang ","Se ","Yong ","Su ","Hong ","Xie ","Yi ","Suo ","Ma ","Cha ","Hai ","Ke ","Ta ","Sang ","Tian ","Ru ","Sou ","Wa ","Ji ","Pang ","Wu ","Xian ","Shi ","Ge ","Zi ","Jie ","Luo ","Weng ","Wa ","Si ","Chi ","Hao ","Suo ","Jia ","Hai ","Suo ","Qin ","Nie ","He ","Cis ","Sai ","Ng ","Ge ","Na ","Dia ","Ai ","[?] ","Tong ","Bi ","Ao ","Ao ","Lian ","Cui ","Zhe ","Mo ","Sou ","Sou ","Tan "]});var OK=m((XGe,AK)=>{AK.exports=["Di ","Qi ","Jiao ","Chong ","Jiao ","Kai ","Tan ","San ","Cao ","Jia ","Ai ","Xiao ","Piao ","Lou ","Ga ","Gu ","Xiao ","Hu ","Hui ","Guo ","Ou ","Xian ","Ze ","Chang ","Xu ","Po ","De ","Ma ","Ma ","Hu ","Lei ","Du ","Ga ","Tang ","Ye ","Beng ","Ying ","Saai ","Jiao ","Mi ","Xiao ","Hua ","Mai ","Ran ","Zuo ","Peng ","Lao ","Xiao ","Ji ","Zhu ","Chao ","Kui ","Zui ","Xiao ","Si ","Hao ","Fu ","Liao ","Qiao ","Xi ","Xiu ","Tan ","Tan ","Mo ","Xun ","E ","Zun ","Fan ","Chi ","Hui ","Zan ","Chuang ","Cu ","Dan ","Yu ","Tun ","Cheng ","Jiao ","Ye ","Xi ","Qi ","Hao ","Lian ","Xu ","Deng ","Hui ","Yin ","Pu ","Jue ","Qin ","Xun ","Nie ","Lu ","Si ","Yan ","Ying ","Da ","Dan ","Yu ","Zhou ","Jin ","Nong ","Yue ","Hui ","Qi ","E ","Zao ","Yi ","Shi ","Jiao ","Yuan ","Ai ","Yong ","Jue ","Kuai ","Yu ","Pen ","Dao ","Ge ","Xin ","Dun ","Dang ","Sin ","Sai ","Pi ","Pi ","Yin ","Zui ","Ning ","Di ","Lan ","Ta ","Huo ","Ru ","Hao ","Xia ","Ya ","Duo ","Xi ","Chou ","Ji ","Jin ","Hao ","Ti ","Chang ","[?] ","[?] ","Ca ","Ti ","Lu ","Hui ","Bo ","You ","Nie ","Yin ","Hu ","Mo ","Huang ","Zhe ","Li ","Liu ","Haai ","Nang ","Xiao ","Mo ","Yan ","Li ","Lu ","Long ","Fu ","Dan ","Chen ","Pin ","Pi ","Xiang ","Huo ","Mo ","Xi ","Duo ","Ku ","Yan ","Chan ","Ying ","Rang ","Dian ","La ","Ta ","Xiao ","Jiao ","Chuo ","Huan ","Huo ","Zhuan ","Nie ","Xiao ","Ca ","Li ","Chan ","Chai ","Li ","Yi ","Luo ","Nang ","Zan ","Su ","Xi ","So ","Jian ","Za ","Zhu ","Lan ","Nie ","Nang ","[?] ","[?] ","Wei ","Hui ","Yin ","Qiu ","Si ","Nin ","Jian ","Hui ","Xin ","Yin ","Nan ","Tuan ","Tuan ","Dun ","Kang ","Yuan ","Jiong ","Pian ","Yun ","Cong ","Hu ","Hui ","Yuan ","You ","Guo ","Kun ","Cong ","Wei ","Tu ","Wei ","Lun ","Guo ","Qun ","Ri ","Ling ","Gu ","Guo ","Tai ","Guo ","Tu ","You "]});var NK=m((UGe,MK)=>{MK.exports=["Guo ","Yin ","Hun ","Pu ","Yu ","Han ","Yuan ","Lun ","Quan ","Yu ","Qing ","Guo ","Chuan ","Wei ","Yuan ","Quan ","Ku ","Fu ","Yuan ","Yuan ","E ","Tu ","Tu ","Tu ","Tuan ","Lue ","Hui ","Yi ","Yuan ","Luan ","Luan ","Tu ","Ya ","Tu ","Ting ","Sheng ","Pu ","Lu ","Iri ","Ya ","Zai ","Wei ","Ge ","Yu ","Wu ","Gui ","Pi ","Yi ","Di ","Qian ","Qian ","Zhen ","Zhuo ","Dang ","Qia ","Akutsu ","Yama ","Kuang ","Chang ","Qi ","Nie ","Mo ","Ji ","Jia ","Zhi ","Zhi ","Ban ","Xun ","Tou ","Qin ","Fen ","Jun ","Keng ","Tun ","Fang ","Fen ","Ben ","Tan ","Kan ","Pi ","Zuo ","Keng ","Bi ","Xing ","Di ","Jing ","Ji ","Kuai ","Di ","Jing ","Jian ","Tan ","Li ","Ba ","Wu ","Fen ","Zhui ","Po ","Pan ","Tang ","Kun ","Qu ","Tan ","Zhi ","Tuo ","Gan ","Ping ","Dian ","Gua ","Ni ","Tai ","Pi ","Jiong ","Yang ","Fo ","Ao ","Liu ","Qiu ","Mu ","Ke ","Gou ","Xue ","Ba ","Chi ","Che ","Ling ","Zhu ","Fu ","Hu ","Zhi ","Chui ","La ","Long ","Long ","Lu ","Ao ","Tay ","Pao ","[?] ","Xing ","Dong ","Ji ","Ke ","Lu ","Ci ","Chi ","Lei ","Gai ","Yin ","Hou ","Dui ","Zhao ","Fu ","Guang ","Yao ","Duo ","Duo ","Gui ","Cha ","Yang ","Yin ","Fa ","Gou ","Yuan ","Die ","Xie ","Ken ","Jiong ","Shou ","E ","Ha ","Dian ","Hong ","Wu ","Kua ","[?] ","Tao ","Dang ","Kai ","Gake ","Nao ","An ","Xing ","Xian ","Huan ","Bang ","Pei ","Ba ","Yi ","Yin ","Han ","Xu ","Chui ","Cen ","Geng ","Ai ","Peng ","Fang ","Que ","Yong ","Xun ","Jia ","Di ","Mai ","Lang ","Xuan ","Cheng ","Yan ","Jin ","Zhe ","Lei ","Lie ","Bu ","Cheng ","Gomi ","Bu ","Shi ","Xun ","Guo ","Jiong ","Ye ","Nian ","Di ","Yu ","Bu ","Ya ","Juan ","Sui ","Pi ","Cheng ","Wan ","Ju ","Lun ","Zheng ","Kong ","Chong ","Dong ","Dai ","Tan ","An ","Cai ","Shu ","Beng ","Kan ","Zhi ","Duo ","Yi ","Zhi ","Yi ","Pei ","Ji ","Zhun ","Qi ","Sao ","Ju ","Ni "]});var HK=m((GGe,BK)=>{BK.exports=["Ku ","Ke ","Tang ","Kun ","Ni ","Jian ","Dui ","Jin ","Gang ","Yu ","E ","Peng ","Gu ","Tu ","Leng ","[?] ","Ya ","Qian ","[?] ","An ","[?] ","Duo ","Nao ","Tu ","Cheng ","Yin ","Hun ","Bi ","Lian ","Guo ","Die ","Zhuan ","Hou ","Bao ","Bao ","Yu ","Di ","Mao ","Jie ","Ruan ","E ","Geng ","Kan ","Zong ","Yu ","Huang ","E ","Yao ","Yan ","Bao ","Ji ","Mei ","Chang ","Du ","Tuo ","Yin ","Feng ","Zhong ","Jie ","Zhen ","Feng ","Gang ","Chuan ","Jian ","Pyeng ","Toride ","Xiang ","Huang ","Leng ","Duan ","[?] ","Xuan ","Ji ","Ji ","Kuai ","Ying ","Ta ","Cheng ","Yong ","Kai ","Su ","Su ","Shi ","Mi ","Ta ","Weng ","Cheng ","Tu ","Tang ","Que ","Zhong ","Li ","Peng ","Bang ","Sai ","Zang ","Dui ","Tian ","Wu ","Cheng ","Xun ","Ge ","Zhen ","Ai ","Gong ","Yan ","Kan ","Tian ","Yuan ","Wen ","Xie ","Liu ","Ama ","Lang ","Chang ","Peng ","Beng ","Chen ","Cu ","Lu ","Ou ","Qian ","Mei ","Mo ","Zhuan ","Shuang ","Shu ","Lou ","Chi ","Man ","Biao ","Jing ","Qi ","Shu ","Di ","Zhang ","Kan ","Yong ","Dian ","Chen ","Zhi ","Xi ","Guo ","Qiang ","Jin ","Di ","Shang ","Mu ","Cui ","Yan ","Ta ","Zeng ","Qi ","Qiang ","Liang ","[?] ","Zhui ","Qiao ","Zeng ","Xu ","Shan ","Shan ","Ba ","Pu ","Kuai ","Dong ","Fan ","Que ","Mo ","Dun ","Dun ","Dun ","Di ","Sheng ","Duo ","Duo ","Tan ","Deng ","Wu ","Fen ","Huang ","Tan ","Da ","Ye ","Sho ","Mama ","Yu ","Qiang ","Ji ","Qiao ","Ken ","Yi ","Pi ","Bi ","Dian ","Jiang ","Ye ","Yong ","Bo ","Tan ","Lan ","Ju ","Huai ","Dang ","Rang ","Qian ","Xun ","Lan ","Xi ","He ","Ai ","Ya ","Dao ","Hao ","Ruan ","Mama ","Lei ","Kuang ","Lu ","Yan ","Tan ","Wei ","Huai ","Long ","Long ","Rui ","Li ","Lin ","Rang ","Ten ","Xun ","Yan ","Lei ","Ba ","[?] ","Shi ","Ren ","[?] ","Zhuang ","Zhuang ","Sheng ","Yi ","Mai ","Ke ","Zhu ","Zhuang ","Hu ","Hu ","Kun ","Yi ","Hu ","Xu ","Kun ","Shou ","Mang ","Zun "]});var YK=m((QGe,qK)=>{qK.exports=["Shou ","Yi ","Zhi ","Gu ","Chu ","Jiang ","Feng ","Bei ","Cay ","Bian ","Sui ","Qun ","Ling ","Fu ","Zuo ","Xia ","Xiong ","[?] ","Nao ","Xia ","Kui ","Xi ","Wai ","Yuan ","Mao ","Su ","Duo ","Duo ","Ye ","Qing ","Uys ","Gou ","Gou ","Qi ","Meng ","Meng ","Yin ","Huo ","Chen ","Da ","Ze ","Tian ","Tai ","Fu ","Guai ","Yao ","Yang ","Hang ","Gao ","Shi ","Ben ","Tai ","Tou ","Yan ","Bi ","Yi ","Kua ","Jia ","Duo ","Kwu ","Kuang ","Yun ","Jia ","Pa ","En ","Lian ","Huan ","Di ","Yan ","Pao ","Quan ","Qi ","Nai ","Feng ","Xie ","Fen ","Dian ","[?] ","Kui ","Zou ","Huan ","Qi ","Kai ","Zha ","Ben ","Yi ","Jiang ","Tao ","Zang ","Ben ","Xi ","Xiang ","Fei ","Diao ","Xun ","Keng ","Dian ","Ao ","She ","Weng ","Pan ","Ao ","Wu ","Ao ","Jiang ","Lian ","Duo ","Yun ","Jiang ","Shi ","Fen ","Huo ","Bi ","Lian ","Duo ","Nu ","Nu ","Ding ","Nai ","Qian ","Jian ","Ta ","Jiu ","Nan ","Cha ","Hao ","Xian ","Fan ","Ji ","Shuo ","Ru ","Fei ","Wang ","Hong ","Zhuang ","Fu ","Ma ","Dan ","Ren ","Fu ","Jing ","Yan ","Xie ","Wen ","Zhong ","Pa ","Du ","Ji ","Keng ","Zhong ","Yao ","Jin ","Yun ","Miao ","Pei ","Shi ","Yue ","Zhuang ","Niu ","Yan ","Na ","Xin ","Fen ","Bi ","Yu ","Tuo ","Feng ","Yuan ","Fang ","Wu ","Yu ","Gui ","Du ","Ba ","Ni ","Zhou ","Zhuo ","Zhao ","Da ","Nai ","Yuan ","Tou ","Xuan ","Zhi ","E ","Mei ","Mo ","Qi ","Bi ","Shen ","Qie ","E ","He ","Xu ","Fa ","Zheng ","Min ","Ban ","Mu ","Fu ","Ling ","Zi ","Zi ","Shi ","Ran ","Shan ","Yang ","Man ","Jie ","Gu ","Si ","Xing ","Wei ","Zi ","Ju ","Shan ","Pin ","Ren ","Yao ","Tong ","Jiang ","Shu ","Ji ","Gai ","Shang ","Kuo ","Juan ","Jiao ","Gou ","Mu ","Jian ","Jian ","Yi ","Nian ","Zhi ","Ji ","Ji ","Xian ","Heng ","Guang ","Jun ","Kua ","Yan ","Ming ","Lie ","Pei ","Yan ","You ","Yan ","Cha ","Shen ","Yin ","Chi ","Gui ","Quan ","Zi "]});var ZK=m((KGe,WK)=>{WK.exports=["Song ","Wei ","Hong ","Wa ","Lou ","Ya ","Rao ","Jiao ","Luan ","Ping ","Xian ","Shao ","Li ","Cheng ","Xiao ","Mang ","Fu ","Suo ","Wu ","Wei ","Ke ","Lai ","Chuo ","Ding ","Niang ","Xing ","Nan ","Yu ","Nuo ","Pei ","Nei ","Juan ","Shen ","Zhi ","Han ","Di ","Zhuang ","E ","Pin ","Tui ","Han ","Mian ","Wu ","Yan ","Wu ","Xi ","Yan ","Yu ","Si ","Yu ","Wa ","[?] ","Xian ","Ju ","Qu ","Shui ","Qi ","Xian ","Zhui ","Dong ","Chang ","Lu ","Ai ","E ","E ","Lou ","Mian ","Cong ","Pou ","Ju ","Po ","Cai ","Ding ","Wan ","Biao ","Xiao ","Shu ","Qi ","Hui ","Fu ","E ","Wo ","Tan ","Fei ","Wei ","Jie ","Tian ","Ni ","Quan ","Jing ","Hun ","Jing ","Qian ","Dian ","Xing ","Hu ","Wa ","Lai ","Bi ","Yin ","Chou ","Chuo ","Fu ","Jing ","Lun ","Yan ","Lan ","Kun ","Yin ","Ya ","Ju ","Li ","Dian ","Xian ","Hwa ","Hua ","Ying ","Chan ","Shen ","Ting ","Dang ","Yao ","Wu ","Nan ","Ruo ","Jia ","Tou ","Xu ","Yu ","Wei ","Ti ","Rou ","Mei ","Dan ","Ruan ","Qin ","Hui ","Wu ","Qian ","Chun ","Mao ","Fu ","Jie ","Duan ","Xi ","Zhong ","Mei ","Huang ","Mian ","An ","Ying ","Xuan ","Jie ","Wei ","Mei ","Yuan ","Zhen ","Qiu ","Ti ","Xie ","Tuo ","Lian ","Mao ","Ran ","Si ","Pian ","Wei ","Wa ","Jiu ","Hu ","Ao ","[?] ","Bou ","Xu ","Tou ","Gui ","Zou ","Yao ","Pi ","Xi ","Yuan ","Ying ","Rong ","Ru ","Chi ","Liu ","Mei ","Pan ","Ao ","Ma ","Gou ","Kui ","Qin ","Jia ","Sao ","Zhen ","Yuan ","Cha ","Yong ","Ming ","Ying ","Ji ","Su ","Niao ","Xian ","Tao ","Pang ","Lang ","Nao ","Bao ","Ai ","Pi ","Pin ","Yi ","Piao ","Yu ","Lei ","Xuan ","Man ","Yi ","Zhang ","Kang ","Yong ","Ni ","Li ","Di ","Gui ","Yan ","Jin ","Zhuan ","Chang ","Ce ","Han ","Nen ","Lao ","Mo ","Zhe ","Hu ","Hu ","Ao ","Nen ","Qiang ","Ma ","Pie ","Gu ","Wu ","Jiao ","Tuo ","Zhan ","Mao ","Xian ","Xian ","Mo ","Liao ","Lian ","Hua "]});var $K=m((zGe,JK)=>{JK.exports=["Gui ","Deng ","Zhi ","Xu ","Yi ","Hua ","Xi ","Hui ","Rao ","Xi ","Yan ","Chan ","Jiao ","Mei ","Fan ","Fan ","Xian ","Yi ","Wei ","Jiao ","Fu ","Shi ","Bi ","Shan ","Sui ","Qiang ","Lian ","Huan ","Xin ","Niao ","Dong ","Yi ","Can ","Ai ","Niang ","Neng ","Ma ","Tiao ","Chou ","Jin ","Ci ","Yu ","Pin ","Yong ","Xu ","Nai ","Yan ","Tai ","Ying ","Can ","Niao ","Wo ","Ying ","Mian ","Kaka ","Ma ","Shen ","Xing ","Ni ","Du ","Liu ","Yuan ","Lan ","Yan ","Shuang ","Ling ","Jiao ","Niang ","Lan ","Xian ","Ying ","Shuang ","Shuai ","Quan ","Mi ","Li ","Luan ","Yan ","Zhu ","Lan ","Zi ","Jie ","Jue ","Jue ","Kong ","Yun ","Zi ","Zi ","Cun ","Sun ","Fu ","Bei ","Zi ","Xiao ","Xin ","Meng ","Si ","Tai ","Bao ","Ji ","Gu ","Nu ","Xue ","[?] ","Zhuan ","Hai ","Luan ","Sun ","Huai ","Mie ","Cong ","Qian ","Shu ","Chan ","Ya ","Zi ","Ni ","Fu ","Zi ","Li ","Xue ","Bo ","Ru ","Lai ","Nie ","Nie ","Ying ","Luan ","Mian ","Zhu ","Rong ","Ta ","Gui ","Zhai ","Qiong ","Yu ","Shou ","An ","Tu ","Song ","Wan ","Rou ","Yao ","Hong ","Yi ","Jing ","Zhun ","Mi ","Zhu ","Dang ","Hong ","Zong ","Guan ","Zhou ","Ding ","Wan ","Yi ","Bao ","Shi ","Shi ","Chong ","Shen ","Ke ","Xuan ","Shi ","You ","Huan ","Yi ","Tiao ","Shi ","Xian ","Gong ","Cheng ","Qun ","Gong ","Xiao ","Zai ","Zha ","Bao ","Hai ","Yan ","Xiao ","Jia ","Shen ","Chen ","Rong ","Huang ","Mi ","Kou ","Kuan ","Bin ","Su ","Cai ","Zan ","Ji ","Yuan ","Ji ","Yin ","Mi ","Kou ","Qing ","Que ","Zhen ","Jian ","Fu ","Ning ","Bing ","Huan ","Mei ","Qin ","Han ","Yu ","Shi ","Ning ","Qin ","Ning ","Zhi ","Yu ","Bao ","Kuan ","Ning ","Qin ","Mo ","Cha ","Ju ","Gua ","Qin ","Hu ","Wu ","Liao ","Shi ","Zhu ","Zhai ","Shen ","Wei ","Xie ","Kuan ","Hui ","Liao ","Jun ","Huan ","Yi ","Yi ","Bao ","Qin ","Chong ","Bao ","Feng ","Cun ","Dui ","Si ","Xun ","Dao ","Lu ","Dui ","Shou "]});var UK=m((VGe,XK)=>{XK.exports=["Po ","Feng ","Zhuan ","Fu ","She ","Ke ","Jiang ","Jiang ","Zhuan ","Wei ","Zun ","Xun ","Shu ","Dui ","Dao ","Xiao ","Ji ","Shao ","Er ","Er ","Er ","Ga ","Jian ","Shu ","Chen ","Shang ","Shang ","Mo ","Ga ","Chang ","Liao ","Xian ","Xian ","[?] ","Wang ","Wang ","You ","Liao ","Liao ","Yao ","Mang ","Wang ","Wang ","Wang ","Ga ","Yao ","Duo ","Kui ","Zhong ","Jiu ","Gan ","Gu ","Gan ","Tui ","Gan ","Gan ","Shi ","Yin ","Chi ","Kao ","Ni ","Jin ","Wei ","Niao ","Ju ","Pi ","Ceng ","Xi ","Bi ","Ju ","Jie ","Tian ","Qu ","Ti ","Jie ","Wu ","Diao ","Shi ","Shi ","Ping ","Ji ","Xie ","Chen ","Xi ","Ni ","Zhan ","Xi ","[?] ","Man ","E ","Lou ","Ping ","Ti ","Fei ","Shu ","Xie ","Tu ","Lu ","Lu ","Xi ","Ceng ","Lu ","Ju ","Xie ","Ju ","Jue ","Liao ","Jue ","Shu ","Xi ","Che ","Tun ","Ni ","Shan ","[?] ","Xian ","Li ","Xue ","Nata ","[?] ","Long ","Yi ","Qi ","Ren ","Wu ","Han ","Shen ","Yu ","Chu ","Sui ","Qi ","[?] ","Yue ","Ban ","Yao ","Ang ","Ya ","Wu ","Jie ","E ","Ji ","Qian ","Fen ","Yuan ","Qi ","Cen ","Qian ","Qi ","Cha ","Jie ","Qu ","Gang ","Xian ","Ao ","Lan ","Dao ","Ba ","Zuo ","Zuo ","Yang ","Ju ","Gang ","Ke ","Gou ","Xue ","Bei ","Li ","Tiao ","Ju ","Yan ","Fu ","Xiu ","Jia ","Ling ","Tuo ","Pei ","You ","Dai ","Kuang ","Yue ","Qu ","Hu ","Po ","Min ","An ","Tiao ","Ling ","Chi ","Yuri ","Dong ","Cem ","Kui ","Xiu ","Mao ","Tong ","Xue ","Yi ","Kura ","He ","Ke ","Luo ","E ","Fu ","Xun ","Die ","Lu ","An ","Er ","Gai ","Quan ","Tong ","Yi ","Mu ","Shi ","An ","Wei ","Hu ","Zhi ","Mi ","Li ","Ji ","Tong ","Wei ","You ","Sang ","Xia ","Li ","Yao ","Jiao ","Zheng ","Luan ","Jiao ","E ","E ","Yu ","Ye ","Bu ","Qiao ","Qun ","Feng ","Feng ","Nao ","Li ","You ","Xian ","Hong ","Dao ","Shen ","Cheng ","Tu ","Geng ","Jun ","Hao ","Xia ","Yin ","Yu "]});var QK=m((e6e,GK)=>{GK.exports=["Lang ","Kan ","Lao ","Lai ","Xian ","Que ","Kong ","Chong ","Chong ","Ta ","Lin ","Hua ","Ju ","Lai ","Qi ","Min ","Kun ","Kun ","Zu ","Gu ","Cui ","Ya ","Ya ","Gang ","Lun ","Lun ","Leng ","Jue ","Duo ","Zheng ","Guo ","Yin ","Dong ","Han ","Zheng ","Wei ","Yao ","Pi ","Yan ","Song ","Jie ","Beng ","Zu ","Jue ","Dong ","Zhan ","Gu ","Yin ","[?] ","Ze ","Huang ","Yu ","Wei ","Yang ","Feng ","Qiu ","Dun ","Ti ","Yi ","Zhi ","Shi ","Zai ","Yao ","E ","Zhu ","Kan ","Lu ","Yan ","Mei ","Gan ","Ji ","Ji ","Huan ","Ting ","Sheng ","Mei ","Qian ","Wu ","Yu ","Zong ","Lan ","Jue ","Yan ","Yan ","Wei ","Zong ","Cha ","Sui ","Rong ","Yamashina ","Qin ","Yu ","Kewashii ","Lou ","Tu ","Dui ","Xi ","Weng ","Cang ","Dang ","Hong ","Jie ","Ai ","Liu ","Wu ","Song ","Qiao ","Zi ","Wei ","Beng ","Dian ","Cuo ","Qian ","Yong ","Nie ","Cuo ","Ji ","[?] ","Tao ","Song ","Zong ","Jiang ","Liao ","Kang ","Chan ","Die ","Cen ","Ding ","Tu ","Lou ","Zhang ","Zhan ","Zhan ","Ao ","Cao ","Qu ","Qiang ","Zui ","Zui ","Dao ","Dao ","Xi ","Yu ","Bo ","Long ","Xiang ","Ceng ","Bo ","Qin ","Jiao ","Yan ","Lao ","Zhan ","Lin ","Liao ","Liao ","Jin ","Deng ","Duo ","Zun ","Jiao ","Gui ","Yao ","Qiao ","Yao ","Jue ","Zhan ","Yi ","Xue ","Nao ","Ye ","Ye ","Yi ","E ","Xian ","Ji ","Xie ","Ke ","Xi ","Di ","Ao ","Zui ","[?] ","Ni ","Rong ","Dao ","Ling ","Za ","Yu ","Yue ","Yin ","[?] ","Jie ","Li ","Sui ","Long ","Long ","Dian ","Ying ","Xi ","Ju ","Chan ","Ying ","Kui ","Yan ","Wei ","Nao ","Quan ","Chao ","Cuan ","Luan ","Dian ","Dian ","[?] ","Yan ","Yan ","Yan ","Nao ","Yan ","Chuan ","Gui ","Chuan ","Zhou ","Huang ","Jing ","Xun ","Chao ","Chao ","Lie ","Gong ","Zuo ","Qiao ","Ju ","Gong ","Kek ","Wu ","Pwu ","Pwu ","Chai ","Qiu ","Qiu ","Ji ","Yi ","Si ","Ba ","Zhi ","Zhao ","Xiang ","Yi ","Jin ","Xun ","Juan ","Phas ","Xun ","Jin ","Fu "]});var zK=m((t6e,KK)=>{KK.exports=["Za ","Bi ","Shi ","Bu ","Ding ","Shuai ","Fan ","Nie ","Shi ","Fen ","Pa ","Zhi ","Xi ","Hu ","Dan ","Wei ","Zhang ","Tang ","Dai ","Ma ","Pei ","Pa ","Tie ","Fu ","Lian ","Zhi ","Zhou ","Bo ","Zhi ","Di ","Mo ","Yi ","Yi ","Ping ","Qia ","Juan ","Ru ","Shuai ","Dai ","Zheng ","Shui ","Qiao ","Zhen ","Shi ","Qun ","Xi ","Bang ","Dai ","Gui ","Chou ","Ping ","Zhang ","Sha ","Wan ","Dai ","Wei ","Chang ","Sha ","Qi ","Ze ","Guo ","Mao ","Du ","Hou ","Zheng ","Xu ","Mi ","Wei ","Wo ","Fu ","Yi ","Bang ","Ping ","Tazuna ","Gong ","Pan ","Huang ","Dao ","Mi ","Jia ","Teng ","Hui ","Zhong ","Shan ","Man ","Mu ","Biao ","Guo ","Ze ","Mu ","Bang ","Zhang ","Jiong ","Chan ","Fu ","Zhi ","Hu ","Fan ","Chuang ","Bi ","Hei ","[?] ","Mi ","Qiao ","Chan ","Fen ","Meng ","Bang ","Chou ","Mie ","Chu ","Jie ","Xian ","Lan ","Gan ","Ping ","Nian ","Qian ","Bing ","Bing ","Xing ","Gan ","Yao ","Huan ","You ","You ","Ji ","Yan ","Pi ","Ting ","Ze ","Guang ","Zhuang ","Mo ","Qing ","Bi ","Qin ","Dun ","Chuang ","Gui ","Ya ","Bai ","Jie ","Xu ","Lu ","Wu ","[?] ","Ku ","Ying ","Di ","Pao ","Dian ","Ya ","Miao ","Geng ","Ci ","Fu ","Tong ","Pang ","Fei ","Xiang ","Yi ","Zhi ","Tiao ","Zhi ","Xiu ","Du ","Zuo ","Xiao ","Tu ","Gui ","Ku ","Pang ","Ting ","You ","Bu ","Ding ","Cheng ","Lai ","Bei ","Ji ","An ","Shu ","Kang ","Yong ","Tuo ","Song ","Shu ","Qing ","Yu ","Yu ","Miao ","Sou ","Ce ","Xiang ","Fei ","Jiu ","He ","Hui ","Liu ","Sha ","Lian ","Lang ","Sou ","Jian ","Pou ","Qing ","Jiu ","Jiu ","Qin ","Ao ","Kuo ","Lou ","Yin ","Liao ","Dai ","Lu ","Yi ","Chu ","Chan ","Tu ","Si ","Xin ","Miao ","Chang ","Wu ","Fei ","Guang ","Koc ","Kuai ","Bi ","Qiang ","Xie ","Lin ","Lin ","Liao ","Lu ","[?] ","Ying ","Xian ","Ting ","Yong ","Li ","Ting ","Yin ","Xun ","Yan ","Ting ","Di ","Po ","Jian ","Hui ","Nai ","Hui ","Gong ","Nian "]});var ez=m((i6e,VK)=>{VK.exports=["Kai ","Bian ","Yi ","Qi ","Nong ","Fen ","Ju ","Yan ","Yi ","Zang ","Bi ","Yi ","Yi ","Er ","San ","Shi ","Er ","Shi ","Shi ","Gong ","Diao ","Yin ","Hu ","Fu ","Hong ","Wu ","Tui ","Chi ","Jiang ","Ba ","Shen ","Di ","Zhang ","Jue ","Tao ","Fu ","Di ","Mi ","Xian ","Hu ","Chao ","Nu ","Jing ","Zhen ","Yi ","Mi ","Quan ","Wan ","Shao ","Ruo ","Xuan ","Jing ","Dun ","Zhang ","Jiang ","Qiang ","Peng ","Dan ","Qiang ","Bi ","Bi ","She ","Dan ","Jian ","Gou ","Sei ","Fa ","Bi ","Kou ","Nagi ","Bie ","Xiao ","Dan ","Kuo ","Qiang ","Hong ","Mi ","Kuo ","Wan ","Jue ","Ji ","Ji ","Gui ","Dang ","Lu ","Lu ","Tuan ","Hui ","Zhi ","Hui ","Hui ","Yi ","Yi ","Yi ","Yi ","Huo ","Huo ","Shan ","Xing ","Wen ","Tong ","Yan ","Yan ","Yu ","Chi ","Cai ","Biao ","Diao ","Bin ","Peng ","Yong ","Piao ","Zhang ","Ying ","Chi ","Chi ","Zhuo ","Tuo ","Ji ","Pang ","Zhong ","Yi ","Wang ","Che ","Bi ","Chi ","Ling ","Fu ","Wang ","Zheng ","Cu ","Wang ","Jing ","Dai ","Xi ","Xun ","Hen ","Yang ","Huai ","Lu ","Hou ","Wa ","Cheng ","Zhi ","Xu ","Jing ","Tu ","Cong ","[?] ","Lai ","Cong ","De ","Pai ","Xi ","[?] ","Qi ","Chang ","Zhi ","Cong ","Zhou ","Lai ","Yu ","Xie ","Jie ","Jian ","Chi ","Jia ","Bian ","Huang ","Fu ","Xun ","Wei ","Pang ","Yao ","Wei ","Xi ","Zheng ","Piao ","Chi ","De ","Zheng ","Zheng ","Bie ","De ","Chong ","Che ","Jiao ","Wei ","Jiao ","Hui ","Mei ","Long ","Xiang ","Bao ","Qu ","Xin ","Shu ","Bi ","Yi ","Le ","Ren ","Dao ","Ding ","Gai ","Ji ","Ren ","Ren ","Chan ","Tan ","Te ","Te ","Gan ","Qi ","Shi ","Cun ","Zhi ","Wang ","Mang ","Xi ","Fan ","Ying ","Tian ","Min ","Min ","Zhong ","Chong ","Wu ","Ji ","Wu ","Xi ","Ye ","You ","Wan ","Cong ","Zhong ","Kuai ","Yu ","Bian ","Zhi ","Qi ","Cui ","Chen ","Tai ","Tun ","Qian ","Nian ","Hun ","Xiong ","Niu ","Wang ","Xian ","Xin ","Kang ","Hu ","Kai ","Fen "]});var iz=m((n6e,tz)=>{tz.exports=["Huai ","Tai ","Song ","Wu ","Ou ","Chang ","Chuang ","Ju ","Yi ","Bao ","Chao ","Min ","Pei ","Zuo ","Zen ","Yang ","Kou ","Ban ","Nu ","Nao ","Zheng ","Pa ","Bu ","Tie ","Gu ","Hu ","Ju ","Da ","Lian ","Si ","Chou ","Di ","Dai ","Yi ","Tu ","You ","Fu ","Ji ","Peng ","Xing ","Yuan ","Ni ","Guai ","Fu ","Xi ","Bi ","You ","Qie ","Xuan ","Cong ","Bing ","Huang ","Xu ","Chu ","Pi ","Xi ","Xi ","Tan ","Koraeru ","Zong ","Dui ","[?] ","Ki ","Yi ","Chi ","Ren ","Xun ","Shi ","Xi ","Lao ","Heng ","Kuang ","Mu ","Zhi ","Xie ","Lian ","Tiao ","Huang ","Die ","Hao ","Kong ","Gui ","Heng ","Xi ","Xiao ","Shu ","S ","Kua ","Qiu ","Yang ","Hui ","Hui ","Chi ","Jia ","Yi ","Xiong ","Guai ","Lin ","Hui ","Zi ","Xu ","Chi ","Xiang ","Nu ","Hen ","En ","Ke ","Tong ","Tian ","Gong ","Quan ","Xi ","Qia ","Yue ","Peng ","Ken ","De ","Hui ","E ","Kyuu ","Tong ","Yan ","Kai ","Ce ","Nao ","Yun ","Mang ","Yong ","Yong ","Yuan ","Pi ","Kun ","Qiao ","Yue ","Yu ","Yu ","Jie ","Xi ","Zhe ","Lin ","Ti ","Han ","Hao ","Qie ","Ti ","Bu ","Yi ","Qian ","Hui ","Xi ","Bei ","Man ","Yi ","Heng ","Song ","Quan ","Cheng ","Hui ","Wu ","Wu ","You ","Li ","Liang ","Huan ","Cong ","Yi ","Yue ","Li ","Nin ","Nao ","E ","Que ","Xuan ","Qian ","Wu ","Min ","Cong ","Fei ","Bei ","Duo ","Cui ","Chang ","Men ","Li ","Ji ","Guan ","Guan ","Xing ","Dao ","Qi ","Kong ","Tian ","Lun ","Xi ","Kan ","Kun ","Ni ","Qing ","Chou ","Dun ","Guo ","Chan ","Liang ","Wan ","Yuan ","Jin ","Ji ","Lin ","Yu ","Huo ","He ","Quan ","Tan ","Ti ","Ti ","Nie ","Wang ","Chuo ","Bu ","Hun ","Xi ","Tang ","Xin ","Wei ","Hui ","E ","Rui ","Zong ","Jian ","Yong ","Dian ","Ju ","Can ","Cheng ","De ","Bei ","Qie ","Can ","Dan ","Guan ","Duo ","Nao ","Yun ","Xiang ","Zhui ","Die ","Huang ","Chun ","Qiong ","Re ","Xing ","Ce ","Bian ","Hun ","Zong ","Ti "]});var rz=m((r6e,nz)=>{nz.exports=["Qiao ","Chou ","Bei ","Xuan ","Wei ","Ge ","Qian ","Wei ","Yu ","Yu ","Bi ","Xuan ","Huan ","Min ","Bi ","Yi ","Mian ","Yong ","Kai ","Dang ","Yin ","E ","Chen ","Mou ","Ke ","Ke ","Yu ","Ai ","Qie ","Yan ","Nuo ","Gan ","Yun ","Zong ","Sai ","Leng ","Fen ","[?] ","Kui ","Kui ","Que ","Gong ","Yun ","Su ","Su ","Qi ","Yao ","Song ","Huang ","Ji ","Gu ","Ju ","Chuang ","Ni ","Xie ","Kai ","Zheng ","Yong ","Cao ","Sun ","Shen ","Bo ","Kai ","Yuan ","Xie ","Hun ","Yong ","Yang ","Li ","Sao ","Tao ","Yin ","Ci ","Xu ","Qian ","Tai ","Huang ","Yun ","Shen ","Ming ","[?] ","She ","Cong ","Piao ","Mo ","Mu ","Guo ","Chi ","Can ","Can ","Can ","Cui ","Min ","Te ","Zhang ","Tong ","Ao ","Shuang ","Man ","Guan ","Que ","Zao ","Jiu ","Hui ","Kai ","Lian ","Ou ","Song ","Jin ","Yin ","Lu ","Shang ","Wei ","Tuan ","Man ","Qian ","She ","Yong ","Qing ","Kang ","Di ","Zhi ","Lou ","Juan ","Qi ","Qi ","Yu ","Ping ","Liao ","Cong ","You ","Chong ","Zhi ","Tong ","Cheng ","Qi ","Qu ","Peng ","Bei ","Bie ","Chun ","Jiao ","Zeng ","Chi ","Lian ","Ping ","Kui ","Hui ","Qiao ","Cheng ","Yin ","Yin ","Xi ","Xi ","Dan ","Tan ","Duo ","Dui ","Dui ","Su ","Jue ","Ce ","Xiao ","Fan ","Fen ","Lao ","Lao ","Chong ","Han ","Qi ","Xian ","Min ","Jing ","Liao ","Wu ","Can ","Jue ","Cu ","Xian ","Tan ","Sheng ","Pi ","Yi ","Chu ","Xian ","Nao ","Dan ","Tan ","Jing ","Song ","Han ","Jiao ","Wai ","Huan ","Dong ","Qin ","Qin ","Qu ","Cao ","Ken ","Xie ","Ying ","Ao ","Mao ","Yi ","Lin ","Se ","Jun ","Huai ","Men ","Lan ","Ai ","Lin ","Yan ","Gua ","Xia ","Chi ","Yu ","Yin ","Dai ","Meng ","Ai ","Meng ","Dui ","Qi ","Mo ","Lan ","Men ","Chou ","Zhi ","Nuo ","Nuo ","Yan ","Yang ","Bo ","Zhi ","Kuang ","Kuang ","You ","Fu ","Liu ","Mie ","Cheng ","[?] ","Chan ","Meng ","Lan ","Huai ","Xuan ","Rang ","Chan ","Ji ","Ju ","Huan ","She ","Yi "]});var sz=m((o6e,oz)=>{oz.exports=["Lian ","Nan ","Mi ","Tang ","Jue ","Gang ","Gang ","Gang ","Ge ","Yue ","Wu ","Jian ","Xu ","Shu ","Rong ","Xi ","Cheng ","Wo ","Jie ","Ge ","Jian ","Qiang ","Huo ","Qiang ","Zhan ","Dong ","Qi ","Jia ","Die ","Zei ","Jia ","Ji ","Shi ","Kan ","Ji ","Kui ","Gai ","Deng ","Zhan ","Chuang ","Ge ","Jian ","Jie ","Yu ","Jian ","Yan ","Lu ","Xi ","Zhan ","Xi ","Xi ","Chuo ","Dai ","Qu ","Hu ","Hu ","Hu ","E ","Shi ","Li ","Mao ","Hu ","Li ","Fang ","Suo ","Bian ","Dian ","Jiong ","Shang ","Yi ","Yi ","Shan ","Hu ","Fei ","Yan ","Shou ","T ","Cai ","Zha ","Qiu ","Le ","Bu ","Ba ","Da ","Reng ","Fu ","Hameru ","Zai ","Tuo ","Zhang ","Diao ","Kang ","Yu ","Ku ","Han ","Shen ","Cha ","Yi ","Gu ","Kou ","Wu ","Tuo ","Qian ","Zhi ","Ren ","Kuo ","Men ","Sao ","Yang ","Niu ","Ban ","Che ","Rao ","Xi ","Qian ","Ban ","Jia ","Yu ","Fu ","Ao ","Xi ","Pi ","Zhi ","Zi ","E ","Dun ","Zhao ","Cheng ","Ji ","Yan ","Kuang ","Bian ","Chao ","Ju ","Wen ","Hu ","Yue ","Jue ","Ba ","Qin ","Zhen ","Zheng ","Yun ","Wan ","Nu ","Yi ","Shu ","Zhua ","Pou ","Tou ","Dou ","Kang ","Zhe ","Pou ","Fu ","Pao ","Ba ","Ao ","Ze ","Tuan ","Kou ","Lun ","Qiang ","[?] ","Hu ","Bao ","Bing ","Zhi ","Peng ","Tan ","Pu ","Pi ","Tai ","Yao ","Zhen ","Zha ","Yang ","Bao ","He ","Ni ","Yi ","Di ","Chi ","Pi ","Za ","Mo ","Mo ","Shen ","Ya ","Chou ","Qu ","Min ","Chu ","Jia ","Fu ","Zhan ","Zhu ","Dan ","Chai ","Mu ","Nian ","La ","Fu ","Pao ","Ban ","Pai ","Ling ","Na ","Guai ","Qian ","Ju ","Tuo ","Ba ","Tuo ","Tuo ","Ao ","Ju ","Zhuo ","Pan ","Zhao ","Bai ","Bai ","Di ","Ni ","Ju ","Kuo ","Long ","Jian ","[?] ","Yong ","Lan ","Ning ","Bo ","Ze ","Qian ","Hen ","Gua ","Shi ","Jie ","Zheng ","Nin ","Gong ","Gong ","Quan ","Shuan ","Cun ","Zan ","Kao ","Chi ","Xie ","Ce ","Hui ","Pin ","Zhuai ","Shi ","Na "]});var lz=m((s6e,az)=>{az.exports=["Bo ","Chi ","Gua ","Zhi ","Kuo ","Duo ","Duo ","Zhi ","Qie ","An ","Nong ","Zhen ","Ge ","Jiao ","Ku ","Dong ","Ru ","Tiao ","Lie ","Zha ","Lu ","Die ","Wa ","Jue ","Mushiru ","Ju ","Zhi ","Luan ","Ya ","Zhua ","Ta ","Xie ","Nao ","Dang ","Jiao ","Zheng ","Ji ","Hui ","Xun ","Ku ","Ai ","Tuo ","Nuo ","Cuo ","Bo ","Geng ","Ti ","Zhen ","Cheng ","Suo ","Suo ","Keng ","Mei ","Long ","Ju ","Peng ","Jian ","Yi ","Ting ","Shan ","Nuo ","Wan ","Xie ","Cha ","Feng ","Jiao ","Wu ","Jun ","Jiu ","Tong ","Kun ","Huo ","Tu ","Zhuo ","Pou ","Le ","Ba ","Han ","Shao ","Nie ","Juan ","Ze ","Song ","Ye ","Jue ","Bu ","Huan ","Bu ","Zun ","Yi ","Zhai ","Lu ","Sou ","Tuo ","Lao ","Sun ","Bang ","Jian ","Huan ","Dao ","[?] ","Wan ","Qin ","Peng ","She ","Lie ","Min ","Men ","Fu ","Bai ","Ju ","Dao ","Wo ","Ai ","Juan ","Yue ","Zong ","Chen ","Chui ","Jie ","Tu ","Ben ","Na ","Nian ","Nuo ","Zu ","Wo ","Xi ","Xian ","Cheng ","Dian ","Sao ","Lun ","Qing ","Gang ","Duo ","Shou ","Diao ","Pou ","Di ","Zhang ","Gun ","Ji ","Tao ","Qia ","Qi ","Pai ","Shu ","Qian ","Ling ","Yi ","Ya ","Jue ","Zheng ","Liang ","Gua ","Yi ","Huo ","Shan ","Zheng ","Lue ","Cai ","Tan ","Che ","Bing ","Jie ","Ti ","Kong ","Tui ","Yan ","Cuo ","Zou ","Ju ","Tian ","Qian ","Ken ","Bai ","Shou ","Jie ","Lu ","Guo ","Haba ","[?] ","Zhi ","Dan ","Mang ","Xian ","Sao ","Guan ","Peng ","Yuan ","Nuo ","Jian ","Zhen ","Jiu ","Jian ","Yu ","Yan ","Kui ","Nan ","Hong ","Rou ","Pi ","Wei ","Sai ","Zou ","Xuan ","Miao ","Ti ","Nie ","Cha ","Shi ","Zong ","Zhen ","Yi ","Shun ","Heng ","Bian ","Yang ","Huan ","Yan ","Zuan ","An ","Xu ","Ya ","Wo ","Ke ","Chuai ","Ji ","Ti ","La ","La ","Cheng ","Kai ","Jiu ","Jiu ","Tu ","Jie ","Hui ","Geng ","Chong ","Shuo ","She ","Xie ","Yuan ","Qian ","Ye ","Cha ","Zha ","Bei ","Yao ","[?] ","[?] ","Lan ","Wen ","Qin "]});var cz=m((a6e,uz)=>{uz.exports=["Chan ","Ge ","Lou ","Zong ","Geng ","Jiao ","Gou ","Qin ","Yong ","Que ","Chou ","Chi ","Zhan ","Sun ","Sun ","Bo ","Chu ","Rong ","Beng ","Cuo ","Sao ","Ke ","Yao ","Dao ","Zhi ","Nu ","Xie ","Jian ","Sou ","Qiu ","Gao ","Xian ","Shuo ","Sang ","Jin ","Mie ","E ","Chui ","Nuo ","Shan ","Ta ","Jie ","Tang ","Pan ","Ban ","Da ","Li ","Tao ","Hu ","Zhi ","Wa ","Xia ","Qian ","Wen ","Qiang ","Tian ","Zhen ","E ","Xi ","Nuo ","Quan ","Cha ","Zha ","Ge ","Wu ","En ","She ","Kang ","She ","Shu ","Bai ","Yao ","Bin ","Sou ","Tan ","Sa ","Chan ","Suo ","Liao ","Chong ","Chuang ","Guo ","Bing ","Feng ","Shuai ","Di ","Qi ","Sou ","Zhai ","Lian ","Tang ","Chi ","Guan ","Lu ","Luo ","Lou ","Zong ","Gai ","Hu ","Zha ","Chuang ","Tang ","Hua ","Cui ","Nai ","Mo ","Jiang ","Gui ","Ying ","Zhi ","Ao ","Zhi ","Nie ","Man ","Shan ","Kou ","Shu ","Suo ","Tuan ","Jiao ","Mo ","Mo ","Zhe ","Xian ","Keng ","Piao ","Jiang ","Yin ","Gou ","Qian ","Lue ","Ji ","Ying ","Jue ","Pie ","Pie ","Lao ","Dun ","Xian ","Ruan ","Kui ","Zan ","Yi ","Xun ","Cheng ","Cheng ","Sa ","Nao ","Heng ","Si ","Qian ","Huang ","Da ","Zun ","Nian ","Lin ","Zheng ","Hui ","Zhuang ","Jiao ","Ji ","Cao ","Dan ","Dan ","Che ","Bo ","Che ","Jue ","Xiao ","Liao ","Ben ","Fu ","Qiao ","Bo ","Cuo ","Zhuo ","Zhuan ","Tuo ","Pu ","Qin ","Dun ","Nian ","[?] ","Xie ","Lu ","Jiao ","Cuan ","Ta ","Han ","Qiao ","Zhua ","Jian ","Gan ","Yong ","Lei ","Kuo ","Lu ","Shan ","Zhuo ","Ze ","Pu ","Chuo ","Ji ","Dang ","Suo ","Cao ","Qing ","Jing ","Huan ","Jie ","Qin ","Kuai ","Dan ","Xi ","Ge ","Pi ","Bo ","Ao ","Ju ","Ye ","[?] ","Mang ","Sou ","Mi ","Ji ","Tai ","Zhuo ","Dao ","Xing ","Lan ","Ca ","Ju ","Ye ","Ru ","Ye ","Ye ","Ni ","Hu ","Ji ","Bin ","Ning ","Ge ","Zhi ","Jie ","Kuo ","Mo ","Jian ","Xie ","Lie ","Tan ","Bai ","Sou ","Lu ","Lue ","Rao ","Zhi "]});var dz=m((l6e,hz)=>{hz.exports=["Pan ","Yang ","Lei ","Sa ","Shu ","Zan ","Nian ","Xian ","Jun ","Huo ","Li ","La ","Han ","Ying ","Lu ","Long ","Qian ","Qian ","Zan ","Qian ","Lan ","San ","Ying ","Mei ","Rang ","Chan ","[?] ","Cuan ","Xi ","She ","Luo ","Jun ","Mi ","Li ","Zan ","Luan ","Tan ","Zuan ","Li ","Dian ","Wa ","Dang ","Jiao ","Jue ","Lan ","Li ","Nang ","Zhi ","Gui ","Gui ","Qi ","Xin ","Pu ","Sui ","Shou ","Kao ","You ","Gai ","Yi ","Gong ","Gan ","Ban ","Fang ","Zheng ","Bo ","Dian ","Kou ","Min ","Wu ","Gu ","He ","Ce ","Xiao ","Mi ","Chu ","Ge ","Di ","Xu ","Jiao ","Min ","Chen ","Jiu ","Zhen ","Duo ","Yu ","Chi ","Ao ","Bai ","Xu ","Jiao ","Duo ","Lian ","Nie ","Bi ","Chang ","Dian ","Duo ","Yi ","Gan ","San ","Ke ","Yan ","Dun ","Qi ","Dou ","Xiao ","Duo ","Jiao ","Jing ","Yang ","Xia ","Min ","Shu ","Ai ","Qiao ","Ai ","Zheng ","Di ","Zhen ","Fu ","Shu ","Liao ","Qu ","Xiong ","Xi ","Jiao ","Sen ","Jiao ","Zhuo ","Yi ","Lian ","Bi ","Li ","Xiao ","Xiao ","Wen ","Xue ","Qi ","Qi ","Zhai ","Bin ","Jue ","Zhai ","[?] ","Fei ","Ban ","Ban ","Lan ","Yu ","Lan ","Wei ","Dou ","Sheng ","Liao ","Jia ","Hu ","Xie ","Jia ","Yu ","Zhen ","Jiao ","Wo ","Tou ","Chu ","Jin ","Chi ","Yin ","Fu ","Qiang ","Zhan ","Qu ","Zhuo ","Zhan ","Duan ","Zhuo ","Si ","Xin ","Zhuo ","Zhuo ","Qin ","Lin ","Zhuo ","Chu ","Duan ","Zhu ","Fang ","Xie ","Hang ","Yu ","Shi ","Pei ","You ","Mye ","Pang ","Qi ","Zhan ","Mao ","Lu ","Pei ","Pi ","Liu ","Fu ","Fang ","Xuan ","Jing ","Jing ","Ni ","Zu ","Zhao ","Yi ","Liu ","Shao ","Jian ","Es ","Yi ","Qi ","Zhi ","Fan ","Piao ","Fan ","Zhan ","Guai ","Sui ","Yu ","Wu ","Ji ","Ji ","Ji ","Huo ","Ri ","Dan ","Jiu ","Zhi ","Zao ","Xie ","Tiao ","Xun ","Xu ","Xu ","Xu ","Gan ","Han ","Tai ","Di ","Xu ","Chan ","Shi ","Kuang ","Yang ","Shi ","Wang ","Min ","Min ","Tun ","Chun ","Wu "]});var fz=m((u6e,gz)=>{gz.exports=["Yun ","Bei ","Ang ","Ze ","Ban ","Jie ","Kun ","Sheng ","Hu ","Fang ","Hao ","Gui ","Chang ","Xuan ","Ming ","Hun ","Fen ","Qin ","Hu ","Yi ","Xi ","Xin ","Yan ","Ze ","Fang ","Tan ","Shen ","Ju ","Yang ","Zan ","Bing ","Xing ","Ying ","Xuan ","Pei ","Zhen ","Ling ","Chun ","Hao ","Mei ","Zuo ","Mo ","Bian ","Xu ","Hun ","Zhao ","Zong ","Shi ","Shi ","Yu ","Fei ","Die ","Mao ","Ni ","Chang ","Wen ","Dong ","Ai ","Bing ","Ang ","Zhou ","Long ","Xian ","Kuang ","Tiao ","Chao ","Shi ","Huang ","Huang ","Xuan ","Kui ","Xu ","Jiao ","Jin ","Zhi ","Jin ","Shang ","Tong ","Hong ","Yan ","Gai ","Xiang ","Shai ","Xiao ","Ye ","Yun ","Hui ","Han ","Han ","Jun ","Wan ","Xian ","Kun ","Zhou ","Xi ","Cheng ","Sheng ","Bu ","Zhe ","Zhe ","Wu ","Han ","Hui ","Hao ","Chen ","Wan ","Tian ","Zhuo ","Zui ","Zhou ","Pu ","Jing ","Xi ","Shan ","Yi ","Xi ","Qing ","Qi ","Jing ","Gui ","Zhen ","Yi ","Zhi ","An ","Wan ","Lin ","Liang ","Chang ","Wang ","Xiao ","Zan ","Hi ","Xuan ","Xuan ","Yi ","Xia ","Yun ","Hui ","Fu ","Min ","Kui ","He ","Ying ","Du ","Wei ","Shu ","Qing ","Mao ","Nan ","Jian ","Nuan ","An ","Yang ","Chun ","Yao ","Suo ","Jin ","Ming ","Jiao ","Kai ","Gao ","Weng ","Chang ","Qi ","Hao ","Yan ","Li ","Ai ","Ji ","Gui ","Men ","Zan ","Xie ","Hao ","Mu ","Mo ","Cong ","Ni ","Zhang ","Hui ","Bao ","Han ","Xuan ","Chuan ","Liao ","Xian ","Dan ","Jing ","Pie ","Lin ","Tun ","Xi ","Yi ","Ji ","Huang ","Tai ","Ye ","Ye ","Li ","Tan ","Tong ","Xiao ","Fei ","Qin ","Zhao ","Hao ","Yi ","Xiang ","Xing ","Sen ","Jiao ","Bao ","Jing ","Yian ","Ai ","Ye ","Ru ","Shu ","Meng ","Xun ","Yao ","Pu ","Li ","Chen ","Kuang ","Die ","[?] ","Yan ","Huo ","Lu ","Xi ","Rong ","Long ","Nang ","Luo ","Luan ","Shai ","Tang ","Yan ","Chu ","Yue ","Yue ","Qu ","Yi ","Geng ","Ye ","Hu ","He ","Shu ","Cao ","Cao ","Noboru ","Man ","Ceng ","Ceng ","Ti "]});var mz=m((c6e,pz)=>{pz.exports=["Zui ","Can ","Xu ","Hui ","Yin ","Qie ","Fen ","Pi ","Yue ","You ","Ruan ","Peng ","Ban ","Fu ","Ling ","Fei ","Qu ","[?] ","Nu ","Tiao ","Shuo ","Zhen ","Lang ","Lang ","Juan ","Ming ","Huang ","Wang ","Tun ","Zhao ","Ji ","Qi ","Ying ","Zong ","Wang ","Tong ","Lang ","[?] ","Meng ","Long ","Mu ","Deng ","Wei ","Mo ","Ben ","Zha ","Zhu ","Zhu ","[?] ","Zhu ","Ren ","Ba ","Po ","Duo ","Duo ","Dao ","Li ","Qiu ","Ji ","Jiu ","Bi ","Xiu ","Ting ","Ci ","Sha ","Eburi ","Za ","Quan ","Qian ","Yu ","Gan ","Wu ","Cha ","Shan ","Xun ","Fan ","Wu ","Zi ","Li ","Xing ","Cai ","Cun ","Ren ","Shao ","Tuo ","Di ","Zhang ","Mang ","Chi ","Yi ","Gu ","Gong ","Du ","Yi ","Qi ","Shu ","Gang ","Tiao ","Moku ","Soma ","Tochi ","Lai ","Sugi ","Mang ","Yang ","Ma ","Miao ","Si ","Yuan ","Hang ","Fei ","Bei ","Jie ","Dong ","Gao ","Yao ","Xian ","Chu ","Qun ","Pa ","Shu ","Hua ","Xin ","Chou ","Zhu ","Chou ","Song ","Ban ","Song ","Ji ","Yue ","Jin ","Gou ","Ji ","Mao ","Pi ","Bi ","Wang ","Ang ","Fang ","Fen ","Yi ","Fu ","Nan ","Xi ","Hu ","Ya ","Dou ","Xun ","Zhen ","Yao ","Lin ","Rui ","E ","Mei ","Zhao ","Guo ","Zhi ","Cong ","Yun ","Waku ","Dou ","Shu ","Zao ","[?] ","Li ","Haze ","Jian ","Cheng ","Matsu ","Qiang ","Feng ","Nan ","Xiao ","Xian ","Ku ","Ping ","Yi ","Xi ","Zhi ","Guai ","Xiao ","Jia ","Jia ","Gou ","Fu ","Mo ","Yi ","Ye ","Ye ","Shi ","Nie ","Bi ","Duo ","Yi ","Ling ","Bing ","Ni ","La ","He ","Pan ","Fan ","Zhong ","Dai ","Ci ","Yang ","Fu ","Bo ","Mou ","Gan ","Qi ","Ran ","Rou ","Mao ","Zhao ","Song ","Zhe ","Xia ","You ","Shen ","Ju ","Tuo ","Zuo ","Nan ","Ning ","Yong ","Di ","Zhi ","Zha ","Cha ","Dan ","Gu ","Pu ","Jiu ","Ao ","Fu ","Jian ","Bo ","Duo ","Ke ","Nai ","Zhu ","Bi ","Liu ","Chai ","Zha ","Si ","Zhu ","Pei ","Shi ","Guai ","Cha ","Yao ","Jue ","Jiu ","Shi "]});var yz=m((h6e,bz)=>{bz.exports=["Zhi ","Liu ","Mei ","Hoy ","Rong ","Zha ","[?] ","Biao ","Zhan ","Jie ","Long ","Dong ","Lu ","Sayng ","Li ","Lan ","Yong ","Shu ","Xun ","Shuan ","Qi ","Zhen ","Qi ","Li ","Yi ","Xiang ","Zhen ","Li ","Su ","Gua ","Kan ","Bing ","Ren ","Xiao ","Bo ","Ren ","Bing ","Zi ","Chou ","Yi ","Jie ","Xu ","Zhu ","Jian ","Zui ","Er ","Er ","You ","Fa ","Gong ","Kao ","Lao ","Zhan ","Li ","Yin ","Yang ","He ","Gen ","Zhi ","Chi ","Ge ","Zai ","Luan ","Fu ","Jie ","Hang ","Gui ","Tao ","Guang ","Wei ","Kuang ","Ru ","An ","An ","Juan ","Yi ","Zhuo ","Ku ","Zhi ","Qiong ","Tong ","Sang ","Sang ","Huan ","Jie ","Jiu ","Xue ","Duo ","Zhui ","Yu ","Zan ","Kasei ","Ying ","Masu ","[?] ","Zhan ","Ya ","Nao ","Zhen ","Dang ","Qi ","Qiao ","Hua ","Kuai ","Jiang ","Zhuang ","Xun ","Suo ","Sha ","Zhen ","Bei ","Ting ","Gua ","Jing ","Bo ","Ben ","Fu ","Rui ","Tong ","Jue ","Xi ","Lang ","Liu ","Feng ","Qi ","Wen ","Jun ","Gan ","Cu ","Liang ","Qiu ","Ting ","You ","Mei ","Bang ","Long ","Peng ","Zhuang ","Di ","Xuan ","Tu ","Zao ","Ao ","Gu ","Bi ","Di ","Han ","Zi ","Zhi ","Ren ","Bei ","Geng ","Jian ","Huan ","Wan ","Nuo ","Jia ","Tiao ","Ji ","Xiao ","Lu ","Huan ","Shao ","Cen ","Fen ","Song ","Meng ","Wu ","Li ","Li ","Dou ","Cen ","Ying ","Suo ","Ju ","Ti ","Jie ","Kun ","Zhuo ","Shu ","Chan ","Fan ","Wei ","Jing ","Li ","Bing ","Fumoto ","Shikimi ","Tao ","Zhi ","Lai ","Lian ","Jian ","Zhuo ","Ling ","Li ","Qi ","Bing ","Zhun ","Cong ","Qian ","Mian ","Qi ","Qi ","Cai ","Gun ","Chan ","Te ","Fei ","Pai ","Bang ","Pou ","Hun ","Zong ","Cheng ","Zao ","Ji ","Li ","Peng ","Yu ","Yu ","Gu ","Hun ","Dong ","Tang ","Gang ","Wang ","Di ","Xi ","Fan ","Cheng ","Zhan ","Qi ","Yuan ","Yan ","Yu ","Quan ","Yi ","Sen ","Ren ","Chui ","Leng ","Qi ","Zhuo ","Fu ","Ke ","Lai ","Zou ","Zou ","Zhuo ","Guan ","Fen ","Fen ","Chen ","Qiong ","Nie "]});var wz=m((d6e,vz)=>{vz.exports=["Wan ","Guo ","Lu ","Hao ","Jie ","Yi ","Chou ","Ju ","Ju ","Cheng ","Zuo ","Liang ","Qiang ","Zhi ","Zhui ","Ya ","Ju ","Bei ","Jiao ","Zhuo ","Zi ","Bin ","Peng ","Ding ","Chu ","Chang ","Kunugi ","Momiji ","Jian ","Gui ","Xi ","Du ","Qian ","Kunugi ","Soko ","Shide ","Luo ","Zhi ","Ken ","Myeng ","Tafu ","[?] ","Peng ","Zhan ","[?] ","Tuo ","Sen ","Duo ","Ye ","Fou ","Wei ","Wei ","Duan ","Jia ","Zong ","Jian ","Yi ","Shen ","Xi ","Yan ","Yan ","Chuan ","Zhan ","Chun ","Yu ","He ","Zha ","Wo ","Pian ","Bi ","Yao ","Huo ","Xu ","Ruo ","Yang ","La ","Yan ","Ben ","Hun ","Kui ","Jie ","Kui ","Si ","Feng ","Xie ","Tuo ","Zhi ","Jian ","Mu ","Mao ","Chu ","Hu ","Hu ","Lian ","Leng ","Ting ","Nan ","Yu ","You ","Mei ","Song ","Xuan ","Xuan ","Ying ","Zhen ","Pian ","Ye ","Ji ","Jie ","Ye ","Chu ","Shun ","Yu ","Cou ","Wei ","Mei ","Di ","Ji ","Jie ","Kai ","Qiu ","Ying ","Rou ","Heng ","Lou ","Le ","Hazou ","Katsura ","Pin ","Muro ","Gai ","Tan ","Lan ","Yun ","Yu ","Chen ","Lu ","Ju ","Sakaki ","[?] ","Pi ","Xie ","Jia ","Yi ","Zhan ","Fu ","Nai ","Mi ","Lang ","Rong ","Gu ","Jian ","Ju ","Ta ","Yao ","Zhen ","Bang ","Sha ","Yuan ","Zi ","Ming ","Su ","Jia ","Yao ","Jie ","Huang ","Gan ","Fei ","Zha ","Qian ","Ma ","Sun ","Yuan ","Xie ","Rong ","Shi ","Zhi ","Cui ","Yun ","Ting ","Liu ","Rong ","Tang ","Que ","Zhai ","Si ","Sheng ","Ta ","Ke ","Xi ","Gu ","Qi ","Kao ","Gao ","Sun ","Pan ","Tao ","Ge ","Xun ","Dian ","Nou ","Ji ","Shuo ","Gou ","Chui ","Qiang ","Cha ","Qian ","Huai ","Mei ","Xu ","Gang ","Gao ","Zhuo ","Tuo ","Hashi ","Yang ","Dian ","Jia ","Jian ","Zui ","Kashi ","Ori ","Bin ","Zhu ","[?] ","Xi ","Qi ","Lian ","Hui ","Yong ","Qian ","Guo ","Gai ","Gai ","Tuan ","Hua ","Cu ","Sen ","Cui ","Beng ","You ","Hu ","Jiang ","Hu ","Huan ","Kui ","Yi ","Nie ","Gao ","Kang ","Gui ","Gui ","Cao ","Man ","Jin "]});var xz=m((g6e,Dz)=>{Dz.exports=["Di ","Zhuang ","Le ","Lang ","Chen ","Cong ","Li ","Xiu ","Qing ","Shuang ","Fan ","Tong ","Guan ","Ji ","Suo ","Lei ","Lu ","Liang ","Mi ","Lou ","Chao ","Su ","Ke ","Shu ","Tang ","Biao ","Lu ","Jiu ","Shu ","Zha ","Shu ","Zhang ","Men ","Mo ","Niao ","Yang ","Tiao ","Peng ","Zhu ","Sha ","Xi ","Quan ","Heng ","Jian ","Cong ","[?] ","Hokuso ","Qiang ","Tara ","Ying ","Er ","Xin ","Zhi ","Qiao ","Zui ","Cong ","Pu ","Shu ","Hua ","Kui ","Zhen ","Zun ","Yue ","Zhan ","Xi ","Xun ","Dian ","Fa ","Gan ","Mo ","Wu ","Qiao ","Nao ","Lin ","Liu ","Qiao ","Xian ","Run ","Fan ","Zhan ","Tuo ","Lao ","Yun ","Shun ","Tui ","Cheng ","Tang ","Meng ","Ju ","Cheng ","Su ","Jue ","Jue ","Tan ","Hui ","Ji ","Nuo ","Xiang ","Tuo ","Ning ","Rui ","Zhu ","Chuang ","Zeng ","Fen ","Qiong ","Ran ","Heng ","Cen ","Gu ","Liu ","Lao ","Gao ","Chu ","Zusa ","Nude ","Ca ","San ","Ji ","Dou ","Shou ","Lu ","[?] ","[?] ","Yuan ","Ta ","Shu ","Jiang ","Tan ","Lin ","Nong ","Yin ","Xi ","Sui ","Shan ","Zui ","Xuan ","Cheng ","Gan ","Ju ","Zui ","Yi ","Qin ","Pu ","Yan ","Lei ","Feng ","Hui ","Dang ","Ji ","Sui ","Bo ","Bi ","Ding ","Chu ","Zhua ","Kuai ","Ji ","Jie ","Jia ","Qing ","Zhe ","Jian ","Qiang ","Dao ","Yi ","Biao ","Song ","She ","Lin ","Kunugi ","Cha ","Meng ","Yin ","Tao ","Tai ","Mian ","Qi ","Toan ","Bin ","Huo ","Ji ","Qian ","Mi ","Ning ","Yi ","Gao ","Jian ","Yin ","Er ","Qing ","Yan ","Qi ","Mi ","Zhao ","Gui ","Chun ","Ji ","Kui ","Po ","Deng ","Chu ","[?] ","Mian ","You ","Zhi ","Guang ","Qian ","Lei ","Lei ","Sa ","Lu ","Li ","Cuan ","Lu ","Mie ","Hui ","Ou ","Lu ","Jie ","Gao ","Du ","Yuan ","Li ","Fei ","Zhuo ","Sou ","Lian ","Tamo ","Chu ","[?] ","Zhu ","Lu ","Yan ","Li ","Zhu ","Chen ","Jie ","E ","Su ","Huai ","Nie ","Yu ","Long ","Lai ","[?] ","Xian ","Kwi ","Ju ","Xiao ","Ling ","Ying ","Jian ","Yin ","You ","Ying "]});var Sz=m((f6e,Cz)=>{Cz.exports=["Xiang ","Nong ","Bo ","Chan ","Lan ","Ju ","Shuang ","She ","Wei ","Cong ","Quan ","Qu ","Cang ","[?] ","Yu ","Luo ","Li ","Zan ","Luan ","Dang ","Jue ","Em ","Lan ","Lan ","Zhu ","Lei ","Li ","Ba ","Nang ","Yu ","Ling ","Tsuki ","Qian ","Ci ","Huan ","Xin ","Yu ","Yu ","Qian ","Ou ","Xu ","Chao ","Chu ","Chi ","Kai ","Yi ","Jue ","Xi ","Xu ","Xia ","Yu ","Kuai ","Lang ","Kuan ","Shuo ","Xi ","Ai ","Yi ","Qi ","Hu ","Chi ","Qin ","Kuan ","Kan ","Kuan ","Kan ","Chuan ","Sha ","Gua ","Yin ","Xin ","Xie ","Yu ","Qian ","Xiao ","Yi ","Ge ","Wu ","Tan ","Jin ","Ou ","Hu ","Ti ","Huan ","Xu ","Pen ","Xi ","Xiao ","Xu ","Xi ","Sen ","Lian ","Chu ","Yi ","Kan ","Yu ","Chuo ","Huan ","Zhi ","Zheng ","Ci ","Bu ","Wu ","Qi ","Bu ","Bu ","Wai ","Ju ","Qian ","Chi ","Se ","Chi ","Se ","Zhong ","Sui ","Sui ","Li ","Cuo ","Yu ","Li ","Gui ","Dai ","Dai ","Si ","Jian ","Zhe ","Mo ","Mo ","Yao ","Mo ","Cu ","Yang ","Tian ","Sheng ","Dai ","Shang ","Xu ","Xun ","Shu ","Can ","Jue ","Piao ","Qia ","Qiu ","Su ","Qing ","Yun ","Lian ","Yi ","Fou ","Zhi ","Ye ","Can ","Hun ","Dan ","Ji ","Ye ","Zhen ","Yun ","Wen ","Chou ","Bin ","Ti ","Jin ","Shang ","Yin ","Diao ","Cu ","Hui ","Cuan ","Yi ","Dan ","Du ","Jiang ","Lian ","Bin ","Du ","Tsukusu ","Jian ","Shu ","Ou ","Duan ","Zhu ","Yin ","Qing ","Yi ","Sha ","Que ","Ke ","Yao ","Jun ","Dian ","Hui ","Hui ","Gu ","Que ","Ji ","Yi ","Ou ","Hui ","Duan ","Yi ","Xiao ","Wu ","Guan ","Mu ","Mei ","Mei ","Ai ","Zuo ","Du ","Yu ","Bi ","Bi ","Bi ","Pi ","Pi ","Bi ","Chan ","Mao ","[?] ","[?] ","Pu ","Mushiru ","Jia ","Zhan ","Sai ","Mu ","Tuo ","Xun ","Er ","Rong ","Xian ","Ju ","Mu ","Hao ","Qiu ","Dou ","Mushiru ","Tan ","Pei ","Ju ","Duo ","Cui ","Bi ","San ","[?] ","Mao ","Sui ","Yu ","Yu ","Tuo ","He ","Jian ","Ta ","San "]});var kz=m((p6e,Tz)=>{Tz.exports=["Lu ","Mu ","Li ","Tong ","Rong ","Chang ","Pu ","Luo ","Zhan ","Sao ","Zhan ","Meng ","Luo ","Qu ","Die ","Shi ","Di ","Min ","Jue ","Mang ","Qi ","Pie ","Nai ","Qi ","Dao ","Xian ","Chuan ","Fen ","Ri ","Nei ","[?] ","Fu ","Shen ","Dong ","Qing ","Qi ","Yin ","Xi ","Hai ","Yang ","An ","Ya ","Ke ","Qing ","Ya ","Dong ","Dan ","Lu ","Qing ","Yang ","Yun ","Yun ","Shui ","San ","Zheng ","Bing ","Yong ","Dang ","Shitamizu ","Le ","Ni ","Tun ","Fan ","Gui ","Ting ","Zhi ","Qiu ","Bin ","Ze ","Mian ","Cuan ","Hui ","Diao ","Yi ","Cha ","Zhuo ","Chuan ","Wan ","Fan ","Dai ","Xi ","Tuo ","Mang ","Qiu ","Qi ","Shan ","Pai ","Han ","Qian ","Wu ","Wu ","Xun ","Si ","Ru ","Gong ","Jiang ","Chi ","Wu ","Tsuchi ","[?] ","Tang ","Zhi ","Chi ","Qian ","Mi ","Yu ","Wang ","Qing ","Jing ","Rui ","Jun ","Hong ","Tai ","Quan ","Ji ","Bian ","Bian ","Gan ","Wen ","Zhong ","Fang ","Xiong ","Jue ","Hang ","Niou ","Qi ","Fen ","Xu ","Xu ","Qin ","Yi ","Wo ","Yun ","Yuan ","Hang ","Yan ","Chen ","Chen ","Dan ","You ","Dun ","Hu ","Huo ","Qie ","Mu ","Rou ","Mei ","Ta ","Mian ","Wu ","Chong ","Tian ","Bi ","Sha ","Zhi ","Pei ","Pan ","Zhui ","Za ","Gou ","Liu ","Mei ","Ze ","Feng ","Ou ","Li ","Lun ","Cang ","Feng ","Wei ","Hu ","Mo ","Mei ","Shu ","Ju ","Zan ","Tuo ","Tuo ","Tuo ","He ","Li ","Mi ","Yi ","Fa ","Fei ","You ","Tian ","Zhi ","Zhao ","Gu ","Zhan ","Yan ","Si ","Kuang ","Jiong ","Ju ","Xie ","Qiu ","Yi ","Jia ","Zhong ","Quan ","Bo ","Hui ","Mi ","Ben ","Zhuo ","Chu ","Le ","You ","Gu ","Hong ","Gan ","Fa ","Mao ","Si ","Hu ","Ping ","Ci ","Fan ","Chi ","Su ","Ning ","Cheng ","Ling ","Pao ","Bo ","Qi ","Si ","Ni ","Ju ","Yue ","Zhu ","Sheng ","Lei ","Xuan ","Xue ","Fu ","Pan ","Min ","Tai ","Yang ","Ji ","Yong ","Guan ","Beng ","Xue ","Long ","Lu ","[?] ","Bo ","Xie ","Po ","Ze ","Jing ","Yin "]});var Pz=m((m6e,Ez)=>{Ez.exports=["Zhou ","Ji ","Yi ","Hui ","Hui ","Zui ","Cheng ","Yin ","Wei ","Hou ","Jian ","Yang ","Lie ","Si ","Ji ","Er ","Xing ","Fu ","Sa ","Suo ","Zhi ","Yin ","Wu ","Xi ","Kao ","Zhu ","Jiang ","Luo ","[?] ","An ","Dong ","Yi ","Mou ","Lei ","Yi ","Mi ","Quan ","Jin ","Mo ","Wei ","Xiao ","Xie ","Hong ","Xu ","Shuo ","Kuang ","Tao ","Qie ","Ju ","Er ","Zhou ","Ru ","Ping ","Xun ","Xiong ","Zhi ","Guang ","Huan ","Ming ","Huo ","Wa ","Qia ","Pai ","Wu ","Qu ","Liu ","Yi ","Jia ","Jing ","Qian ","Jiang ","Jiao ","Cheng ","Shi ","Zhuo ","Ce ","Pal ","Kuai ","Ji ","Liu ","Chan ","Hun ","Hu ","Nong ","Xun ","Jin ","Lie ","Qiu ","Wei ","Zhe ","Jun ","Han ","Bang ","Mang ","Zhuo ","You ","Xi ","Bo ","Dou ","Wan ","Hong ","Yi ","Pu ","Ying ","Lan ","Hao ","Lang ","Han ","Li ","Geng ","Fu ","Wu ","Lian ","Chun ","Feng ","Yi ","Yu ","Tong ","Lao ","Hai ","Jin ","Jia ","Chong ","Weng ","Mei ","Sui ","Cheng ","Pei ","Xian ","Shen ","Tu ","Kun ","Pin ","Nie ","Han ","Jing ","Xiao ","She ","Nian ","Tu ","Yong ","Xiao ","Xian ","Ting ","E ","Su ","Tun ","Juan ","Cen ","Ti ","Li ","Shui ","Si ","Lei ","Shui ","Tao ","Du ","Lao ","Lai ","Lian ","Wei ","Wo ","Yun ","Huan ","Di ","[?] ","Run ","Jian ","Zhang ","Se ","Fu ","Guan ","Xing ","Shou ","Shuan ","Ya ","Chuo ","Zhang ","Ye ","Kong ","Wo ","Han ","Tuo ","Dong ","He ","Wo ","Ju ","Gan ","Liang ","Hun ","Ta ","Zhuo ","Dian ","Qie ","De ","Juan ","Zi ","Xi ","Yao ","Qi ","Gu ","Guo ","Han ","Lin ","Tang ","Zhou ","Peng ","Hao ","Chang ","Shu ","Qi ","Fang ","Chi ","Lu ","Nao ","Ju ","Tao ","Cong ","Lei ","Zhi ","Peng ","Fei ","Song ","Tian ","Pi ","Dan ","Yu ","Ni ","Yu ","Lu ","Gan ","Mi ","Jing ","Ling ","Lun ","Yin ","Cui ","Qu ","Huai ","Yu ","Nian ","Shen ","Piao ","Chun ","Wa ","Yuan ","Lai ","Hun ","Qing ","Yan ","Qian ","Tian ","Miao ","Zhi ","Yin ","Mi "]});var Rz=m((b6e,_z)=>{_z.exports=["Ben ","Yuan ","Wen ","Re ","Fei ","Qing ","Yuan ","Ke ","Ji ","She ","Yuan ","Shibui ","Lu ","Zi ","Du ","[?] ","Jian ","Min ","Pi ","Tani ","Yu ","Yuan ","Shen ","Shen ","Rou ","Huan ","Zhu ","Jian ","Nuan ","Yu ","Qiu ","Ting ","Qu ","Du ","Feng ","Zha ","Bo ","Wo ","Wo ","Di ","Wei ","Wen ","Ru ","Xie ","Ce ","Wei ","Ge ","Gang ","Yan ","Hong ","Xuan ","Mi ","Ke ","Mao ","Ying ","Yan ","You ","Hong ","Miao ","Xing ","Mei ","Zai ","Hun ","Nai ","Kui ","Shi ","E ","Pai ","Mei ","Lian ","Qi ","Qi ","Mei ","Tian ","Cou ","Wei ","Can ","Tuan ","Mian ","Hui ","Mo ","Xu ","Ji ","Pen ","Jian ","Jian ","Hu ","Feng ","Xiang ","Yi ","Yin ","Zhan ","Shi ","Jie ","Cheng ","Huang ","Tan ","Yu ","Bi ","Min ","Shi ","Tu ","Sheng ","Yong ","Qu ","Zhong ","Suei ","Jiu ","Jiao ","Qiou ","Yin ","Tang ","Long ","Huo ","Yuan ","Nan ","Ban ","You ","Quan ","Chui ","Liang ","Chan ","Yan ","Chun ","Nie ","Zi ","Wan ","Shi ","Man ","Ying ","Ratsu ","Kui ","[?] ","Jian ","Xu ","Lu ","Gui ","Gai ","[?] ","[?] ","Po ","Jin ","Gui ","Tang ","Yuan ","Suo ","Yuan ","Lian ","Yao ","Meng ","Zhun ","Sheng ","Ke ","Tai ","Da ","Wa ","Liu ","Gou ","Sao ","Ming ","Zha ","Shi ","Yi ","Lun ","Ma ","Pu ","Wei ","Li ","Cai ","Wu ","Xi ","Wen ","Qiang ","Ze ","Shi ","Su ","Yi ","Zhen ","Sou ","Yun ","Xiu ","Yin ","Rong ","Hun ","Su ","Su ","Ni ","Ta ","Shi ","Ru ","Wei ","Pan ","Chu ","Chu ","Pang ","Weng ","Cang ","Mie ","He ","Dian ","Hao ","Huang ","Xi ","Zi ","Di ","Zhi ","Ying ","Fu ","Jie ","Hua ","Ge ","Zi ","Tao ","Teng ","Sui ","Bi ","Jiao ","Hui ","Gun ","Yin ","Gao ","Long ","Zhi ","Yan ","She ","Man ","Ying ","Chun ","Lu ","Lan ","Luan ","[?] ","Bin ","Tan ","Yu ","Sou ","Hu ","Bi ","Biao ","Zhi ","Jiang ","Kou ","Shen ","Shang ","Di ","Mi ","Ao ","Lu ","Hu ","Hu ","You ","Chan ","Fan ","Yong ","Gun ","Man "]});var Fz=m((y6e,Lz)=>{Lz.exports=["Qing ","Yu ","Piao ","Ji ","Ya ","Jiao ","Qi ","Xi ","Ji ","Lu ","Lu ","Long ","Jin ","Guo ","Cong ","Lou ","Zhi ","Gai ","Qiang ","Li ","Yan ","Cao ","Jiao ","Cong ","Qun ","Tuan ","Ou ","Teng ","Ye ","Xi ","Mi ","Tang ","Mo ","Shang ","Han ","Lian ","Lan ","Wa ","Li ","Qian ","Feng ","Xuan ","Yi ","Man ","Zi ","Mang ","Kang ","Lei ","Peng ","Shu ","Zhang ","Zhang ","Chong ","Xu ","Huan ","Kuo ","Jian ","Yan ","Chuang ","Liao ","Cui ","Ti ","Yang ","Jiang ","Cong ","Ying ","Hong ","Xun ","Shu ","Guan ","Ying ","Xiao ","[?] ","[?] ","Xu ","Lian ","Zhi ","Wei ","Pi ","Jue ","Jiao ","Po ","Dang ","Hui ","Jie ","Wu ","Pa ","Ji ","Pan ","Gui ","Xiao ","Qian ","Qian ","Xi ","Lu ","Xi ","Xuan ","Dun ","Huang ","Min ","Run ","Su ","Liao ","Zhen ","Zhong ","Yi ","Di ","Wan ","Dan ","Tan ","Chao ","Xun ","Kui ","Yie ","Shao ","Tu ","Zhu ","San ","Hei ","Bi ","Shan ","Chan ","Chan ","Shu ","Tong ","Pu ","Lin ","Wei ","Se ","Se ","Cheng ","Jiong ","Cheng ","Hua ","Jiao ","Lao ","Che ","Gan ","Cun ","Heng ","Si ","Shu ","Peng ","Han ","Yun ","Liu ","Hong ","Fu ","Hao ","He ","Xian ","Jian ","Shan ","Xi ","Oki ","[?] ","Lan ","[?] ","Yu ","Lin ","Min ","Zao ","Dang ","Wan ","Ze ","Xie ","Yu ","Li ","Shi ","Xue ","Ling ","Man ","Zi ","Yong ","Kuai ","Can ","Lian ","Dian ","Ye ","Ao ","Huan ","Zhen ","Chan ","Man ","Dan ","Dan ","Yi ","Sui ","Pi ","Ju ","Ta ","Qin ","Ji ","Zhuo ","Lian ","Nong ","Guo ","Jin ","Fen ","Se ","Ji ","Sui ","Hui ","Chu ","Ta ","Song ","Ding ","[?] ","Zhu ","Lai ","Bin ","Lian ","Mi ","Shi ","Shu ","Mi ","Ning ","Ying ","Ying ","Meng ","Jin ","Qi ","Pi ","Ji ","Hao ","Ru ","Zui ","Wo ","Tao ","Yin ","Yin ","Dui ","Ci ","Huo ","Jing ","Lan ","Jun ","Ai ","Pu ","Zhuo ","Wei ","Bin ","Gu ","Qian ","Xing ","Hama ","Kuo ","Fei ","[?] ","Boku ","Jian ","Wei ","Luo ","Zan ","Lu ","Li "]});var jz=m((v6e,Iz)=>{Iz.exports=["You ","Yang ","Lu ","Si ","Jie ","Ying ","Du ","Wang ","Hui ","Xie ","Pan ","Shen ","Biao ","Chan ","Mo ","Liu ","Jian ","Pu ","Se ","Cheng ","Gu ","Bin ","Huo ","Xian ","Lu ","Qin ","Han ","Ying ","Yong ","Li ","Jing ","Xiao ","Ying ","Sui ","Wei ","Xie ","Huai ","Hao ","Zhu ","Long ","Lai ","Dui ","Fan ","Hu ","Lai ","[?] ","[?] ","Ying ","Mi ","Ji ","Lian ","Jian ","Ying ","Fen ","Lin ","Yi ","Jian ","Yue ","Chan ","Dai ","Rang ","Jian ","Lan ","Fan ","Shuang ","Yuan ","Zhuo ","Feng ","She ","Lei ","Lan ","Cong ","Qu ","Yong ","Qian ","Fa ","Guan ","Que ","Yan ","Hao ","Hyeng ","Sa ","Zan ","Luan ","Yan ","Li ","Mi ","Shan ","Tan ","Dang ","Jiao ","Chan ","[?] ","Hao ","Ba ","Zhu ","Lan ","Lan ","Nang ","Wan ","Luan ","Xun ","Xian ","Yan ","Gan ","Yan ","Yu ","Huo ","Si ","Mie ","Guang ","Deng ","Hui ","Xiao ","Xiao ","Hu ","Hong ","Ling ","Zao ","Zhuan ","Jiu ","Zha ","Xie ","Chi ","Zhuo ","Zai ","Zai ","Can ","Yang ","Qi ","Zhong ","Fen ","Niu ","Jiong ","Wen ","Po ","Yi ","Lu ","Chui ","Pi ","Kai ","Pan ","Yan ","Kai ","Pang ","Mu ","Chao ","Liao ","Gui ","Kang ","Tun ","Guang ","Xin ","Zhi ","Guang ","Guang ","Wei ","Qiang ","[?] ","Da ","Xia ","Zheng ","Zhu ","Ke ","Zhao ","Fu ","Ba ","Duo ","Duo ","Ling ","Zhuo ","Xuan ","Ju ","Tan ","Pao ","Jiong ","Pao ","Tai ","Tai ","Bing ","Yang ","Tong ","Han ","Zhu ","Zha ","Dian ","Wei ","Shi ","Lian ","Chi ","Huang ","[?] ","Hu ","Shuo ","Lan ","Jing ","Jiao ","Xu ","Xing ","Quan ","Lie ","Huan ","Yang ","Xiao ","Xiu ","Xian ","Yin ","Wu ","Zhou ","Yao ","Shi ","Wei ","Tong ","Xue ","Zai ","Kai ","Hong ","Luo ","Xia ","Zhu ","Xuan ","Zheng ","Po ","Yan ","Hui ","Guang ","Zhe ","Hui ","Kao ","[?] ","Fan ","Shao ","Ye ","Hui ","[?] ","Tang ","Jin ","Re ","[?] ","Xi ","Fu ","Jiong ","Che ","Pu ","Jing ","Zhuo ","Ting ","Wan ","Hai ","Peng ","Lang ","Shan ","Hu ","Feng ","Chi ","Rong "]});var Oz=m((w6e,Az)=>{Az.exports=["Hu ","Xi ","Shu ","He ","Xun ","Ku ","Jue ","Xiao ","Xi ","Yan ","Han ","Zhuang ","Jun ","Di ","Xie ","Ji ","Wu ","[?] ","[?] ","Han ","Yan ","Huan ","Men ","Ju ","Chou ","Bei ","Fen ","Lin ","Kun ","Hun ","Tun ","Xi ","Cui ","Wu ","Hong ","Ju ","Fu ","Wo ","Jiao ","Cong ","Feng ","Ping ","Qiong ","Ruo ","Xi ","Qiong ","Xin ","Zhuo ","Yan ","Yan ","Yi ","Jue ","Yu ","Gang ","Ran ","Pi ","Gu ","[?] ","Sheng ","Chang ","Shao ","[?] ","[?] ","[?] ","[?] ","Chen ","He ","Kui ","Zhong ","Duan ","Xia ","Hui ","Feng ","Lian ","Xuan ","Xing ","Huang ","Jiao ","Jian ","Bi ","Ying ","Zhu ","Wei ","Tuan ","Tian ","Xi ","Nuan ","Nuan ","Chan ","Yan ","Jiong ","Jiong ","Yu ","Mei ","Sha ","Wei ","Ye ","Xin ","Qiong ","Rou ","Mei ","Huan ","Xu ","Zhao ","Wei ","Fan ","Qiu ","Sui ","Yang ","Lie ","Zhu ","Jie ","Gao ","Gua ","Bao ","Hu ","Yun ","Xia ","[?] ","[?] ","Bian ","Gou ","Tui ","Tang ","Chao ","Shan ","N ","Bo ","Huang ","Xie ","Xi ","Wu ","Xi ","Yun ","He ","He ","Xi ","Yun ","Xiong ","Nai ","Shan ","Qiong ","Yao ","Xun ","Mi ","Lian ","Ying ","Wen ","Rong ","Oozutsu ","[?] ","Qiang ","Liu ","Xi ","Bi ","Biao ","Zong ","Lu ","Jian ","Shou ","Yi ","Lou ","Feng ","Sui ","Yi ","Tong ","Jue ","Zong ","Yun ","Hu ","Yi ","Zhi ","Ao ","Wei ","Liao ","Han ","Ou ","Re ","Jiong ","Man ","[?] ","Shang ","Cuan ","Zeng ","Jian ","Xi ","Xi ","Xi ","Yi ","Xiao ","Chi ","Huang ","Chan ","Ye ","Qian ","Ran ","Yan ","Xian ","Qiao ","Zun ","Deng ","Dun ","Shen ","Jiao ","Fen ","Si ","Liao ","Yu ","Lin ","Tong ","Shao ","Fen ","Fan ","Yan ","Xun ","Lan ","Mei ","Tang ","Yi ","Jing ","Men ","[?] ","[?] ","Ying ","Yu ","Yi ","Xue ","Lan ","Tai ","Zao ","Can ","Sui ","Xi ","Que ","Cong ","Lian ","Hui ","Zhu ","Xie ","Ling ","Wei ","Yi ","Xie ","Zhao ","Hui ","Tatsu ","Nung ","Lan ","Ru ","Xian ","Kao ","Xun ","Jin ","Chou ","Chou ","Yao "]});var Nz=m((D6e,Mz)=>{Mz.exports=["He ","Lan ","Biao ","Rong ","Li ","Mo ","Bao ","Ruo ","Lu ","La ","Ao ","Xun ","Kuang ","Shuo ","[?] ","Li ","Lu ","Jue ","Liao ","Yan ","Xi ","Xie ","Long ","Ye ","[?] ","Rang ","Yue ","Lan ","Cong ","Jue ","Tong ","Guan ","[?] ","Che ","Mi ","Tang ","Lan ","Zhu ","[?] ","Ling ","Cuan ","Yu ","Zhua ","Tsumekanmuri ","Pa ","Zheng ","Pao ","Cheng ","Yuan ","Ai ","Wei ","[?] ","Jue ","Jue ","Fu ","Ye ","Ba ","Die ","Ye ","Yao ","Zu ","Shuang ","Er ","Qiang ","Chuang ","Ge ","Zang ","Die ","Qiang ","Yong ","Qiang ","Pian ","Ban ","Pan ","Shao ","Jian ","Pai ","Du ","Chuang ","Tou ","Zha ","Bian ","Die ","Bang ","Bo ","Chuang ","You ","[?] ","Du ","Ya ","Cheng ","Niu ","Ushihen ","Pin ","Jiu ","Mou ","Tuo ","Mu ","Lao ","Ren ","Mang ","Fang ","Mao ","Mu ","Gang ","Wu ","Yan ","Ge ","Bei ","Si ","Jian ","Gu ","You ","Ge ","Sheng ","Mu ","Di ","Qian ","Quan ","Quan ","Zi ","Te ","Xi ","Mang ","Keng ","Qian ","Wu ","Gu ","Xi ","Li ","Li ","Pou ","Ji ","Gang ","Zhi ","Ben ","Quan ","Run ","Du ","Ju ","Jia ","Jian ","Feng ","Pian ","Ke ","Ju ","Kao ","Chu ","Xi ","Bei ","Luo ","Jie ","Ma ","San ","Wei ","Li ","Dun ","Tong ","[?] ","Jiang ","Ikenie ","Li ","Du ","Lie ","Pi ","Piao ","Bao ","Xi ","Chou ","Wei ","Kui ","Chou ","Quan ","Fan ","Ba ","Fan ","Qiu ","Ji ","Cai ","Chuo ","An ","Jie ","Zhuang ","Guang ","Ma ","You ","Kang ","Bo ","Hou ","Ya ","Yin ","Huan ","Zhuang ","Yun ","Kuang ","Niu ","Di ","Qing ","Zhong ","Mu ","Bei ","Pi ","Ju ","Ni ","Sheng ","Pao ","Xia ","Tuo ","Hu ","Ling ","Fei ","Pi ","Ni ","Ao ","You ","Gou ","Yue ","Ju ","Dan ","Po ","Gu ","Xian ","Ning ","Huan ","Hen ","Jiao ","He ","Zhao ","Ji ","Xun ","Shan ","Ta ","Rong ","Shou ","Tong ","Lao ","Du ","Xia ","Shi ","Hua ","Zheng ","Yu ","Sun ","Yu ","Bi ","Mang ","Xi ","Juan ","Li ","Xia ","Yin ","Suan ","Lang ","Bei ","Zhi ","Yan "]});var Hz=m((x6e,Bz)=>{Bz.exports=["Sha ","Li ","Han ","Xian ","Jing ","Pai ","Fei ","Yao ","Ba ","Qi ","Ni ","Biao ","Yin ","Lai ","Xi ","Jian ","Qiang ","Kun ","Yan ","Guo ","Zong ","Mi ","Chang ","Yi ","Zhi ","Zheng ","Ya ","Meng ","Cai ","Cu ","She ","Kari ","Cen ","Luo ","Hu ","Zong ","Ji ","Wei ","Feng ","Wo ","Yuan ","Xing ","Zhu ","Mao ","Wei ","Yuan ","Xian ","Tuan ","Ya ","Nao ","Xie ","Jia ","Hou ","Bian ","You ","You ","Mei ","Zha ","Yao ","Sun ","Bo ","Ming ","Hua ","Yuan ","Sou ","Ma ","Yuan ","Dai ","Yu ","Shi ","Hao ","[?] ","Yi ","Zhen ","Chuang ","Hao ","Man ","Jing ","Jiang ","Mu ","Zhang ","Chan ","Ao ","Ao ","Hao ","Cui ","Fen ","Jue ","Bi ","Bi ","Huang ","Pu ","Lin ","Yu ","Tong ","Yao ","Liao ","Shuo ","Xiao ","Swu ","Ton ","Xi ","Ge ","Juan ","Du ","Hui ","Kuai ","Xian ","Xie ","Ta ","Xian ","Xun ","Ning ","Pin ","Huo ","Nou ","Meng ","Lie ","Nao ","Guang ","Shou ","Lu ","Ta ","Xian ","Mi ","Rang ","Huan ","Nao ","Luo ","Xian ","Qi ","Jue ","Xuan ","Miao ","Zi ","Lu ","Lu ","Yu ","Su ","Wang ","Qiu ","Ga ","Ding ","Le ","Ba ","Ji ","Hong ","Di ","Quan ","Gan ","Jiu ","Yu ","Ji ","Yu ","Yang ","Ma ","Gong ","Wu ","Fu ","Wen ","Jie ","Ya ","Fen ","Bian ","Beng ","Yue ","Jue ","Yun ","Jue ","Wan ","Jian ","Mei ","Dan ","Pi ","Wei ","Huan ","Xian ","Qiang ","Ling ","Dai ","Yi ","An ","Ping ","Dian ","Fu ","Xuan ","Xi ","Bo ","Ci ","Gou ","Jia ","Shao ","Po ","Ci ","Ke ","Ran ","Sheng ","Shen ","Yi ","Zu ","Jia ","Min ","Shan ","Liu ","Bi ","Zhen ","Zhen ","Jue ","Fa ","Long ","Jin ","Jiao ","Jian ","Li ","Guang ","Xian ","Zhou ","Gong ","Yan ","Xiu ","Yang ","Xu ","Luo ","Su ","Zhu ","Qin ","Ken ","Xun ","Bao ","Er ","Xiang ","Yao ","Xia ","Heng ","Gui ","Chong ","Xu ","Ban ","Pei ","[?] ","Dang ","Ei ","Hun ","Wen ","E ","Cheng ","Ti ","Wu ","Wu ","Cheng ","Jun ","Mei ","Bei ","Ting ","Xian ","Chuo "]});var Yz=m((C6e,qz)=>{qz.exports=["Han ","Xuan ","Yan ","Qiu ","Quan ","Lang ","Li ","Xiu ","Fu ","Liu ","Ye ","Xi ","Ling ","Li ","Jin ","Lian ","Suo ","Chiisai ","[?] ","Wan ","Dian ","Pin ","Zhan ","Cui ","Min ","Yu ","Ju ","Chen ","Lai ","Wen ","Sheng ","Wei ","Dian ","Chu ","Zhuo ","Pei ","Cheng ","Hu ","Qi ","E ","Kun ","Chang ","Qi ","Beng ","Wan ","Lu ","Cong ","Guan ","Yan ","Diao ","Bei ","Lin ","Qin ","Pi ","Pa ","Que ","Zhuo ","Qin ","Fa ","[?] ","Qiong ","Du ","Jie ","Hun ","Yu ","Mao ","Mei ","Chun ","Xuan ","Ti ","Xing ","Dai ","Rou ","Min ","Zhen ","Wei ","Ruan ","Huan ","Jie ","Chuan ","Jian ","Zhuan ","Yang ","Lian ","Quan ","Xia ","Duan ","Yuan ","Ye ","Nao ","Hu ","Ying ","Yu ","Huang ","Rui ","Se ","Liu ","Shi ","Rong ","Suo ","Yao ","Wen ","Wu ","Jin ","Jin ","Ying ","Ma ","Tao ","Liu ","Tang ","Li ","Lang ","Gui ","Zhen ","Qiang ","Cuo ","Jue ","Zhao ","Yao ","Ai ","Bin ","Tu ","Chang ","Kun ","Zhuan ","Cong ","Jin ","Yi ","Cui ","Cong ","Qi ","Li ","Ying ","Suo ","Qiu ","Xuan ","Ao ","Lian ","Man ","Zhang ","Yin ","[?] ","Ying ","Zhi ","Lu ","Wu ","Deng ","Xiou ","Zeng ","Xun ","Qu ","Dang ","Lin ","Liao ","Qiong ","Su ","Huang ","Gui ","Pu ","Jing ","Fan ","Jin ","Liu ","Ji ","[?] ","Jing ","Ai ","Bi ","Can ","Qu ","Zao ","Dang ","Jiao ","Gun ","Tan ","Hui ","Huan ","Se ","Sui ","Tian ","[?] ","Yu ","Jin ","Lu ","Bin ","Shou ","Wen ","Zui ","Lan ","Xi ","Ji ","Xuan ","Ruan ","Huo ","Gai ","Lei ","Du ","Li ","Zhi ","Rou ","Li ","Zan ","Qiong ","Zhe ","Gui ","Sui ","La ","Long ","Lu ","Li ","Zan ","Lan ","Ying ","Mi ","Xiang ","Xi ","Guan ","Dao ","Zan ","Huan ","Gua ","Bo ","Die ","Bao ","Hu ","Zhi ","Piao ","Ban ","Rang ","Li ","Wa ","Dekaguramu ","Jiang ","Qian ","Fan ","Pen ","Fang ","Dan ","Weng ","Ou ","Deshiguramu ","Miriguramu ","Thon ","Hu ","Ling ","Yi ","Ping ","Ci ","Hekutogura ","Juan ","Chang ","Chi ","Sarake ","Dang ","Meng ","Pou "]});var Zz=m((S6e,Wz)=>{Wz.exports=["Zhui ","Ping ","Bian ","Zhou ","Zhen ","Senchigura ","Ci ","Ying ","Qi ","Xian ","Lou ","Di ","Ou ","Meng ","Zhuan ","Peng ","Lin ","Zeng ","Wu ","Pi ","Dan ","Weng ","Ying ","Yan ","Gan ","Dai ","Shen ","Tian ","Tian ","Han ","Chang ","Sheng ","Qing ","Sheng ","Chan ","Chan ","Rui ","Sheng ","Su ","Sen ","Yong ","Shuai ","Lu ","Fu ","Yong ","Beng ","Feng ","Ning ","Tian ","You ","Jia ","Shen ","Zha ","Dian ","Fu ","Nan ","Dian ","Ping ","Ting ","Hua ","Ting ","Quan ","Zi ","Meng ","Bi ","Qi ","Liu ","Xun ","Liu ","Chang ","Mu ","Yun ","Fan ","Fu ","Geng ","Tian ","Jie ","Jie ","Quan ","Wei ","Fu ","Tian ","Mu ","Tap ","Pan ","Jiang ","Wa ","Da ","Nan ","Liu ","Ben ","Zhen ","Chu ","Mu ","Mu ","Ce ","Cen ","Gai ","Bi ","Da ","Zhi ","Lue ","Qi ","Lue ","Pan ","Kesa ","Fan ","Hua ","Yu ","Yu ","Mu ","Jun ","Yi ","Liu ","Yu ","Die ","Chou ","Hua ","Dang ","Chuo ","Ji ","Wan ","Jiang ","Sheng ","Chang ","Tuan ","Lei ","Ji ","Cha ","Liu ","Tatamu ","Tuan ","Lin ","Jiang ","Jiang ","Chou ","Bo ","Die ","Die ","Pi ","Nie ","Dan ","Shu ","Shu ","Zhi ","Yi ","Chuang ","Nai ","Ding ","Bi ","Jie ","Liao ","Gong ","Ge ","Jiu ","Zhou ","Xia ","Shan ","Xu ","Nue ","Li ","Yang ","Chen ","You ","Ba ","Jie ","Jue ","Zhi ","Xia ","Cui ","Bi ","Yi ","Li ","Zong ","Chuang ","Feng ","Zhu ","Pao ","Pi ","Gan ","Ke ","Ci ","Xie ","Qi ","Dan ","Zhen ","Fa ","Zhi ","Teng ","Ju ","Ji ","Fei ","Qu ","Dian ","Jia ","Xian ","Cha ","Bing ","Ni ","Zheng ","Yong ","Jing ","Quan ","Chong ","Tong ","Yi ","Kai ","Wei ","Hui ","Duo ","Yang ","Chi ","Zhi ","Hen ","Ya ","Mei ","Dou ","Jing ","Xiao ","Tong ","Tu ","Mang ","Pi ","Xiao ","Suan ","Pu ","Li ","Zhi ","Cuo ","Duo ","Wu ","Sha ","Lao ","Shou ","Huan ","Xian ","Yi ","Peng ","Zhang ","Guan ","Tan ","Fei ","Ma ","Lin ","Chi ","Ji ","Dian ","An ","Chi ","Bi ","Bei ","Min ","Gu ","Dui ","E ","Wei "]});var $z=m((T6e,Jz)=>{Jz.exports=["Yu ","Cui ","Ya ","Zhu ","Cu ","Dan ","Shen ","Zhung ","Ji ","Yu ","Hou ","Feng ","La ","Yang ","Shen ","Tu ","Yu ","Gua ","Wen ","Huan ","Ku ","Jia ","Yin ","Yi ","Lu ","Sao ","Jue ","Chi ","Xi ","Guan ","Yi ","Wen ","Ji ","Chuang ","Ban ","Lei ","Liu ","Chai ","Shou ","Nue ","Dian ","Da ","Pie ","Tan ","Zhang ","Biao ","Shen ","Cu ","Luo ","Yi ","Zong ","Chou ","Zhang ","Zhai ","Sou ","Suo ","Que ","Diao ","Lou ","Lu ","Mo ","Jin ","Yin ","Ying ","Huang ","Fu ","Liao ","Long ","Qiao ","Liu ","Lao ","Xian ","Fei ","Dan ","Yin ","He ","Yan ","Ban ","Xian ","Guan ","Guai ","Nong ","Yu ","Wei ","Yi ","Yong ","Pi ","Lei ","Li ","Shu ","Dan ","Lin ","Dian ","Lin ","Lai ","Pie ","Ji ","Chi ","Yang ","Xian ","Jie ","Zheng ","[?] ","Li ","Huo ","Lai ","Shaku ","Dian ","Xian ","Ying ","Yin ","Qu ","Yong ","Tan ","Dian ","Luo ","Luan ","Luan ","Bo ","[?] ","Gui ","Po ","Fa ","Deng ","Fa ","Bai ","Bai ","Qie ","Bi ","Zao ","Zao ","Mao ","De ","Pa ","Jie ","Huang ","Gui ","Ci ","Ling ","Gao ","Mo ","Ji ","Jiao ","Peng ","Gao ","Ai ","E ","Hao ","Han ","Bi ","Wan ","Chou ","Qian ","Xi ","Ai ","Jiong ","Hao ","Huang ","Hao ","Ze ","Cui ","Hao ","Xiao ","Ye ","Po ","Hao ","Jiao ","Ai ","Xing ","Huang ","Li ","Piao ","He ","Jiao ","Pi ","Gan ","Pao ","Zhou ","Jun ","Qiu ","Cun ","Que ","Zha ","Gu ","Jun ","Jun ","Zhou ","Zha ","Gu ","Zhan ","Du ","Min ","Qi ","Ying ","Yu ","Bei ","Zhao ","Zhong ","Pen ","He ","Ying ","He ","Yi ","Bo ","Wan ","He ","Ang ","Zhan ","Yan ","Jian ","He ","Yu ","Kui ","Fan ","Gai ","Dao ","Pan ","Fu ","Qiu ","Sheng ","Dao ","Lu ","Zhan ","Meng ","Li ","Jin ","Xu ","Jian ","Pan ","Guan ","An ","Lu ","Shu ","Zhou ","Dang ","An ","Gu ","Li ","Mu ","Cheng ","Gan ","Xu ","Mang ","Mang ","Zhi ","Qi ","Ruan ","Tian ","Xiang ","Dun ","Xin ","Xi ","Pan ","Feng ","Dun ","Min "]});var Uz=m((k6e,Xz)=>{Xz.exports=["Ming ","Sheng ","Shi ","Yun ","Mian ","Pan ","Fang ","Miao ","Dan ","Mei ","Mao ","Kan ","Xian ","Ou ","Shi ","Yang ","Zheng ","Yao ","Shen ","Huo ","Da ","Zhen ","Kuang ","Ju ","Shen ","Chi ","Sheng ","Mei ","Mo ","Zhu ","Zhen ","Zhen ","Mian ","Di ","Yuan ","Die ","Yi ","Zi ","Zi ","Chao ","Zha ","Xuan ","Bing ","Mi ","Long ","Sui ","Dong ","Mi ","Die ","Yi ","Er ","Ming ","Xuan ","Chi ","Kuang ","Juan ","Mou ","Zhen ","Tiao ","Yang ","Yan ","Mo ","Zhong ","Mai ","Zhao ","Zheng ","Mei ","Jun ","Shao ","Han ","Huan ","Di ","Cheng ","Cuo ","Juan ","E ","Wan ","Xian ","Xi ","Kun ","Lai ","Jian ","Shan ","Tian ","Hun ","Wan ","Ling ","Shi ","Qiong ","Lie ","Yai ","Jing ","Zheng ","Li ","Lai ","Sui ","Juan ","Shui ","Sui ","Du ","Bi ","Bi ","Mu ","Hun ","Ni ","Lu ","Yi ","Jie ","Cai ","Zhou ","Yu ","Hun ","Ma ","Xia ","Xing ","Xi ","Gun ","Cai ","Chun ","Jian ","Mei ","Du ","Hou ","Xuan ","Ti ","Kui ","Gao ","Rui ","Mou ","Xu ","Fa ","Wen ","Miao ","Chou ","Kui ","Mi ","Weng ","Kou ","Dang ","Chen ","Ke ","Sou ","Xia ","Qiong ","Mao ","Ming ","Man ","Shui ","Ze ","Zhang ","Yi ","Diao ","Ou ","Mo ","Shun ","Cong ","Lou ","Chi ","Man ","Piao ","Cheng ","Ji ","Meng ","[?] ","Run ","Pie ","Xi ","Qiao ","Pu ","Zhu ","Deng ","Shen ","Shun ","Liao ","Che ","Xian ","Kan ","Ye ","Xu ","Tong ","Mou ","Lin ","Kui ","Xian ","Ye ","Ai ","Hui ","Zhan ","Jian ","Gu ","Zhao ","Qu ","Wei ","Chou ","Sao ","Ning ","Xun ","Yao ","Huo ","Meng ","Mian ","Bin ","Mian ","Li ","Kuang ","Jue ","Xuan ","Mian ","Huo ","Lu ","Meng ","Long ","Guan ","Man ","Xi ","Chu ","Tang ","Kan ","Zhu ","Mao ","Jin ","Lin ","Yu ","Shuo ","Ce ","Jue ","Shi ","Yi ","Shen ","Zhi ","Hou ","Shen ","Ying ","Ju ","Zhou ","Jiao ","Cuo ","Duan ","Ai ","Jiao ","Zeng ","Huo ","Bai ","Shi ","Ding ","Qi ","Ji ","Zi ","Gan ","Wu ","Tuo ","Ku ","Qiang ","Xi ","Fan ","Kuang "]});var Qz=m((E6e,Gz)=>{Gz.exports=["Dang ","Ma ","Sha ","Dan ","Jue ","Li ","Fu ","Min ","Nuo ","Huo ","Kang ","Zhi ","Qi ","Kan ","Jie ","Fen ","E ","Ya ","Pi ","Zhe ","Yan ","Sui ","Zhuan ","Che ","Dun ","Pan ","Yan ","[?] ","Feng ","Fa ","Mo ","Zha ","Qu ","Yu ","Luo ","Tuo ","Tuo ","Di ","Zhai ","Zhen ","Ai ","Fei ","Mu ","Zhu ","Li ","Bian ","Nu ","Ping ","Peng ","Ling ","Pao ","Le ","Po ","Bo ","Po ","Shen ","Za ","Nuo ","Li ","Long ","Tong ","[?] ","Li ","Aragane ","Chu ","Keng ","Quan ","Zhu ","Kuang ","Huo ","E ","Nao ","Jia ","Lu ","Wei ","Ai ","Luo ","Ken ","Xing ","Yan ","Tong ","Peng ","Xi ","[?] ","Hong ","Shuo ","Xia ","Qiao ","[?] ","Wei ","Qiao ","[?] ","Keng ","Xiao ","Que ","Chan ","Lang ","Hong ","Yu ","Xiao ","Xia ","Mang ","Long ","Iong ","Che ","Che ","E ","Liu ","Ying ","Mang ","Que ","Yan ","Sha ","Kun ","Yu ","[?] ","Kaki ","Lu ","Chen ","Jian ","Nue ","Song ","Zhuo ","Keng ","Peng ","Yan ","Zhui ","Kong ","Ceng ","Qi ","Zong ","Qing ","Lin ","Jun ","Bo ","Ding ","Min ","Diao ","Jian ","He ","Lu ","Ai ","Sui ","Que ","Ling ","Bei ","Yin ","Dui ","Wu ","Qi ","Lun ","Wan ","Dian ","Gang ","Pei ","Qi ","Chen ","Ruan ","Yan ","Die ","Ding ","Du ","Tuo ","Jie ","Ying ","Bian ","Ke ","Bi ","Wei ","Shuo ","Zhen ","Duan ","Xia ","Dang ","Ti ","Nao ","Peng ","Jian ","Di ","Tan ","Cha ","Seki ","Qi ","[?] ","Feng ","Xuan ","Que ","Que ","Ma ","Gong ","Nian ","Su ","E ","Ci ","Liu ","Si ","Tang ","Bang ","Hua ","Pi ","Wei ","Sang ","Lei ","Cuo ","Zhen ","Xia ","Qi ","Lian ","Pan ","Wei ","Yun ","Dui ","Zhe ","Ke ","La ","[?] ","Qing ","Gun ","Zhuan ","Chan ","Qi ","Ao ","Peng ","Lu ","Lu ","Kan ","Qiang ","Chen ","Yin ","Lei ","Biao ","Qi ","Mo ","Qi ","Cui ","Zong ","Qing ","Chuo ","[?] ","Ji ","Shan ","Lao ","Qu ","Zeng ","Deng ","Jian ","Xi ","Lin ","Ding ","Dian ","Huang ","Pan ","Za ","Qiao ","Di ","Li "]});var zz=m((P6e,Kz)=>{Kz.exports=["Tani ","Jiao ","[?] ","Zhang ","Qiao ","Dun ","Xian ","Yu ","Zhui ","He ","Huo ","Zhai ","Lei ","Ke ","Chu ","Ji ","Que ","Dang ","Yi ","Jiang ","Pi ","Pi ","Yu ","Pin ","Qi ","Ai ","Kai ","Jian ","Yu ","Ruan ","Meng ","Pao ","Ci ","[?] ","[?] ","Mie ","Ca ","Xian ","Kuang ","Lei ","Lei ","Zhi ","Li ","Li ","Fan ","Que ","Pao ","Ying ","Li ","Long ","Long ","Mo ","Bo ","Shuang ","Guan ","Lan ","Zan ","Yan ","Shi ","Shi ","Li ","Reng ","She ","Yue ","Si ","Qi ","Ta ","Ma ","Xie ","Xian ","Xian ","Zhi ","Qi ","Zhi ","Beng ","Dui ","Zhong ","[?] ","Yi ","Shi ","You ","Zhi ","Tiao ","Fu ","Fu ","Mi ","Zu ","Zhi ","Suan ","Mei ","Zuo ","Qu ","Hu ","Zhu ","Shen ","Sui ","Ci ","Chai ","Mi ","Lu ","Yu ","Xiang ","Wu ","Tiao ","Piao ","Zhu ","Gui ","Xia ","Zhi ","Ji ","Gao ","Zhen ","Gao ","Shui ","Jin ","Chen ","Gai ","Kun ","Di ","Dao ","Huo ","Tao ","Qi ","Gu ","Guan ","Zui ","Ling ","Lu ","Bing ","Jin ","Dao ","Zhi ","Lu ","Shan ","Bei ","Zhe ","Hui ","You ","Xi ","Yin ","Zi ","Huo ","Zhen ","Fu ","Yuan ","Wu ","Xian ","Yang ","Ti ","Yi ","Mei ","Si ","Di ","[?] ","Zhuo ","Zhen ","Yong ","Ji ","Gao ","Tang ","Si ","Ma ","Ta ","[?] ","Xuan ","Qi ","Yu ","Xi ","Ji ","Si ","Chan ","Tan ","Kuai ","Sui ","Li ","Nong ","Ni ","Dao ","Li ","Rang ","Yue ","Ti ","Zan ","Lei ","Rou ","Yu ","Yu ","Chi ","Xie ","Qin ","He ","Tu ","Xiu ","Si ","Ren ","Tu ","Zi ","Cha ","Gan ","Yi ","Xian ","Bing ","Nian ","Qiu ","Qiu ","Chong ","Fen ","Hao ","Yun ","Ke ","Miao ","Zhi ","Geng ","Bi ","Zhi ","Yu ","Mi ","Ku ","Ban ","Pi ","Ni ","Li ","You ","Zu ","Pi ","Ba ","Ling ","Mo ","Cheng ","Nian ","Qin ","Yang ","Zuo ","Zhi ","Zhi ","Shu ","Ju ","Zi ","Huo ","Ji ","Cheng ","Tong ","Zhi ","Huo ","He ","Yin ","Zi ","Zhi ","Jie ","Ren ","Du ","Yi ","Zhu ","Hui ","Nong ","Fu "]});var e5=m((_6e,Vz)=>{Vz.exports=["Xi ","Kao ","Lang ","Fu ","Ze ","Shui ","Lu ","Kun ","Gan ","Geng ","Ti ","Cheng ","Tu ","Shao ","Shui ","Ya ","Lun ","Lu ","Gu ","Zuo ","Ren ","Zhun ","Bang ","Bai ","Ji ","Zhi ","Zhi ","Kun ","Leng ","Peng ","Ke ","Bing ","Chou ","Zu ","Yu ","Su ","Lue ","[?] ","Yi ","Xi ","Bian ","Ji ","Fu ","Bi ","Nuo ","Jie ","Zhong ","Zong ","Xu ","Cheng ","Dao ","Wen ","Lian ","Zi ","Yu ","Ji ","Xu ","Zhen ","Zhi ","Dao ","Jia ","Ji ","Gao ","Gao ","Gu ","Rong ","Sui ","You ","Ji ","Kang ","Mu ","Shan ","Men ","Zhi ","Ji ","Lu ","Su ","Ji ","Ying ","Wen ","Qiu ","Se ","[?] ","Yi ","Huang ","Qie ","Ji ","Sui ","Xiao ","Pu ","Jiao ","Zhuo ","Tong ","Sai ","Lu ","Sui ","Nong ","Se ","Hui ","Rang ","Nuo ","Yu ","Bin ","Ji ","Tui ","Wen ","Cheng ","Huo ","Gong ","Lu ","Biao ","[?] ","Rang ","Zhuo ","Li ","Zan ","Xue ","Wa ","Jiu ","Qiong ","Xi ","Qiong ","Kong ","Yu ","Sen ","Jing ","Yao ","Chuan ","Zhun ","Tu ","Lao ","Qie ","Zhai ","Yao ","Bian ","Bao ","Yao ","Bing ","Wa ","Zhu ","Jiao ","Qiao ","Diao ","Wu ","Gui ","Yao ","Zhi ","Chuang ","Yao ","Tiao ","Jiao ","Chuang ","Jiong ","Xiao ","Cheng ","Kou ","Cuan ","Wo ","Dan ","Ku ","Ke ","Zhui ","Xu ","Su ","Guan ","Kui ","Dou ","[?] ","Yin ","Wo ","Wa ","Ya ","Yu ","Ju ","Qiong ","Yao ","Yao ","Tiao ","Chao ","Yu ","Tian ","Diao ","Ju ","Liao ","Xi ","Wu ","Kui ","Chuang ","Zhao ","[?] ","Kuan ","Long ","Cheng ","Cui ","Piao ","Zao ","Cuan ","Qiao ","Qiong ","Dou ","Zao ","Long ","Qie ","Li ","Chu ","Shi ","Fou ","Qian ","Chu ","Hong ","Qi ","Qian ","Gong ","Shi ","Shu ","Miao ","Ju ","Zhan ","Zhu ","Ling ","Long ","Bing ","Jing ","Jing ","Zhang ","Yi ","Si ","Jun ","Hong ","Tong ","Song ","Jing ","Diao ","Yi ","Shu ","Jing ","Qu ","Jie ","Ping ","Duan ","Shao ","Zhuan ","Ceng ","Deng ","Cui ","Huai ","Jing ","Kan ","Jing ","Zhu ","Zhu ","Le ","Peng ","Yu ","Chi ","Gan "]});var i5=m((R6e,t5)=>{t5.exports=["Mang ","Zhu ","Utsubo ","Du ","Ji ","Xiao ","Ba ","Suan ","Ji ","Zhen ","Zhao ","Sun ","Ya ","Zhui ","Yuan ","Hu ","Gang ","Xiao ","Cen ","Pi ","Bi ","Jian ","Yi ","Dong ","Shan ","Sheng ","Xia ","Di ","Zhu ","Na ","Chi ","Gu ","Li ","Qie ","Min ","Bao ","Tiao ","Si ","Fu ","Ce ","Ben ","Pei ","Da ","Zi ","Di ","Ling ","Ze ","Nu ","Fu ","Gou ","Fan ","Jia ","Ge ","Fan ","Shi ","Mao ","Po ","Sey ","Jian ","Qiong ","Long ","Souke ","Bian ","Luo ","Gui ","Qu ","Chi ","Yin ","Yao ","Xian ","Bi ","Qiong ","Gua ","Deng ","Jiao ","Jin ","Quan ","Sun ","Ru ","Fa ","Kuang ","Zhu ","Tong ","Ji ","Da ","Xing ","Ce ","Zhong ","Kou ","Lai ","Bi ","Shai ","Dang ","Zheng ","Ce ","Fu ","Yun ","Tu ","Pa ","Li ","Lang ","Ju ","Guan ","Jian ","Han ","Tong ","Xia ","Zhi ","Cheng ","Suan ","Shi ","Zhu ","Zuo ","Xiao ","Shao ","Ting ","Ce ","Yan ","Gao ","Kuai ","Gan ","Chou ","Kago ","Gang ","Yun ","O ","Qian ","Xiao ","Jian ","Pu ","Lai ","Zou ","Bi ","Bi ","Bi ","Ge ","Chi ","Guai ","Yu ","Jian ","Zhao ","Gu ","Chi ","Zheng ","Jing ","Sha ","Zhou ","Lu ","Bo ","Ji ","Lin ","Suan ","Jun ","Fu ","Zha ","Gu ","Kong ","Qian ","Quan ","Jun ","Chui ","Guan ","Yuan ","Ce ","Ju ","Bo ","Ze ","Qie ","Tuo ","Luo ","Dan ","Xiao ","Ruo ","Jian ","Xuan ","Bian ","Sun ","Xiang ","Xian ","Ping ","Zhen ","Sheng ","Hu ","Shi ","Zhu ","Yue ","Chun ","Lu ","Wu ","Dong ","Xiao ","Ji ","Jie ","Huang ","Xing ","Mei ","Fan ","Chui ","Zhuan ","Pian ","Feng ","Zhu ","Hong ","Qie ","Hou ","Qiu ","Miao ","Qian ","[?] ","Kui ","Sik ","Lou ","Yun ","He ","Tang ","Yue ","Chou ","Gao ","Fei ","Ruo ","Zheng ","Gou ","Nie ","Qian ","Xiao ","Cuan ","Gong ","Pang ","Du ","Li ","Bi ","Zhuo ","Chu ","Shai ","Chi ","Zhu ","Qiang ","Long ","Lan ","Jian ","Bu ","Li ","Hui ","Bi ","Di ","Cong ","Yan ","Peng ","Sen ","Zhuan ","Pai ","Piao ","Dou ","Yu ","Mie ","Zhuan "]});var r5=m((L6e,n5)=>{n5.exports=["Ze ","Xi ","Guo ","Yi ","Hu ","Chan ","Kou ","Cu ","Ping ","Chou ","Ji ","Gui ","Su ","Lou ","Zha ","Lu ","Nian ","Suo ","Cuan ","Sasara ","Suo ","Le ","Duan ","Yana ","Xiao ","Bo ","Mi ","Si ","Dang ","Liao ","Dan ","Dian ","Fu ","Jian ","Min ","Kui ","Dai ","Qiao ","Deng ","Huang ","Sun ","Lao ","Zan ","Xiao ","Du ","Shi ","Zan ","[?] ","Pai ","Hata ","Pai ","Gan ","Ju ","Du ","Lu ","Yan ","Bo ","Dang ","Sai ","Ke ","Long ","Qian ","Lian ","Bo ","Zhou ","Lai ","[?] ","Lan ","Kui ","Yu ","Yue ","Hao ","Zhen ","Tai ","Ti ","Mi ","Chou ","Ji ","[?] ","Hata ","Teng ","Zhuan ","Zhou ","Fan ","Sou ","Zhou ","Kuji ","Zhuo ","Teng ","Lu ","Lu ","Jian ","Tuo ","Ying ","Yu ","Lai ","Long ","Shinshi ","Lian ","Lan ","Qian ","Yue ","Zhong ","Qu ","Lian ","Bian ","Duan ","Zuan ","Li ","Si ","Luo ","Ying ","Yue ","Zhuo ","Xu ","Mi ","Di ","Fan ","Shen ","Zhe ","Shen ","Nu ","Xie ","Lei ","Xian ","Zi ","Ni ","Cun ","[?] ","Qian ","Kume ","Bi ","Ban ","Wu ","Sha ","Kang ","Rou ","Fen ","Bi ","Cui ","[?] ","Li ","Chi ","Nukamiso ","Ro ","Ba ","Li ","Gan ","Ju ","Po ","Mo ","Cu ","Nian ","Zhou ","Li ","Su ","Tiao ","Li ","Qi ","Su ","Hong ","Tong ","Zi ","Ce ","Yue ","Zhou ","Lin ","Zhuang ","Bai ","[?] ","Fen ","Ji ","[?] ","Sukumo ","Liang ","Xian ","Fu ","Liang ","Can ","Geng ","Li ","Yue ","Lu ","Ju ","Qi ","Cui ","Bai ","Zhang ","Lin ","Zong ","Jing ","Guo ","Kouji ","San ","San ","Tang ","Bian ","Rou ","Mian ","Hou ","Xu ","Zong ","Hu ","Jian ","Zan ","Ci ","Li ","Xie ","Fu ","Ni ","Bei ","Gu ","Xiu ","Gao ","Tang ","Qiu ","Sukumo ","Cao ","Zhuang ","Tang ","Mi ","San ","Fen ","Zao ","Kang ","Jiang ","Mo ","San ","San ","Nuo ","Xi ","Liang ","Jiang ","Kuai ","Bo ","Huan ","[?] ","Zong ","Xian ","Nuo ","Tuan ","Nie ","Li ","Zuo ","Di ","Nie ","Tiao ","Lan ","Mi ","Jiao ","Jiu ","Xi ","Gong ","Zheng ","Jiu ","You "]});var s5=m((F6e,o5)=>{o5.exports=["Ji ","Cha ","Zhou ","Xun ","Yue ","Hong ","Yu ","He ","Wan ","Ren ","Wen ","Wen ","Qiu ","Na ","Zi ","Tou ","Niu ","Fou ","Jie ","Shu ","Chun ","Pi ","Yin ","Sha ","Hong ","Zhi ","Ji ","Fen ","Yun ","Ren ","Dan ","Jin ","Su ","Fang ","Suo ","Cui ","Jiu ","Zha ","Kinu ","Jin ","Fu ","Zhi ","Ci ","Zi ","Chou ","Hong ","Zha ","Lei ","Xi ","Fu ","Xie ","Shen ","Bei ","Zhu ","Qu ","Ling ","Zhu ","Shao ","Gan ","Yang ","Fu ","Tuo ","Zhen ","Dai ","Zhuo ","Shi ","Zhong ","Xian ","Zu ","Jiong ","Ban ","Ju ","Mo ","Shu ","Zui ","Wata ","Jing ","Ren ","Heng ","Xie ","Jie ","Zhu ","Chou ","Gua ","Bai ","Jue ","Kuang ","Hu ","Ci ","Geng ","Geng ","Tao ","Xie ","Ku ","Jiao ","Quan ","Gai ","Luo ","Xuan ","Bing ","Xian ","Fu ","Gei ","Tong ","Rong ","Tiao ","Yin ","Lei ","Xie ","Quan ","Xu ","Lun ","Die ","Tong ","Si ","Jiang ","Xiang ","Hui ","Jue ","Zhi ","Jian ","Juan ","Chi ","Mian ","Zhen ","Lu ","Cheng ","Qiu ","Shu ","Bang ","Tong ","Xiao ","Wan ","Qin ","Geng ","Xiu ","Ti ","Xiu ","Xie ","Hong ","Xi ","Fu ","Ting ","Sui ","Dui ","Kun ","Fu ","Jing ","Hu ","Zhi ","Yan ","Jiong ","Feng ","Ji ","Sok ","Kase ","Zong ","Lin ","Duo ","Li ","Lu ","Liang ","Chou ","Quan ","Shao ","Qi ","Qi ","Zhun ","Qi ","Wan ","Qian ","Xian ","Shou ","Wei ","Qi ","Tao ","Wan ","Gang ","Wang ","Beng ","Zhui ","Cai ","Guo ","Cui ","Lun ","Liu ","Qi ","Zhan ","Bei ","Chuo ","Ling ","Mian ","Qi ","Qie ","Tan ","Zong ","Gun ","Zou ","Yi ","Zi ","Xing ","Liang ","Jin ","Fei ","Rui ","Min ","Yu ","Zong ","Fan ","Lu ","Xu ","Yingl ","Zhang ","Kasuri ","Xu ","Xiang ","Jian ","Ke ","Xian ","Ruan ","Mian ","Qi ","Duan ","Zhong ","Di ","Min ","Miao ","Yuan ","Xie ","Bao ","Si ","Qiu ","Bian ","Huan ","Geng ","Cong ","Mian ","Wei ","Fu ","Wei ","Yu ","Gou ","Miao ","Xie ","Lian ","Zong ","Bian ","Yun ","Yin ","Ti ","Gua ","Zhi ","Yun ","Cheng ","Chan ","Dai "]});var l5=m((I6e,a5)=>{a5.exports=["Xia ","Yuan ","Zong ","Xu ","Nawa ","Odoshi ","Geng ","Sen ","Ying ","Jin ","Yi ","Zhui ","Ni ","Bang ","Gu ","Pan ","Zhou ","Jian ","Cuo ","Quan ","Shuang ","Yun ","Xia ","Shuai ","Xi ","Rong ","Tao ","Fu ","Yun ","Zhen ","Gao ","Ru ","Hu ","Zai ","Teng ","Xian ","Su ","Zhen ","Zong ","Tao ","Horo ","Cai ","Bi ","Feng ","Cu ","Li ","Suo ","Yin ","Xi ","Zong ","Lei ","Zhuan ","Qian ","Man ","Zhi ","Lu ","Mo ","Piao ","Lian ","Mi ","Xuan ","Zong ","Ji ","Shan ","Sui ","Fan ","Shuai ","Beng ","Yi ","Sao ","Mou ","Zhou ","Qiang ","Hun ","Sem ","Xi ","Jung ","Xiu ","Ran ","Xuan ","Hui ","Qiao ","Zeng ","Zuo ","Zhi ","Shan ","San ","Lin ","Yu ","Fan ","Liao ","Chuo ","Zun ","Jian ","Rao ","Chan ","Rui ","Xiu ","Hui ","Hua ","Zuan ","Xi ","Qiang ","Un ","Da ","Sheng ","Hui ","Xi ","Se ","Jian ","Jiang ","Huan ","Zao ","Cong ","Jie ","Jiao ","Bo ","Chan ","Yi ","Nao ","Sui ","Yi ","Shai ","Xu ","Ji ","Bin ","Qian ","Lan ","Pu ","Xun ","Zuan ","Qi ","Peng ","Li ","Mo ","Lei ","Xie ","Zuan ","Kuang ","You ","Xu ","Lei ","Xian ","Chan ","Kou ","Lu ","Chan ","Ying ","Cai ","Xiang ","Xian ","Zui ","Zuan ","Luo ","Xi ","Dao ","Lan ","Lei ","Lian ","Si ","Jiu ","Yu ","Hong ","Zhou ","Xian ","He ","Yue ","Ji ","Wan ","Kuang ","Ji ","Ren ","Wei ","Yun ","Hong ","Chun ","Pi ","Sha ","Gang ","Na ","Ren ","Zong ","Lun ","Fen ","Zhi ","Wen ","Fang ","Zhu ","Yin ","Niu ","Shu ","Xian ","Gan ","Xie ","Fu ","Lian ","Zu ","Shen ","Xi ","Zhi ","Zhong ","Zhou ","Ban ","Fu ","Zhuo ","Shao ","Yi ","Jing ","Dai ","Bang ","Rong ","Jie ","Ku ","Rao ","Die ","Heng ","Hui ","Gei ","Xuan ","Jiang ","Luo ","Jue ","Jiao ","Tong ","Geng ","Xiao ","Juan ","Xiu ","Xi ","Sui ","Tao ","Ji ","Ti ","Ji ","Xu ","Ling ","[?] ","Xu ","Qi ","Fei ","Chuo ","Zhang ","Gun ","Sheng ","Wei ","Mian ","Shou ","Beng ","Chou ","Tao ","Liu ","Quan ","Zong ","Zhan ","Wan ","Lu "]});var c5=m((j6e,u5)=>{u5.exports=["Zhui ","Zi ","Ke ","Xiang ","Jian ","Mian ","Lan ","Ti ","Miao ","Qi ","Yun ","Hui ","Si ","Duo ","Duan ","Bian ","Xian ","Gou ","Zhui ","Huan ","Di ","Lu ","Bian ","Min ","Yuan ","Jin ","Fu ","Ru ","Zhen ","Feng ","Shuai ","Gao ","Chan ","Li ","Yi ","Jian ","Bin ","Piao ","Man ","Lei ","Ying ","Suo ","Mou ","Sao ","Xie ","Liao ","Shan ","Zeng ","Jiang ","Qian ","Zao ","Huan ","Jiao ","Zuan ","Fou ","Xie ","Gang ","Fou ","Que ","Fou ","Kaakeru ","Bo ","Ping ","Hou ","[?] ","Gang ","Ying ","Ying ","Qing ","Xia ","Guan ","Zun ","Tan ","Chang ","Qi ","Weng ","Ying ","Lei ","Tan ","Lu ","Guan ","Wang ","Wang ","Gang ","Wang ","Han ","[?] ","Luo ","Fu ","Mi ","Fa ","Gu ","Zhu ","Ju ","Mao ","Gu ","Min ","Gang ","Ba ","Gua ","Ti ","Juan ","Fu ","Lin ","Yan ","Zhao ","Zui ","Gua ","Zhuo ","Yu ","Zhi ","An ","Fa ","Nan ","Shu ","Si ","Pi ","Ma ","Liu ","Ba ","Fa ","Li ","Chao ","Wei ","Bi ","Ji ","Zeng ","Tong ","Liu ","Ji ","Juan ","Mi ","Zhao ","Luo ","Pi ","Ji ","Ji ","Luan ","Yang ","Mie ","Qiang ","Ta ","Mei ","Yang ","You ","You ","Fen ","Ba ","Gao ","Yang ","Gu ","Qiang ","Zang ","Gao ","Ling ","Yi ","Zhu ","Di ","Xiu ","Qian ","Yi ","Xian ","Rong ","Qun ","Qun ","Qian ","Huan ","Zui ","Xian ","Yi ","Yashinau ","Qiang ","Xian ","Yu ","Geng ","Jie ","Tang ","Yuan ","Xi ","Fan ","Shan ","Fen ","Shan ","Lian ","Lei ","Geng ","Nou ","Qiang ","Chan ","Yu ","Gong ","Yi ","Chong ","Weng ","Fen ","Hong ","Chi ","Chi ","Cui ","Fu ","Xia ","Pen ","Yi ","La ","Yi ","Pi ","Ling ","Liu ","Zhi ","Qu ","Xi ","Xie ","Xiang ","Xi ","Xi ","Qi ","Qiao ","Hui ","Hui ","Xiao ","Se ","Hong ","Jiang ","Di ","Cui ","Fei ","Tao ","Sha ","Chi ","Zhu ","Jian ","Xuan ","Shi ","Pian ","Zong ","Wan ","Hui ","Hou ","He ","He ","Han ","Ao ","Piao ","Yi ","Lian ","Qu ","[?] ","Lin ","Pen ","Qiao ","Ao ","Fan ","Yi ","Hui ","Xuan ","Dao "]});var d5=m((A6e,h5)=>{h5.exports=["Yao ","Lao ","[?] ","Kao ","Mao ","Zhe ","Qi ","Gou ","Gou ","Gou ","Die ","Die ","Er ","Shua ","Ruan ","Er ","Nai ","Zhuan ","Lei ","Ting ","Zi ","Geng ","Chao ","Hao ","Yun ","Pa ","Pi ","Chi ","Si ","Chu ","Jia ","Ju ","He ","Chu ","Lao ","Lun ","Ji ","Tang ","Ou ","Lou ","Nou ","Gou ","Pang ","Ze ","Lou ","Ji ","Lao ","Huo ","You ","Mo ","Huai ","Er ","Zhe ","Ting ","Ye ","Da ","Song ","Qin ","Yun ","Chi ","Dan ","Dan ","Hong ","Geng ","Zhi ","[?] ","Nie ","Dan ","Zhen ","Che ","Ling ","Zheng ","You ","Wa ","Liao ","Long ","Zhi ","Ning ","Tiao ","Er ","Ya ","Die ","Gua ","[?] ","Lian ","Hao ","Sheng ","Lie ","Pin ","Jing ","Ju ","Bi ","Di ","Guo ","Wen ","Xu ","Ping ","Cong ","Shikato ","[?] ","Ting ","Yu ","Cong ","Kui ","Tsuraneru ","Kui ","Cong ","Lian ","Weng ","Kui ","Lian ","Lian ","Cong ","Ao ","Sheng ","Song ","Ting ","Kui ","Nie ","Zhi ","Dan ","Ning ","Qie ","Ji ","Ting ","Ting ","Long ","Yu ","Yu ","Zhao ","Si ","Su ","Yi ","Su ","Si ","Zhao ","Zhao ","Rou ","Yi ","Le ","Ji ","Qiu ","Ken ","Cao ","Ge ","Di ","Huan ","Huang ","Yi ","Ren ","Xiao ","Ru ","Zhou ","Yuan ","Du ","Gang ","Rong ","Gan ","Cha ","Wo ","Chang ","Gu ","Zhi ","Han ","Fu ","Fei ","Fen ","Pei ","Pang ","Jian ","Fang ","Zhun ","You ","Na ","Hang ","Ken ","Ran ","Gong ","Yu ","Wen ","Yao ","Jin ","Pi ","Qian ","Xi ","Xi ","Fei ","Ken ","Jing ","Tai ","Shen ","Zhong ","Zhang ","Xie ","Shen ","Wei ","Zhou ","Die ","Dan ","Fei ","Ba ","Bo ","Qu ","Tian ","Bei ","Gua ","Tai ","Zi ","Ku ","Zhi ","Ni ","Ping ","Zi ","Fu ","Pang ","Zhen ","Xian ","Zuo ","Pei ","Jia ","Sheng ","Zhi ","Bao ","Mu ","Qu ","Hu ","Ke ","Yi ","Yin ","Xu ","Yang ","Long ","Dong ","Ka ","Lu ","Jing ","Nu ","Yan ","Pang ","Kua ","Yi ","Guang ","Gai ","Ge ","Dong ","Zhi ","Xiao ","Xiong ","Xiong ","Er ","E ","Xing ","Pian ","Neng ","Zi ","Gui "]});var f5=m((O6e,g5)=>{g5.exports=["Cheng ","Tiao ","Zhi ","Cui ","Mei ","Xie ","Cui ","Xie ","Mo ","Mai ","Ji ","Obiyaakasu ","[?] ","Kuai ","Sa ","Zang ","Qi ","Nao ","Mi ","Nong ","Luan ","Wan ","Bo ","Wen ","Guan ","Qiu ","Jiao ","Jing ","Rou ","Heng ","Cuo ","Lie ","Shan ","Ting ","Mei ","Chun ","Shen ","Xie ","De ","Zui ","Cu ","Xiu ","Xin ","Tuo ","Pao ","Cheng ","Nei ","Fu ","Dou ","Tuo ","Niao ","Noy ","Pi ","Gu ","Gua ","Li ","Lian ","Zhang ","Cui ","Jie ","Liang ","Zhou ","Pi ","Biao ","Lun ","Pian ","Guo ","Kui ","Chui ","Dan ","Tian ","Nei ","Jing ","Jie ","La ","Yi ","An ","Ren ","Shen ","Chuo ","Fu ","Fu ","Ju ","Fei ","Qiang ","Wan ","Dong ","Pi ","Guo ","Zong ","Ding ","Wu ","Mei ","Ruan ","Zhuan ","Zhi ","Cou ","Gua ","Ou ","Di ","An ","Xing ","Nao ","Yu ","Chuan ","Nan ","Yun ","Zhong ","Rou ","E ","Sai ","Tu ","Yao ","Jian ","Wei ","Jiao ","Yu ","Jia ","Duan ","Bi ","Chang ","Fu ","Xian ","Ni ","Mian ","Wa ","Teng ","Tui ","Bang ","Qian ","Lu ","Wa ","Sou ","Tang ","Su ","Zhui ","Ge ","Yi ","Bo ","Liao ","Ji ","Pi ","Xie ","Gao ","Lu ","Bin ","Ou ","Chang ","Lu ","Guo ","Pang ","Chuai ","Piao ","Jiang ","Fu ","Tang ","Mo ","Xi ","Zhuan ","Lu ","Jiao ","Ying ","Lu ","Zhi ","Tara ","Chun ","Lian ","Tong ","Peng ","Ni ","Zha ","Liao ","Cui ","Gui ","Xiao ","Teng ","Fan ","Zhi ","Jiao ","Shan ","Wu ","Cui ","Run ","Xiang ","Sui ","Fen ","Ying ","Tan ","Zhua ","Dan ","Kuai ","Nong ","Tun ","Lian ","Bi ","Yong ","Jue ","Chu ","Yi ","Juan ","La ","Lian ","Sao ","Tun ","Gu ","Qi ","Cui ","Bin ","Xun ","Ru ","Huo ","Zang ","Xian ","Biao ","Xing ","Kuan ","La ","Yan ","Lu ","Huo ","Zang ","Luo ","Qu ","Zang ","Luan ","Ni ","Zang ","Chen ","Qian ","Wo ","Guang ","Zang ","Lin ","Guang ","Zi ","Jiao ","Nie ","Chou ","Ji ","Gao ","Chou ","Mian ","Nie ","Zhi ","Zhi ","Ge ","Jian ","Die ","Zhi ","Xiu ","Tai ","Zhen ","Jiu ","Xian ","Yu ","Cha "]});var m5=m((M6e,p5)=>{p5.exports=["Yao ","Yu ","Chong ","Xi ","Xi ","Jiu ","Yu ","Yu ","Xing ","Ju ","Jiu ","Xin ","She ","She ","Yadoru ","Jiu ","Shi ","Tan ","Shu ","Shi ","Tian ","Dan ","Pu ","Pu ","Guan ","Hua ","Tan ","Chuan ","Shun ","Xia ","Wu ","Zhou ","Dao ","Gang ","Shan ","Yi ","[?] ","Pa ","Tai ","Fan ","Ban ","Chuan ","Hang ","Fang ","Ban ","Que ","Hesaki ","Zhong ","Jian ","Cang ","Ling ","Zhu ","Ze ","Duo ","Bo ","Xian ","Ge ","Chuan ","Jia ","Lu ","Hong ","Pang ","Xi ","[?] ","Fu ","Zao ","Feng ","Li ","Shao ","Yu ","Lang ","Ting ","[?] ","Wei ","Bo ","Meng ","Nian ","Ju ","Huang ","Shou ","Zong ","Bian ","Mao ","Die ","[?] ","Bang ","Cha ","Yi ","Sao ","Cang ","Cao ","Lou ","Dai ","Sori ","Yao ","Tong ","Yofune ","Dang ","Tan ","Lu ","Yi ","Jie ","Jian ","Huo ","Meng ","Qi ","Lu ","Lu ","Chan ","Shuang ","Gen ","Liang ","Jian ","Jian ","Se ","Yan ","Fu ","Ping ","Yan ","Yan ","Cao ","Cao ","Yi ","Le ","Ting ","Qiu ","Ai ","Nai ","Tiao ","Jiao ","Jie ","Peng ","Wan ","Yi ","Chai ","Mian ","Mie ","Gan ","Qian ","Yu ","Yu ","Shuo ","Qiong ","Tu ","Xia ","Qi ","Mang ","Zi ","Hui ","Sui ","Zhi ","Xiang ","Bi ","Fu ","Tun ","Wei ","Wu ","Zhi ","Qi ","Shan ","Wen ","Qian ","Ren ","Fou ","Kou ","Jie ","Lu ","Xu ","Ji ","Qin ","Qi ","Yuan ","Fen ","Ba ","Rui ","Xin ","Ji ","Hua ","Hua ","Fang ","Wu ","Jue ","Gou ","Zhi ","Yun ","Qin ","Ao ","Chu ","Mao ","Ya ","Fei ","Reng ","Hang ","Cong ","Yin ","You ","Bian ","Yi ","Susa ","Wei ","Li ","Pi ","E ","Xian ","Chang ","Cang ","Meng ","Su ","Yi ","Yuan ","Ran ","Ling ","Tai ","Tiao ","Di ","Miao ","Qiong ","Li ","Yong ","Ke ","Mu ","Pei ","Bao ","Gou ","Min ","Yi ","Yi ","Ju ","Pi ","Ruo ","Ku ","Zhu ","Ni ","Bo ","Bing ","Shan ","Qiu ","Yao ","Xian ","Ben ","Hong ","Ying ","Zha ","Dong ","Ju ","Die ","Nie ","Gan ","Hu ","Ping ","Mei ","Fu ","Sheng ","Gu ","Bi ","Wei "]});var y5=m((N6e,b5)=>{b5.exports=["Fu ","Zhuo ","Mao ","Fan ","Qie ","Mao ","Mao ","Ba ","Zi ","Mo ","Zi ","Di ","Chi ","Ji ","Jing ","Long ","[?] ","Niao ","[?] ","Xue ","Ying ","Qiong ","Ge ","Ming ","Li ","Rong ","Yin ","Gen ","Qian ","Chai ","Chen ","Yu ","Xiu ","Zi ","Lie ","Wu ","Ji ","Kui ","Ce ","Chong ","Ci ","Gou ","Guang ","Mang ","Chi ","Jiao ","Jiao ","Fu ","Yu ","Zhu ","Zi ","Jiang ","Hui ","Yin ","Cha ","Fa ","Rong ","Ru ","Chong ","Mang ","Tong ","Zhong ","[?] ","Zhu ","Xun ","Huan ","Kua ","Quan ","Gai ","Da ","Jing ","Xing ","Quan ","Cao ","Jing ","Er ","An ","Shou ","Chi ","Ren ","Jian ","Ti ","Huang ","Ping ","Li ","Jin ","Lao ","Shu ","Zhuang ","Da ","Jia ","Rao ","Bi ","Ze ","Qiao ","Hui ","Qi ","Dang ","[?] ","Rong ","Hun ","Ying ","Luo ","Ying ","Xun ","Jin ","Sun ","Yin ","Mai ","Hong ","Zhou ","Yao ","Du ","Wei ","Chu ","Dou ","Fu ","Ren ","Yin ","He ","Bi ","Bu ","Yun ","Di ","Tu ","Sui ","Sui ","Cheng ","Chen ","Wu ","Bie ","Xi ","Geng ","Li ","Fu ","Zhu ","Mo ","Li ","Zhuang ","Ji ","Duo ","Qiu ","Sha ","Suo ","Chen ","Feng ","Ju ","Mei ","Meng ","Xing ","Jing ","Che ","Xin ","Jun ","Yan ","Ting ","Diao ","Cuo ","Wan ","Han ","You ","Cuo ","Jia ","Wang ","You ","Niu ","Shao ","Xian ","Lang ","Fu ","E ","Mo ","Wen ","Jie ","Nan ","Mu ","Kan ","Lai ","Lian ","Shi ","Wo ","Usagi ","Lian ","Huo ","You ","Ying ","Ying ","Nuc ","Chun ","Mang ","Mang ","Ci ","Wan ","Jing ","Di ","Qu ","Dong ","Jian ","Zou ","Gu ","La ","Lu ","Ju ","Wei ","Jun ","Nie ","Kun ","He ","Pu ","Zi ","Gao ","Guo ","Fu ","Lun ","Chang ","Chou ","Song ","Chui ","Zhan ","Men ","Cai ","Ba ","Li ","Tu ","Bo ","Han ","Bao ","Qin ","Juan ","Xi ","Qin ","Di ","Jie ","Pu ","Dang ","Jin ","Zhao ","Tai ","Geng ","Hua ","Gu ","Ling ","Fei ","Jin ","An ","Wang ","Beng ","Zhou ","Yan ","Ju ","Jian ","Lin ","Tan ","Shu ","Tian ","Dao "]});var w5=m((B6e,v5)=>{v5.exports=["Hu ","Qi ","He ","Cui ","Tao ","Chun ","Bei ","Chang ","Huan ","Fei ","Lai ","Qi ","Meng ","Ping ","Wei ","Dan ","Sha ","Huan ","Yan ","Yi ","Tiao ","Qi ","Wan ","Ce ","Nai ","Kutabireru ","Tuo ","Jiu ","Tie ","Luo ","[?] ","[?] ","Meng ","[?] ","Yaji ","[?] ","Ying ","Ying ","Ying ","Xiao ","Sa ","Qiu ","Ke ","Xiang ","Wan ","Yu ","Yu ","Fu ","Lian ","Xuan ","Yuan ","Nan ","Ze ","Wo ","Chun ","Xiao ","Yu ","Pian ","Mao ","An ","E ","Luo ","Ying ","Huo ","Gua ","Jiang ","Mian ","Zuo ","Zuo ","Ju ","Bao ","Rou ","Xi ","Xie ","An ","Qu ","Jian ","Fu ","Lu ","Jing ","Pen ","Feng ","Hong ","Hong ","Hou ","Yan ","Tu ","Zhu ","Zi ","Xiang ","Shen ","Ge ","Jie ","Jing ","Mi ","Huang ","Shen ","Pu ","Gai ","Dong ","Zhou ","Qian ","Wei ","Bo ","Wei ","Pa ","Ji ","Hu ","Zang ","Jia ","Duan ","Yao ","Jun ","Cong ","Quan ","Wei ","Xian ","Kui ","Ting ","Hun ","Xi ","Shi ","Qi ","Lan ","Zong ","Yao ","Yuan ","Mei ","Yun ","Shu ","Di ","Zhuan ","Guan ","Sukumo ","Xue ","Chan ","Kai ","Kui ","[?] ","Jiang ","Lou ","Wei ","Pai ","[?] ","Sou ","Yin ","Shi ","Chun ","Shi ","Yun ","Zhen ","Lang ","Nu ","Meng ","He ","Que ","Suan ","Yuan ","Li ","Ju ","Xi ","Pang ","Chu ","Xu ","Tu ","Liu ","Wo ","Zhen ","Qian ","Zu ","Po ","Cuo ","Yuan ","Chu ","Yu ","Kuai ","Pan ","Pu ","Pu ","Na ","Shuo ","Xi ","Fen ","Yun ","Zheng ","Jian ","Ji ","Ruo ","Cang ","En ","Mi ","Hao ","Sun ","Zhen ","Ming ","Sou ","Xu ","Liu ","Xi ","Gu ","Lang ","Rong ","Weng ","Gai ","Cuo ","Shi ","Tang ","Luo ","Ru ","Suo ","Xian ","Bei ","Yao ","Gui ","Bi ","Zong ","Gun ","Za ","Xiu ","Ce ","Hai ","Lan ","[?] ","Ji ","Li ","Can ","Lang ","Yu ","[?] ","Ying ","Mo ","Diao ","Tiao ","Mao ","Tong ","Zhu ","Peng ","An ","Lian ","Cong ","Xi ","Ping ","Qiu ","Jin ","Chun ","Jie ","Wei ","Tui ","Cao ","Yu ","Yi ","Ji ","Liao ","Bi ","Lu ","Su "]});var x5=m((H6e,D5)=>{D5.exports=["Bu ","Zhang ","Luo ","Jiang ","Man ","Yan ","Ling ","Ji ","Piao ","Gun ","Han ","Di ","Su ","Lu ","She ","Shang ","Di ","Mie ","Xun ","Man ","Bo ","Di ","Cuo ","Zhe ","Sen ","Xuan ","Wei ","Hu ","Ao ","Mi ","Lou ","Cu ","Zhong ","Cai ","Po ","Jiang ","Mi ","Cong ","Niao ","Hui ","Jun ","Yin ","Jian ","Yan ","Shu ","Yin ","Kui ","Chen ","Hu ","Sha ","Kou ","Qian ","Ma ","Zang ","Sonoko ","Qiang ","Dou ","Lian ","Lin ","Kou ","Ai ","Bi ","Li ","Wei ","Ji ","Xun ","Sheng ","Fan ","Meng ","Ou ","Chan ","Dian ","Xun ","Jiao ","Rui ","Rui ","Lei ","Yu ","Qiao ","Chu ","Hua ","Jian ","Mai ","Yun ","Bao ","You ","Qu ","Lu ","Rao ","Hui ","E ","Teng ","Fei ","Jue ","Zui ","Fa ","Ru ","Fen ","Kui ","Shun ","Rui ","Ya ","Xu ","Fu ","Jue ","Dang ","Wu ","Tong ","Si ","Xiao ","Xi ","Long ","Yun ","[?] ","Qi ","Jian ","Yun ","Sun ","Ling ","Yu ","Xia ","Yong ","Ji ","Hong ","Si ","Nong ","Lei ","Xuan ","Yun ","Yu ","Xi ","Hao ","Bo ","Hao ","Ai ","Wei ","Hui ","Wei ","Ji ","Ci ","Xiang ","Luan ","Mie ","Yi ","Leng ","Jiang ","Can ","Shen ","Qiang ","Lian ","Ke ","Yuan ","Da ","Ti ","Tang ","Xie ","Bi ","Zhan ","Sun ","Lian ","Fan ","Ding ","Jie ","Gu ","Xie ","Shu ","Jian ","Kao ","Hong ","Sa ","Xin ","Xun ","Yao ","Hie ","Sou ","Shu ","Xun ","Dui ","Pin ","Wei ","Neng ","Chou ","Mai ","Ru ","Piao ","Tai ","Qi ","Zao ","Chen ","Zhen ","Er ","Ni ","Ying ","Gao ","Cong ","Xiao ","Qi ","Fa ","Jian ","Xu ","Kui ","Jie ","Bian ","Diao ","Mi ","Lan ","Jin ","Cang ","Miao ","Qiong ","Qie ","Xian ","[?] ","Ou ","Xian ","Su ","Lu ","Yi ","Xu ","Xie ","Li ","Yi ","La ","Lei ","Xiao ","Di ","Zhi ","Bei ","Teng ","Yao ","Mo ","Huan ","Piao ","Fan ","Sou ","Tan ","Tui ","Qiong ","Qiao ","Wei ","Liu ","Hui ","[?] ","Gao ","Yun ","[?] ","Li ","Shu ","Chu ","Ai ","Lin ","Zao ","Xuan ","Chen ","Lai ","Huo "]});var S5=m((q6e,C5)=>{C5.exports=["Tuo ","Wu ","Rui ","Rui ","Qi ","Heng ","Lu ","Su ","Tui ","Mang ","Yun ","Pin ","Yu ","Xun ","Ji ","Jiong ","Xian ","Mo ","Hagi ","Su ","Jiong ","[?] ","Nie ","Bo ","Rang ","Yi ","Xian ","Yu ","Ju ","Lian ","Lian ","Yin ","Qiang ","Ying ","Long ","Tong ","Wei ","Yue ","Ling ","Qu ","Yao ","Fan ","Mi ","Lan ","Kui ","Lan ","Ji ","Dang ","Katsura ","Lei ","Lei ","Hua ","Feng ","Zhi ","Wei ","Kui ","Zhan ","Huai ","Li ","Ji ","Mi ","Lei ","Huai ","Luo ","Ji ","Kui ","Lu ","Jian ","San ","[?] ","Lei ","Quan ","Xiao ","Yi ","Luan ","Men ","Bie ","Hu ","Hu ","Lu ","Nue ","Lu ","Si ","Xiao ","Qian ","Chu ","Hu ","Xu ","Cuo ","Fu ","Xu ","Xu ","Lu ","Hu ","Yu ","Hao ","Jiao ","Ju ","Guo ","Bao ","Yan ","Zhan ","Zhan ","Kui ","Ban ","Xi ","Shu ","Chong ","Qiu ","Diao ","Ji ","Qiu ","Cheng ","Shi ","[?] ","Di ","Zhe ","She ","Yu ","Gan ","Zi ","Hong ","Hui ","Meng ","Ge ","Sui ","Xia ","Chai ","Shi ","Yi ","Ma ","Xiang ","Fang ","E ","Pa ","Chi ","Qian ","Wen ","Wen ","Rui ","Bang ","Bi ","Yue ","Yue ","Jun ","Qi ","Ran ","Yin ","Qi ","Tian ","Yuan ","Jue ","Hui ","Qin ","Qi ","Zhong ","Ya ","Ci ","Mu ","Wang ","Fen ","Fen ","Hang ","Gong ","Zao ","Fu ","Ran ","Jie ","Fu ","Chi ","Dou ","Piao ","Xian ","Ni ","Te ","Qiu ","You ","Zha ","Ping ","Chi ","You ","He ","Han ","Ju ","Li ","Fu ","Ran ","Zha ","Gou ","Pi ","Bo ","Xian ","Zhu ","Diao ","Bie ","Bing ","Gu ","Ran ","Qu ","She ","Tie ","Ling ","Gu ","Dan ","Gu ","Ying ","Li ","Cheng ","Qu ","Mou ","Ge ","Ci ","Hui ","Hui ","Mang ","Fu ","Yang ","Wa ","Lie ","Zhu ","Yi ","Xian ","Kuo ","Jiao ","Li ","Yi ","Ping ","Ji ","Ha ","She ","Yi ","Wang ","Mo ","Qiong ","Qie ","Gui ","Gong ","Zhi ","Man ","Ebi ","Zhi ","Jia ","Rao ","Si ","Qi ","Xing ","Lie ","Qiu ","Shao ","Yong ","Jia ","Shui ","Che ","Bai ","E ","Han "]});var k5=m((Y6e,T5)=>{T5.exports=["Shu ","Xuan ","Feng ","Shen ","Zhen ","Fu ","Xian ","Zhe ","Wu ","Fu ","Li ","Lang ","Bi ","Chu ","Yuan ","You ","Jie ","Dan ","Yan ","Ting ","Dian ","Shui ","Hui ","Gua ","Zhi ","Song ","Fei ","Ju ","Mi ","Qi ","Qi ","Yu ","Jun ","Zha ","Meng ","Qiang ","Si ","Xi ","Lun ","Li ","Die ","Tiao ","Tao ","Kun ","Gan ","Han ","Yu ","Bang ","Fei ","Pi ","Wei ","Dun ","Yi ","Yuan ","Su ","Quan ","Qian ","Rui ","Ni ","Qing ","Wei ","Liang ","Guo ","Wan ","Dong ","E ","Ban ","Di ","Wang ","Can ","Yang ","Ying ","Guo ","Chan ","[?] ","La ","Ke ","Ji ","He ","Ting ","Mai ","Xu ","Mian ","Yu ","Jie ","Shi ","Xuan ","Huang ","Yan ","Bian ","Rou ","Wei ","Fu ","Yuan ","Mei ","Wei ","Fu ","Ruan ","Xie ","You ","Qiu ","Mao ","Xia ","Ying ","Shi ","Chong ","Tang ","Zhu ","Zong ","Ti ","Fu ","Yuan ","Hui ","Meng ","La ","Du ","Hu ","Qiu ","Die ","Li ","Gua ","Yun ","Ju ","Nan ","Lou ","Qun ","Rong ","Ying ","Jiang ","[?] ","Lang ","Pang ","Si ","Xi ","Ci ","Xi ","Yuan ","Weng ","Lian ","Sou ","Ban ","Rong ","Rong ","Ji ","Wu ","Qiu ","Han ","Qin ","Yi ","Bi ","Hua ","Tang ","Yi ","Du ","Nai ","He ","Hu ","Hui ","Ma ","Ming ","Yi ","Wen ","Ying ","Teng ","Yu ","Cang ","So ","Ebi ","Man ","[?] ","Shang ","Zhe ","Cao ","Chi ","Di ","Ao ","Lu ","Wei ","Zhi ","Tang ","Chen ","Piao ","Qu ","Pi ","Yu ","Jian ","Luo ","Lou ","Qin ","Zhong ","Yin ","Jiang ","Shuai ","Wen ","Jiao ","Wan ","Zhi ","Zhe ","Ma ","Ma ","Guo ","Liu ","Mao ","Xi ","Cong ","Li ","Man ","Xiao ","Kamakiri ","Zhang ","Mang ","Xiang ","Mo ","Zui ","Si ","Qiu ","Te ","Zhi ","Peng ","Peng ","Jiao ","Qu ","Bie ","Liao ","Pan ","Gui ","Xi ","Ji ","Zhuan ","Huang ","Fei ","Lao ","Jue ","Jue ","Hui ","Yin ","Chan ","Jiao ","Shan ","Rao ","Xiao ","Mou ","Chong ","Xun ","Si ","[?] ","Cheng ","Dang ","Li ","Xie ","Shan ","Yi ","Jing ","Da ","Chan ","Qi "]});var P5=m((W6e,E5)=>{E5.exports=["Ci ","Xiang ","She ","Luo ","Qin ","Ying ","Chai ","Li ","Ze ","Xuan ","Lian ","Zhu ","Ze ","Xie ","Mang ","Xie ","Qi ","Rong ","Jian ","Meng ","Hao ","Ruan ","Huo ","Zhuo ","Jie ","Bin ","He ","Mie ","Fan ","Lei ","Jie ","La ","Mi ","Li ","Chun ","Li ","Qiu ","Nie ","Lu ","Du ","Xiao ","Zhu ","Long ","Li ","Long ","Feng ","Ye ","Beng ","Shang ","Gu ","Juan ","Ying ","[?] ","Xi ","Can ","Qu ","Quan ","Du ","Can ","Man ","Jue ","Jie ","Zhu ","Zha ","Xie ","Huang ","Niu ","Pei ","Nu ","Xin ","Zhong ","Mo ","Er ","Ke ","Mie ","Xi ","Xing ","Yan ","Kan ","Yuan ","[?] ","Ling ","Xuan ","Shu ","Xian ","Tong ","Long ","Jie ","Xian ","Ya ","Hu ","Wei ","Dao ","Chong ","Wei ","Dao ","Zhun ","Heng ","Qu ","Yi ","Yi ","Bu ","Gan ","Yu ","Biao ","Cha ","Yi ","Shan ","Chen ","Fu ","Gun ","Fen ","Shuai ","Jie ","Na ","Zhong ","Dan ","Ri ","Zhong ","Zhong ","Xie ","Qi ","Xie ","Ran ","Zhi ","Ren ","Qin ","Jin ","Jun ","Yuan ","Mei ","Chai ","Ao ","Niao ","Hui ","Ran ","Jia ","Tuo ","Ling ","Dai ","Bao ","Pao ","Yao ","Zuo ","Bi ","Shao ","Tan ","Ju ","He ","Shu ","Xiu ","Zhen ","Yi ","Pa ","Bo ","Di ","Wa ","Fu ","Gun ","Zhi ","Zhi ","Ran ","Pan ","Yi ","Mao ","Tuo ","Na ","Kou ","Xian ","Chan ","Qu ","Bei ","Gun ","Xi ","Ne ","Bo ","Horo ","Fu ","Yi ","Chi ","Ku ","Ren ","Jiang ","Jia ","Cun ","Mo ","Jie ","Er ","Luo ","Ru ","Zhu ","Gui ","Yin ","Cai ","Lie ","Kamishimo ","Yuki ","Zhuang ","Dang ","[?] ","Kun ","Ken ","Niao ","Shu ","Jia ","Kun ","Cheng ","Li ","Juan ","Shen ","Pou ","Ge ","Yi ","Yu ","Zhen ","Liu ","Qiu ","Qun ","Ji ","Yi ","Bu ","Zhuang ","Shui ","Sha ","Qun ","Li ","Lian ","Lian ","Ku ","Jian ","Fou ","Chan ","Bi ","Gun ","Tao ","Yuan ","Ling ","Chi ","Chang ","Chou ","Duo ","Biao ","Liang ","Chang ","Pei ","Pei ","Fei ","Yuan ","Luo ","Guo ","Yan ","Du ","Xi ","Zhi ","Ju ","Qi "]});var R5=m((Z6e,_5)=>{_5.exports=["Ji ","Zhi ","Gua ","Ken ","Che ","Ti ","Ti ","Fu ","Chong ","Xie ","Bian ","Die ","Kun ","Duan ","Xiu ","Xiu ","He ","Yuan ","Bao ","Bao ","Fu ","Yu ","Tuan ","Yan ","Hui ","Bei ","Chu ","Lu ","Ena ","Hitoe ","Yun ","Da ","Gou ","Da ","Huai ","Rong ","Yuan ","Ru ","Nai ","Jiong ","Suo ","Ban ","Tun ","Chi ","Sang ","Niao ","Ying ","Jie ","Qian ","Huai ","Ku ","Lian ","Bao ","Li ","Zhe ","Shi ","Lu ","Yi ","Die ","Xie ","Xian ","Wei ","Biao ","Cao ","Ji ","Jiang ","Sen ","Bao ","Xiang ","Chihaya ","Pu ","Jian ","Zhuan ","Jian ","Zui ","Ji ","Dan ","Za ","Fan ","Bo ","Xiang ","Xin ","Bie ","Rao ","Man ","Lan ","Ao ","Duo ","Gui ","Cao ","Sui ","Nong ","Chan ","Lian ","Bi ","Jin ","Dang ","Shu ","Tan ","Bi ","Lan ","Pu ","Ru ","Zhi ","[?] ","Shu ","Wa ","Shi ","Bai ","Xie ","Bo ","Chen ","Lai ","Long ","Xi ","Xian ","Lan ","Zhe ","Dai ","Tasuki ","Zan ","Shi ","Jian ","Pan ","Yi ","Ran ","Ya ","Xi ","Xi ","Yao ","Feng ","Tan ","[?] ","Biao ","Fu ","Ba ","He ","Ji ","Ji ","Jian ","Guan ","Bian ","Yan ","Gui ","Jue ","Pian ","Mao ","Mi ","Mi ","Mie ","Shi ","Si ","Zhan ","Luo ","Jue ","Mi ","Tiao ","Lian ","Yao ","Zhi ","Jun ","Xi ","Shan ","Wei ","Xi ","Tian ","Yu ","Lan ","E ","Du ","Qin ","Pang ","Ji ","Ming ","Ying ","Gou ","Qu ","Zhan ","Jin ","Guan ","Deng ","Jian ","Luo ","Qu ","Jian ","Wei ","Jue ","Qu ","Luo ","Lan ","Shen ","Di ","Guan ","Jian ","Guan ","Yan ","Gui ","Mi ","Shi ","Zhan ","Lan ","Jue ","Ji ","Xi ","Di ","Tian ","Yu ","Gou ","Jin ","Qu ","Jiao ","Jiu ","Jin ","Cu ","Jue ","Zhi ","Chao ","Ji ","Gu ","Dan ","Zui ","Di ","Shang ","Hua ","Quan ","Ge ","Chi ","Jie ","Gui ","Gong ","Hong ","Jie ","Hun ","Qiu ","Xing ","Su ","Ni ","Ji ","Lu ","Zhi ","Zha ","Bi ","Xing ","Hu ","Shang ","Gong ","Zhi ","Xue ","Chu ","Xi ","Yi ","Lu ","Jue ","Xi ","Yan ","Xi "]});var F5=m((J6e,L5)=>{L5.exports=["Yan ","Yan ","Ding ","Fu ","Qiu ","Qiu ","Jiao ","Hong ","Ji ","Fan ","Xun ","Diao ","Hong ","Cha ","Tao ","Xu ","Jie ","Yi ","Ren ","Xun ","Yin ","Shan ","Qi ","Tuo ","Ji ","Xun ","Yin ","E ","Fen ","Ya ","Yao ","Song ","Shen ","Yin ","Xin ","Jue ","Xiao ","Ne ","Chen ","You ","Zhi ","Xiong ","Fang ","Xin ","Chao ","She ","Xian ","Sha ","Tun ","Xu ","Yi ","Yi ","Su ","Chi ","He ","Shen ","He ","Xu ","Zhen ","Zhu ","Zheng ","Gou ","Zi ","Zi ","Zhan ","Gu ","Fu ","Quan ","Die ","Ling ","Di ","Yang ","Li ","Nao ","Pan ","Zhou ","Gan ","Yi ","Ju ","Ao ","Zha ","Tuo ","Yi ","Qu ","Zhao ","Ping ","Bi ","Xiong ","Qu ","Ba ","Da ","Zu ","Tao ","Zhu ","Ci ","Zhe ","Yong ","Xu ","Xun ","Yi ","Huang ","He ","Shi ","Cha ","Jiao ","Shi ","Hen ","Cha ","Gou ","Gui ","Quan ","Hui ","Jie ","Hua ","Gai ","Xiang ","Wei ","Shen ","Chou ","Tong ","Mi ","Zhan ","Ming ","E ","Hui ","Yan ","Xiong ","Gua ","Er ","Beng ","Tiao ","Chi ","Lei ","Zhu ","Kuang ","Kua ","Wu ","Yu ","Teng ","Ji ","Zhi ","Ren ","Su ","Lang ","E ","Kuang ","E ","Shi ","Ting ","Dan ","Bo ","Chan ","You ","Heng ","Qiao ","Qin ","Shua ","An ","Yu ","Xiao ","Cheng ","Jie ","Xian ","Wu ","Wu ","Gao ","Song ","Pu ","Hui ","Jing ","Shuo ","Zhen ","Shuo ","Du ","Yasashi ","Chang ","Shui ","Jie ","Ke ","Qu ","Cong ","Xiao ","Sui ","Wang ","Xuan ","Fei ","Chi ","Ta ","Yi ","Na ","Yin ","Diao ","Pi ","Chuo ","Chan ","Chen ","Zhun ","Ji ","Qi ","Tan ","Zhui ","Wei ","Ju ","Qing ","Jian ","Zheng ","Ze ","Zou ","Qian ","Zhuo ","Liang ","Jian ","Zhu ","Hao ","Lun ","Shen ","Biao ","Huai ","Pian ","Yu ","Die ","Xu ","Pian ","Shi ","Xuan ","Shi ","Hun ","Hua ","E ","Zhong ","Di ","Xie ","Fu ","Pu ","Ting ","Jian ","Qi ","Yu ","Zi ","Chuan ","Xi ","Hui ","Yin ","An ","Xian ","Nan ","Chen ","Feng ","Zhu ","Yang ","Yan ","Heng ","Xuan ","Ge ","Nuo ","Qi "]});var j5=m(($6e,I5)=>{I5.exports=["Mou ","Ye ","Wei ","[?] ","Teng ","Zou ","Shan ","Jian ","Bo ","Ku ","Huang ","Huo ","Ge ","Ying ","Mi ","Xiao ","Mi ","Xi ","Qiang ","Chen ","Nue ","Ti ","Su ","Bang ","Chi ","Qian ","Shi ","Jiang ","Yuan ","Xie ","Xue ","Tao ","Yao ","Yao ","[?] ","Yu ","Biao ","Cong ","Qing ","Li ","Mo ","Mo ","Shang ","Zhe ","Miu ","Jian ","Ze ","Jie ","Lian ","Lou ","Can ","Ou ","Guan ","Xi ","Zhuo ","Ao ","Ao ","Jin ","Zhe ","Yi ","Hu ","Jiang ","Man ","Chao ","Han ","Hua ","Chan ","Xu ","Zeng ","Se ","Xi ","She ","Dui ","Zheng ","Nao ","Lan ","E ","Ying ","Jue ","Ji ","Zun ","Jiao ","Bo ","Hui ","Zhuan ","Mu ","Zen ","Zha ","Shi ","Qiao ","Tan ","Zen ","Pu ","Sheng ","Xuan ","Zao ","Tan ","Dang ","Sui ","Qian ","Ji ","Jiao ","Jing ","Lian ","Nou ","Yi ","Ai ","Zhan ","Pi ","Hui ","Hua ","Yi ","Yi ","Shan ","Rang ","Nou ","Qian ","Zhui ","Ta ","Hu ","Zhou ","Hao ","Ye ","Ying ","Jian ","Yu ","Jian ","Hui ","Du ","Zhe ","Xuan ","Zan ","Lei ","Shen ","Wei ","Chan ","Li ","Yi ","Bian ","Zhe ","Yan ","E ","Chou ","Wei ","Chou ","Yao ","Chan ","Rang ","Yin ","Lan ","Chen ","Huo ","Zhe ","Huan ","Zan ","Yi ","Dang ","Zhan ","Yan ","Du ","Yan ","Ji ","Ding ","Fu ","Ren ","Ji ","Jie ","Hong ","Tao ","Rang ","Shan ","Qi ","Tuo ","Xun ","Yi ","Xun ","Ji ","Ren ","Jiang ","Hui ","Ou ","Ju ","Ya ","Ne ","Xu ","E ","Lun ","Xiong ","Song ","Feng ","She ","Fang ","Jue ","Zheng ","Gu ","He ","Ping ","Zu ","Shi ","Xiong ","Zha ","Su ","Zhen ","Di ","Zou ","Ci ","Qu ","Zhao ","Bi ","Yi ","Yi ","Kuang ","Lei ","Shi ","Gua ","Shi ","Jie ","Hui ","Cheng ","Zhu ","Shen ","Hua ","Dan ","Gou ","Quan ","Gui ","Xun ","Yi ","Zheng ","Gai ","Xiang ","Cha ","Hun ","Xu ","Zhou ","Jie ","Wu ","Yu ","Qiao ","Wu ","Gao ","You ","Hui ","Kuang ","Shuo ","Song ","Ai ","Qing ","Zhu ","Zou ","Nuo ","Du ","Zhuo ","Fei ","Ke ","Wei "]});var O5=m((X6e,A5)=>{A5.exports=["Yu ","Shui ","Shen ","Diao ","Chan ","Liang ","Zhun ","Sui ","Tan ","Shen ","Yi ","Mou ","Chen ","Die ","Huang ","Jian ","Xie ","Nue ","Ye ","Wei ","E ","Yu ","Xuan ","Chan ","Zi ","An ","Yan ","Di ","Mi ","Pian ","Xu ","Mo ","Dang ","Su ","Xie ","Yao ","Bang ","Shi ","Qian ","Mi ","Jin ","Man ","Zhe ","Jian ","Miu ","Tan ","Zen ","Qiao ","Lan ","Pu ","Jue ","Yan ","Qian ","Zhan ","Chen ","Gu ","Qian ","Hong ","Xia ","Jue ","Hong ","Han ","Hong ","Xi ","Xi ","Huo ","Liao ","Han ","Du ","Long ","Dou ","Jiang ","Qi ","Shi ","Li ","Deng ","Wan ","Bi ","Shu ","Xian ","Feng ","Zhi ","Zhi ","Yan ","Yan ","Shi ","Chu ","Hui ","Tun ","Yi ","Tun ","Yi ","Jian ","Ba ","Hou ","E ","Cu ","Xiang ","Huan ","Jian ","Ken ","Gai ","Qu ","Fu ","Xi ","Bin ","Hao ","Yu ","Zhu ","Jia ","[?] ","Xi ","Bo ","Wen ","Huan ","Bin ","Di ","Zong ","Fen ","Yi ","Zhi ","Bao ","Chai ","Han ","Pi ","Na ","Pi ","Gou ","Na ","You ","Diao ","Mo ","Si ","Xiu ","Huan ","Kun ","He ","He ","Mo ","Han ","Mao ","Li ","Ni ","Bi ","Yu ","Jia ","Tuan ","Mao ","Pi ","Xi ","E ","Ju ","Mo ","Chu ","Tan ","Huan ","Jue ","Bei ","Zhen ","Yuan ","Fu ","Cai ","Gong ","Te ","Yi ","Hang ","Wan ","Pin ","Huo ","Fan ","Tan ","Guan ","Ze ","Zhi ","Er ","Zhu ","Shi ","Bi ","Zi ","Er ","Gui ","Pian ","Bian ","Mai ","Dai ","Sheng ","Kuang ","Fei ","Tie ","Yi ","Chi ","Mao ","He ","Bi ","Lu ","Ren ","Hui ","Gai ","Pian ","Zi ","Jia ","Xu ","Zei ","Jiao ","Gai ","Zang ","Jian ","Ying ","Xun ","Zhen ","She ","Bin ","Bin ","Qiu ","She ","Chuan ","Zang ","Zhou ","Lai ","Zan ","Si ","Chen ","Shang ","Tian ","Pei ","Geng ","Xian ","Mai ","Jian ","Sui ","Fu ","Tan ","Cong ","Cong ","Zhi ","Ji ","Zhang ","Du ","Jin ","Xiong ","Shun ","Yun ","Bao ","Zai ","Lai ","Feng ","Cang ","Ji ","Sheng ","Ai ","Zhuan ","Fu ","Gou ","Sai ","Ze ","Liao "]});var N5=m((U6e,M5)=>{M5.exports=["Wei ","Bai ","Chen ","Zhuan ","Zhi ","Zhui ","Biao ","Yun ","Zeng ","Tan ","Zan ","Yan ","[?] ","Shan ","Wan ","Ying ","Jin ","Gan ","Xian ","Zang ","Bi ","Du ","Shu ","Yan ","[?] ","Xuan ","Long ","Gan ","Zang ","Bei ","Zhen ","Fu ","Yuan ","Gong ","Cai ","Ze ","Xian ","Bai ","Zhang ","Huo ","Zhi ","Fan ","Tan ","Pin ","Bian ","Gou ","Zhu ","Guan ","Er ","Jian ","Bi ","Shi ","Tie ","Gui ","Kuang ","Dai ","Mao ","Fei ","He ","Yi ","Zei ","Zhi ","Jia ","Hui ","Zi ","Ren ","Lu ","Zang ","Zi ","Gai ","Jin ","Qiu ","Zhen ","Lai ","She ","Fu ","Du ","Ji ","Shu ","Shang ","Si ","Bi ","Zhou ","Geng ","Pei ","Tan ","Lai ","Feng ","Zhui ","Fu ","Zhuan ","Sai ","Ze ","Yan ","Zan ","Yun ","Zeng ","Shan ","Ying ","Gan ","Chi ","Xi ","She ","Nan ","Xiong ","Xi ","Cheng ","He ","Cheng ","Zhe ","Xia ","Tang ","Zou ","Zou ","Li ","Jiu ","Fu ","Zhao ","Gan ","Qi ","Shan ","Qiong ","Qin ","Xian ","Ci ","Jue ","Qin ","Chi ","Ci ","Chen ","Chen ","Die ","Ju ","Chao ","Di ","Se ","Zhan ","Zhu ","Yue ","Qu ","Jie ","Chi ","Chu ","Gua ","Xue ","Ci ","Tiao ","Duo ","Lie ","Gan ","Suo ","Cu ","Xi ","Zhao ","Su ","Yin ","Ju ","Jian ","Que ","Tang ","Chuo ","Cui ","Lu ","Qu ","Dang ","Qiu ","Zi ","Ti ","Qu ","Chi ","Huang ","Qiao ","Qiao ","Yao ","Zao ","Ti ","[?] ","Zan ","Zan ","Zu ","Pa ","Bao ","Ku ","Ke ","Dun ","Jue ","Fu ","Chen ","Jian ","Fang ","Zhi ","Sa ","Yue ","Pa ","Qi ","Yue ","Qiang ","Tuo ","Tai ","Yi ","Nian ","Ling ","Mei ","Ba ","Die ","Ku ","Tuo ","Jia ","Ci ","Pao ","Qia ","Zhu ","Ju ","Die ","Zhi ","Fu ","Pan ","Ju ","Shan ","Bo ","Ni ","Ju ","Li ","Gen ","Yi ","Ji ","Dai ","Xian ","Jiao ","Duo ","Zhu ","Zhuan ","Kua ","Zhuai ","Gui ","Qiong ","Kui ","Xiang ","Chi ","Lu ","Beng ","Zhi ","Jia ","Tiao ","Cai ","Jian ","Ta ","Qiao ","Bi ","Xian ","Duo ","Ji ","Ju ","Ji ","Shu ","Tu "]});var H5=m((G6e,B5)=>{B5.exports=["Chu ","Jing ","Nie ","Xiao ","Bo ","Chi ","Qun ","Mou ","Shu ","Lang ","Yong ","Jiao ","Chou ","Qiao ","[?] ","Ta ","Jian ","Qi ","Wo ","Wei ","Zhuo ","Jie ","Ji ","Nie ","Ju ","Ju ","Lun ","Lu ","Leng ","Huai ","Ju ","Chi ","Wan ","Quan ","Ti ","Bo ","Zu ","Qie ","Ji ","Cu ","Zong ","Cai ","Zong ","Peng ","Zhi ","Zheng ","Dian ","Zhi ","Yu ","Duo ","Dun ","Chun ","Yong ","Zhong ","Di ","Zhe ","Chen ","Chuai ","Jian ","Gua ","Tang ","Ju ","Fu ","Zu ","Die ","Pian ","Rou ","Nuo ","Ti ","Cha ","Tui ","Jian ","Dao ","Cuo ","Xi ","Ta ","Qiang ","Zhan ","Dian ","Ti ","Ji ","Nie ","Man ","Liu ","Zhan ","Bi ","Chong ","Lu ","Liao ","Cu ","Tang ","Dai ","Suo ","Xi ","Kui ","Ji ","Zhi ","Qiang ","Di ","Man ","Zong ","Lian ","Beng ","Zao ","Nian ","Bie ","Tui ","Ju ","Deng ","Ceng ","Xian ","Fan ","Chu ","Zhong ","Dun ","Bo ","Cu ","Zu ","Jue ","Jue ","Lin ","Ta ","Qiao ","Qiao ","Pu ","Liao ","Dun ","Cuan ","Kuang ","Zao ","Ta ","Bi ","Bi ","Zhu ","Ju ","Chu ","Qiao ","Dun ","Chou ","Ji ","Wu ","Yue ","Nian ","Lin ","Lie ","Zhi ","Li ","Zhi ","Chan ","Chu ","Duan ","Wei ","Long ","Lin ","Xian ","Wei ","Zuan ","Lan ","Xie ","Rang ","Xie ","Nie ","Ta ","Qu ","Jie ","Cuan ","Zuan ","Xi ","Kui ","Jue ","Lin ","Shen ","Gong ","Dan ","Segare ","Qu ","Ti ","Duo ","Duo ","Gong ","Lang ","Nerau ","Luo ","Ai ","Ji ","Ju ","Tang ","Utsuke ","[?] ","Yan ","Shitsuke ","Kang ","Qu ","Lou ","Lao ","Tuo ","Zhi ","Yagate ","Ti ","Dao ","Yagate ","Yu ","Che ","Ya ","Gui ","Jun ","Wei ","Yue ","Xin ","Di ","Xuan ","Fan ","Ren ","Shan ","Qiang ","Shu ","Tun ","Chen ","Dai ","E ","Na ","Qi ","Mao ","Ruan ","Ren ","Fan ","Zhuan ","Hong ","Hu ","Qu ","Huang ","Di ","Ling ","Dai ","Ao ","Zhen ","Fan ","Kuang ","Ang ","Peng ","Bei ","Gu ","Ku ","Pao ","Zhu ","Rong ","E ","Ba ","Zhou ","Zhi ","Yao ","Ke ","Yi ","Qing ","Shi ","Ping "]});var Y5=m((Q6e,q5)=>{q5.exports=["Er ","Qiong ","Ju ","Jiao ","Guang ","Lu ","Kai ","Quan ","Zhou ","Zai ","Zhi ","She ","Liang ","Yu ","Shao ","You ","Huan ","Yun ","Zhe ","Wan ","Fu ","Qing ","Zhou ","Ni ","Ling ","Zhe ","Zhan ","Liang ","Zi ","Hui ","Wang ","Chuo ","Guo ","Kan ","Yi ","Peng ","Qian ","Gun ","Nian ","Pian ","Guan ","Bei ","Lun ","Pai ","Liang ","Ruan ","Rou ","Ji ","Yang ","Xian ","Chuan ","Cou ","Qun ","Ge ","You ","Hong ","Shu ","Fu ","Zi ","Fu ","Wen ","Ben ","Zhan ","Yu ","Wen ","Tao ","Gu ","Zhen ","Xia ","Yuan ","Lu ","Jiu ","Chao ","Zhuan ","Wei ","Hun ","Sori ","Che ","Jiao ","Zhan ","Pu ","Lao ","Fen ","Fan ","Lin ","Ge ","Se ","Kan ","Huan ","Yi ","Ji ","Dui ","Er ","Yu ","Xian ","Hong ","Lei ","Pei ","Li ","Li ","Lu ","Lin ","Che ","Ya ","Gui ","Xuan ","Di ","Ren ","Zhuan ","E ","Lun ","Ruan ","Hong ","Ku ","Ke ","Lu ","Zhou ","Zhi ","Yi ","Hu ","Zhen ","Li ","Yao ","Qing ","Shi ","Zai ","Zhi ","Jiao ","Zhou ","Quan ","Lu ","Jiao ","Zhe ","Fu ","Liang ","Nian ","Bei ","Hui ","Gun ","Wang ","Liang ","Chuo ","Zi ","Cou ","Fu ","Ji ","Wen ","Shu ","Pei ","Yuan ","Xia ","Zhan ","Lu ","Che ","Lin ","Xin ","Gu ","Ci ","Ci ","Pi ","Zui ","Bian ","La ","La ","Ci ","Xue ","Ban ","Bian ","Bian ","Bian ","[?] ","Bian ","Ban ","Ci ","Bian ","Bian ","Chen ","Ru ","Nong ","Nong ","Zhen ","Chuo ","Chuo ","Suberu ","Reng ","Bian ","Bian ","Sip ","Ip ","Liao ","Da ","Chan ","Gan ","Qian ","Yu ","Yu ","Qi ","Xun ","Yi ","Guo ","Mai ","Qi ","Za ","Wang ","Jia ","Zhun ","Ying ","Ti ","Yun ","Jin ","Hang ","Ya ","Fan ","Wu ","Da ","E ","Huan ","Zhe ","Totemo ","Jin ","Yuan ","Wei ","Lian ","Chi ","Che ","Ni ","Tiao ","Zhi ","Yi ","Jiong ","Jia ","Chen ","Dai ","Er ","Di ","Po ","Wang ","Die ","Ze ","Tao ","Shu ","Tuo ","Kep ","Jing ","Hui ","Tong ","You ","Mi ","Beng ","Ji ","Nai ","Yi ","Jie ","Zhui ","Lie ","Xun "]});var Z5=m((K6e,W5)=>{W5.exports=["Tui ","Song ","Gua ","Tao ","Pang ","Hou ","Ni ","Dun ","Jiong ","Xuan ","Xun ","Bu ","You ","Xiao ","Qiu ","Tou ","Zhu ","Qiu ","Di ","Di ","Tu ","Jing ","Ti ","Dou ","Yi ","Zhe ","Tong ","Guang ","Wu ","Shi ","Cheng ","Su ","Zao ","Qun ","Feng ","Lian ","Suo ","Hui ","Li ","Sako ","Lai ","Ben ","Cuo ","Jue ","Beng ","Huan ","Dai ","Lu ","You ","Zhou ","Jin ","Yu ","Chuo ","Kui ","Wei ","Ti ","Yi ","Da ","Yuan ","Luo ","Bi ","Nuo ","Yu ","Dang ","Sui ","Dun ","Sui ","Yan ","Chuan ","Chi ","Ti ","Yu ","Shi ","Zhen ","You ","Yun ","E ","Bian ","Guo ","E ","Xia ","Huang ","Qiu ","Dao ","Da ","Wei ","Appare ","Yi ","Gou ","Yao ","Chu ","Liu ","Xun ","Ta ","Di ","Chi ","Yuan ","Su ","Ta ","Qian ","[?] ","Yao ","Guan ","Zhang ","Ao ","Shi ","Ce ","Chi ","Su ","Zao ","Zhe ","Dun ","Di ","Lou ","Chi ","Cuo ","Lin ","Zun ","Rao ","Qian ","Xuan ","Yu ","Yi ","Wu ","Liao ","Ju ","Shi ","Bi ","Yao ","Mai ","Xie ","Sui ","Huan ","Zhan ","Teng ","Er ","Miao ","Bian ","Bian ","La ","Li ","Yuan ","Yao ","Luo ","Li ","Yi ","Ting ","Deng ","Qi ","Yong ","Shan ","Han ","Yu ","Mang ","Ru ","Qiong ","[?] ","Kuang ","Fu ","Kang ","Bin ","Fang ","Xing ","Na ","Xin ","Shen ","Bang ","Yuan ","Cun ","Huo ","Xie ","Bang ","Wu ","Ju ","You ","Han ","Tai ","Qiu ","Bi ","Pei ","Bing ","Shao ","Bei ","Wa ","Di ","Zou ","Ye ","Lin ","Kuang ","Gui ","Zhu ","Shi ","Ku ","Yu ","Gai ","Ge ","Xi ","Zhi ","Ji ","Xun ","Hou ","Xing ","Jiao ","Xi ","Gui ","Nuo ","Lang ","Jia ","Kuai ","Zheng ","Otoko ","Yun ","Yan ","Cheng ","Dou ","Chi ","Lu ","Fu ","Wu ","Fu ","Gao ","Hao ","Lang ","Jia ","Geng ","Jun ","Ying ","Bo ","Xi ","Bei ","Li ","Yun ","Bu ","Xiao ","Qi ","Pi ","Qing ","Guo ","Zhou ","Tan ","Zou ","Ping ","Lai ","Ni ","Chen ","You ","Bu ","Xiang ","Dan ","Ju ","Yong ","Qiao ","Yi ","Du ","Yan ","Mei "]});var $5=m((z6e,J5)=>{J5.exports=["Ruo ","Bei ","E ","Yu ","Juan ","Yu ","Yun ","Hou ","Kui ","Xiang ","Xiang ","Sou ","Tang ","Ming ","Xi ","Ru ","Chu ","Zi ","Zou ","Ju ","Wu ","Xiang ","Yun ","Hao ","Yong ","Bi ","Mo ","Chao ","Fu ","Liao ","Yin ","Zhuan ","Hu ","Qiao ","Yan ","Zhang ","Fan ","Qiao ","Xu ","Deng ","Bi ","Xin ","Bi ","Ceng ","Wei ","Zheng ","Mao ","Shan ","Lin ","Po ","Dan ","Meng ","Ye ","Cao ","Kuai ","Feng ","Meng ","Zou ","Kuang ","Lian ","Zan ","Chan ","You ","Qi ","Yan ","Chan ","Zan ","Ling ","Huan ","Xi ","Feng ","Zan ","Li ","You ","Ding ","Qiu ","Zhuo ","Pei ","Zhou ","Yi ","Hang ","Yu ","Jiu ","Yan ","Zui ","Mao ","Dan ","Xu ","Tou ","Zhen ","Fen ","Sakenomoto ","[?] ","Yun ","Tai ","Tian ","Qia ","Tuo ","Zuo ","Han ","Gu ","Su ","Po ","Chou ","Zai ","Ming ","Luo ","Chuo ","Chou ","You ","Tong ","Zhi ","Xian ","Jiang ","Cheng ","Yin ","Tu ","Xiao ","Mei ","Ku ","Suan ","Lei ","Pu ","Zui ","Hai ","Yan ","Xi ","Niang ","Wei ","Lu ","Lan ","Yan ","Tao ","Pei ","Zhan ","Chun ","Tan ","Zui ","Chuo ","Cu ","Kun ","Ti ","Mian ","Du ","Hu ","Xu ","Xing ","Tan ","Jiu ","Chun ","Yun ","Po ","Ke ","Sou ","Mi ","Quan ","Chou ","Cuo ","Yun ","Yong ","Ang ","Zha ","Hai ","Tang ","Jiang ","Piao ","Shan ","Yu ","Li ","Zao ","Lao ","Yi ","Jiang ","Pu ","Jiao ","Xi ","Tan ","Po ","Nong ","Yi ","Li ","Ju ","Jiao ","Yi ","Niang ","Ru ","Xun ","Chou ","Yan ","Ling ","Mi ","Mi ","Niang ","Xin ","Jiao ","Xi ","Mi ","Yan ","Bian ","Cai ","Shi ","You ","Shi ","Shi ","Li ","Zhong ","Ye ","Liang ","Li ","Jin ","Jin ","Qiu ","Yi ","Diao ","Dao ","Zhao ","Ding ","Po ","Qiu ","He ","Fu ","Zhen ","Zhi ","Ba ","Luan ","Fu ","Nai ","Diao ","Shan ","Qiao ","Kou ","Chuan ","Zi ","Fan ","Yu ","Hua ","Han ","Gong ","Qi ","Mang ","Ri ","Di ","Si ","Xi ","Yi ","Chai ","Shi ","Tu ","Xi ","Nu ","Qian ","Ishiyumi ","Jian ","Pi ","Ye ","Yin "]});var U5=m((V6e,X5)=>{X5.exports=["Ba ","Fang ","Chen ","Xing ","Tou ","Yue ","Yan ","Fu ","Pi ","Na ","Xin ","E ","Jue ","Dun ","Gou ","Yin ","Qian ","Ban ","Ji ","Ren ","Chao ","Niu ","Fen ","Yun ","Ji ","Qin ","Pi ","Guo ","Hong ","Yin ","Jun ","Shi ","Yi ","Zhong ","Nie ","Gai ","Ri ","Huo ","Tai ","Kang ","Habaki ","Irori ","Ngaak ","[?] ","Duo ","Zi ","Ni ","Tu ","Shi ","Min ","Gu ","E ","Ling ","Bing ","Yi ","Gu ","Ba ","Pi ","Yu ","Si ","Zuo ","Bu ","You ","Dian ","Jia ","Zhen ","Shi ","Shi ","Tie ","Ju ","Zhan ","Shi ","She ","Xuan ","Zhao ","Bao ","He ","Bi ","Sheng ","Chu ","Shi ","Bo ","Zhu ","Chi ","Za ","Po ","Tong ","Qian ","Fu ","Zhai ","Liu ","Qian ","Fu ","Li ","Yue ","Pi ","Yang ","Ban ","Bo ","Jie ","Gou ","Shu ","Zheng ","Mu ","Ni ","Nie ","Di ","Jia ","Mu ","Dan ","Shen ","Yi ","Si ","Kuang ","Ka ","Bei ","Jian ","Tong ","Xing ","Hong ","Jiao ","Chi ","Er ","Ge ","Bing ","Shi ","Mou ","Jia ","Yin ","Jun ","Zhou ","Chong ","Shang ","Tong ","Mo ","Lei ","Ji ","Yu ","Xu ","Ren ","Zun ","Zhi ","Qiong ","Shan ","Chi ","Xian ","Xing ","Quan ","Pi ","Tie ","Zhu ","Hou ","Ming ","Kua ","Yao ","Xian ","Xian ","Xiu ","Jun ","Cha ","Lao ","Ji ","Pi ","Ru ","Mi ","Yi ","Yin ","Guang ","An ","Diou ","You ","Se ","Kao ","Qian ","Luan ","Kasugai ","Ai ","Diao ","Han ","Rui ","Shi ","Keng ","Qiu ","Xiao ","Zhe ","Xiu ","Zang ","Ti ","Cuo ","Gua ","Gong ","Zhong ","Dou ","Lu ","Mei ","Lang ","Wan ","Xin ","Yun ","Bei ","Wu ","Su ","Yu ","Chan ","Ting ","Bo ","Han ","Jia ","Hong ","Cuan ","Feng ","Chan ","Wan ","Zhi ","Si ","Xuan ","Wu ","Wu ","Tiao ","Gong ","Zhuo ","Lue ","Xing ","Qian ","Shen ","Han ","Lue ","Xie ","Chu ","Zheng ","Ju ","Xian ","Tie ","Mang ","Pu ","Li ","Pan ","Rui ","Cheng ","Gao ","Li ","Te ","Pyeng ","Zhu ","[?] ","Tu ","Liu ","Zui ","Ju ","Chang ","Yuan ","Jian ","Gang ","Diao ","Tao ","Chang "]});var Q5=m((e4e,G5)=>{G5.exports=["Lun ","Kua ","Ling ","Bei ","Lu ","Li ","Qiang ","Pou ","Juan ","Min ","Zui ","Peng ","An ","Pi ","Xian ","Ya ","Zhui ","Lei ","A ","Kong ","Ta ","Kun ","Du ","Wei ","Chui ","Zi ","Zheng ","Ben ","Nie ","Cong ","Qun ","Tan ","Ding ","Qi ","Qian ","Zhuo ","Qi ","Yu ","Jin ","Guan ","Mao ","Chang ","Tian ","Xi ","Lian ","Tao ","Gu ","Cuo ","Shu ","Zhen ","Lu ","Meng ","Lu ","Hua ","Biao ","Ga ","Lai ","Ken ","Kazari ","Bu ","Nai ","Wan ","Zan ","[?] ","De ","Xian ","[?] ","Huo ","Liang ","[?] ","Men ","Kai ","Ying ","Di ","Lian ","Guo ","Xian ","Du ","Tu ","Wei ","Cong ","Fu ","Rou ","Ji ","E ","Rou ","Chen ","Ti ","Zha ","Hong ","Yang ","Duan ","Xia ","Yu ","Keng ","Xing ","Huang ","Wei ","Fu ","Zhao ","Cha ","Qie ","She ","Hong ","Kui ","Tian ","Mou ","Qiao ","Qiao ","Hou ","Tou ","Cong ","Huan ","Ye ","Min ","Jian ","Duan ","Jian ","Song ","Kui ","Hu ","Xuan ","Duo ","Jie ","Zhen ","Bian ","Zhong ","Zi ","Xiu ","Ye ","Mei ","Pai ","Ai ","Jie ","[?] ","Mei ","Chuo ","Ta ","Bang ","Xia ","Lian ","Suo ","Xi ","Liu ","Zu ","Ye ","Nou ","Weng ","Rong ","Tang ","Suo ","Qiang ","Ge ","Shuo ","Chui ","Bo ","Pan ","Sa ","Bi ","Sang ","Gang ","Zi ","Wu ","Ying ","Huang ","Tiao ","Liu ","Kai ","Sun ","Sha ","Sou ","Wan ","Hao ","Zhen ","Zhen ","Luo ","Yi ","Yuan ","Tang ","Nie ","Xi ","Jia ","Ge ","Ma ","Juan ","Kasugai ","Habaki ","Suo ","[?] ","[?] ","[?] ","Na ","Lu ","Suo ","Ou ","Zu ","Tuan ","Xiu ","Guan ","Xuan ","Lian ","Shou ","Ao ","Man ","Mo ","Luo ","Bi ","Wei ","Liu ","Di ","Qiao ","Cong ","Yi ","Lu ","Ao ","Keng ","Qiang ","Cui ","Qi ","Chang ","Tang ","Man ","Yong ","Chan ","Feng ","Jing ","Biao ","Shu ","Lou ","Xiu ","Cong ","Long ","Zan ","Jian ","Cao ","Li ","Xia ","Xi ","Kang ","[?] ","Beng ","[?] ","[?] ","Zheng ","Lu ","Hua ","Ji ","Pu ","Hui ","Qiang ","Po ","Lin ","Suo ","Xiu ","San ","Cheng "]});var z5=m((t4e,K5)=>{K5.exports=["Kui ","Si ","Liu ","Nao ","Heng ","Pie ","Sui ","Fan ","Qiao ","Quan ","Yang ","Tang ","Xiang ","Jue ","Jiao ","Zun ","Liao ","Jie ","Lao ","Dui ","Tan ","Zan ","Ji ","Jian ","Zhong ","Deng ","Ya ","Ying ","Dui ","Jue ","Nou ","Ti ","Pu ","Tie ","[?] ","[?] ","Ding ","Shan ","Kai ","Jian ","Fei ","Sui ","Lu ","Juan ","Hui ","Yu ","Lian ","Zhuo ","Qiao ","Qian ","Zhuo ","Lei ","Bi ","Tie ","Huan ","Ye ","Duo ","Guo ","Dang ","Ju ","Fen ","Da ","Bei ","Yi ","Ai ","Zong ","Xun ","Diao ","Zhu ","Heng ","Zhui ","Ji ","Nie ","Ta ","Huo ","Qing ","Bin ","Ying ","Kui ","Ning ","Xu ","Jian ","Jian ","Yari ","Cha ","Zhi ","Mie ","Li ","Lei ","Ji ","Zuan ","Kuang ","Shang ","Peng ","La ","Du ","Shuo ","Chuo ","Lu ","Biao ","Bao ","Lu ","[?] ","[?] ","Long ","E ","Lu ","Xin ","Jian ","Lan ","Bo ","Jian ","Yao ","Chan ","Xiang ","Jian ","Xi ","Guan ","Cang ","Nie ","Lei ","Cuan ","Qu ","Pan ","Luo ","Zuan ","Luan ","Zao ","Nie ","Jue ","Tang ","Shu ","Lan ","Jin ","Qiu ","Yi ","Zhen ","Ding ","Zhao ","Po ","Diao ","Tu ","Qian ","Chuan ","Shan ","Ji ","Fan ","Diao ","Men ","Nu ","Xi ","Chai ","Xing ","Gai ","Bu ","Tai ","Ju ","Dun ","Chao ","Zhong ","Na ","Bei ","Gang ","Ban ","Qian ","Yao ","Qin ","Jun ","Wu ","Gou ","Kang ","Fang ","Huo ","Tou ","Niu ","Ba ","Yu ","Qian ","Zheng ","Qian ","Gu ","Bo ","E ","Po ","Bu ","Ba ","Yue ","Zuan ","Mu ","Dan ","Jia ","Dian ","You ","Tie ","Bo ","Ling ","Shuo ","Qian ","Liu ","Bao ","Shi ","Xuan ","She ","Bi ","Ni ","Pi ","Duo ","Xing ","Kao ","Lao ","Er ","Mang ","Ya ","You ","Cheng ","Jia ","Ye ","Nao ","Zhi ","Dang ","Tong ","Lu ","Diao ","Yin ","Kai ","Zha ","Zhu ","Xian ","Ting ","Diu ","Xian ","Hua ","Quan ","Sha ","Jia ","Yao ","Ge ","Ming ","Zheng ","Se ","Jiao ","Yi ","Chan ","Chong ","Tang ","An ","Yin ","Ru ","Zhu ","Lao ","Pu ","Wu ","Lai ","Te ","Lian ","Keng "]});var e7=m((i4e,V5)=>{V5.exports=["Xiao ","Suo ","Li ","Zheng ","Chu ","Guo ","Gao ","Tie ","Xiu ","Cuo ","Lue ","Feng ","Xin ","Liu ","Kai ","Jian ","Rui ","Ti ","Lang ","Qian ","Ju ","A ","Qiang ","Duo ","Tian ","Cuo ","Mao ","Ben ","Qi ","De ","Kua ","Kun ","Chang ","Xi ","Gu ","Luo ","Chui ","Zhui ","Jin ","Zhi ","Xian ","Juan ","Huo ","Pou ","Tan ","Ding ","Jian ","Ju ","Meng ","Zi ","Qie ","Ying ","Kai ","Qiang ","Song ","E ","Cha ","Qiao ","Zhong ","Duan ","Sou ","Huang ","Huan ","Ai ","Du ","Mei ","Lou ","Zi ","Fei ","Mei ","Mo ","Zhen ","Bo ","Ge ","Nie ","Tang ","Juan ","Nie ","Na ","Liu ","Hao ","Bang ","Yi ","Jia ","Bin ","Rong ","Biao ","Tang ","Man ","Luo ","Beng ","Yong ","Jing ","Di ","Zu ","Xuan ","Liu ","Tan ","Jue ","Liao ","Pu ","Lu ","Dui ","Lan ","Pu ","Cuan ","Qiang ","Deng ","Huo ","Lei ","Huan ","Zhuo ","Lian ","Yi ","Cha ","Biao ","La ","Chan ","Xiang ","Chang ","Chang ","Jiu ","Ao ","Die ","Qu ","Liao ","Mi ","Chang ","Men ","Ma ","Shuan ","Shan ","Huo ","Men ","Yan ","Bi ","Han ","Bi ","San ","Kai ","Kang ","Beng ","Hong ","Run ","San ","Xian ","Xian ","Jian ","Min ","Xia ","Yuru ","Dou ","Zha ","Nao ","Jian ","Peng ","Xia ","Ling ","Bian ","Bi ","Run ","He ","Guan ","Ge ","Ge ","Fa ","Chu ","Hong ","Gui ","Min ","Se ","Kun ","Lang ","Lu ","Ting ","Sha ","Ju ","Yue ","Yue ","Chan ","Qu ","Lin ","Chang ","Shai ","Kun ","Yan ","Min ","Yan ","E ","Hun ","Yu ","Wen ","Xiang ","Bao ","Xiang ","Qu ","Yao ","Wen ","Ban ","An ","Wei ","Yin ","Kuo ","Que ","Lan ","Du ","[?] ","Phwung ","Tian ","Nie ","Ta ","Kai ","He ","Que ","Chuang ","Guan ","Dou ","Qi ","Kui ","Tang ","Guan ","Piao ","Kan ","Xi ","Hui ","Chan ","Pi ","Dang ","Huan ","Ta ","Wen ","[?] ","Men ","Shuan ","Shan ","Yan ","Han ","Bi ","Wen ","Chuang ","Run ","Wei ","Xian ","Hong ","Jian ","Min ","Kang ","Men ","Zha ","Nao ","Gui ","Wen ","Ta ","Min ","Lu ","Kai "]});var i7=m((n4e,t7)=>{t7.exports=["Fa ","Ge ","He ","Kun ","Jiu ","Yue ","Lang ","Du ","Yu ","Yan ","Chang ","Xi ","Wen ","Hun ","Yan ","E ","Chan ","Lan ","Qu ","Hui ","Kuo ","Que ","Ge ","Tian ","Ta ","Que ","Kan ","Huan ","Fu ","Fu ","Le ","Dui ","Xin ","Qian ","Wu ","Yi ","Tuo ","Yin ","Yang ","Dou ","E ","Sheng ","Ban ","Pei ","Keng ","Yun ","Ruan ","Zhi ","Pi ","Jing ","Fang ","Yang ","Yin ","Zhen ","Jie ","Cheng ","E ","Qu ","Di ","Zu ","Zuo ","Dian ","Ling ","A ","Tuo ","Tuo ","Po ","Bing ","Fu ","Ji ","Lu ","Long ","Chen ","Xing ","Duo ","Lou ","Mo ","Jiang ","Shu ","Duo ","Xian ","Er ","Gui ","Yu ","Gai ","Shan ","Xun ","Qiao ","Xing ","Chun ","Fu ","Bi ","Xia ","Shan ","Sheng ","Zhi ","Pu ","Dou ","Yuan ","Zhen ","Chu ","Xian ","Tou ","Nie ","Yun ","Xian ","Pei ","Pei ","Zou ","Yi ","Dui ","Lun ","Yin ","Ju ","Chui ","Chen ","Pi ","Ling ","Tao ","Xian ","Lu ","Sheng ","Xian ","Yin ","Zhu ","Yang ","Reng ","Shan ","Chong ","Yan ","Yin ","Yu ","Ti ","Yu ","Long ","Wei ","Wei ","Nie ","Dui ","Sui ","An ","Huang ","Jie ","Sui ","Yin ","Gai ","Yan ","Hui ","Ge ","Yun ","Wu ","Wei ","Ai ","Xi ","Tang ","Ji ","Zhang ","Dao ","Ao ","Xi ","Yin ","[?] ","Rao ","Lin ","Tui ","Deng ","Pi ","Sui ","Sui ","Yu ","Xian ","Fen ","Ni ","Er ","Ji ","Dao ","Xi ","Yin ","E ","Hui ","Long ","Xi ","Li ","Li ","Li ","Zhui ","He ","Zhi ","Zhun ","Jun ","Nan ","Yi ","Que ","Yan ","Qian ","Ya ","Xiong ","Ya ","Ji ","Gu ","Huan ","Zhi ","Gou ","Jun ","Ci ","Yong ","Ju ","Chu ","Hu ","Za ","Luo ","Yu ","Chou ","Diao ","Sui ","Han ","Huo ","Shuang ","Guan ","Chu ","Za ","Yong ","Ji ","Xi ","Chou ","Liu ","Li ","Nan ","Xue ","Za ","Ji ","Ji ","Yu ","Yu ","Xue ","Na ","Fou ","Se ","Mu ","Wen ","Fen ","Pang ","Yun ","Li ","Li ","Ang ","Ling ","Lei ","An ","Bao ","Meng ","Dian ","Dang ","Xing ","Wu ","Zhao "]});var r7=m((r4e,n7)=>{n7.exports=["Xu ","Ji ","Mu ","Chen ","Xiao ","Zha ","Ting ","Zhen ","Pei ","Mei ","Ling ","Qi ","Chou ","Huo ","Sha ","Fei ","Weng ","Zhan ","Yin ","Ni ","Chou ","Tun ","Lin ","[?] ","Dong ","Ying ","Wu ","Ling ","Shuang ","Ling ","Xia ","Hong ","Yin ","Mo ","Mai ","Yun ","Liu ","Meng ","Bin ","Wu ","Wei ","Huo ","Yin ","Xi ","Yi ","Ai ","Dan ","Deng ","Xian ","Yu ","Lu ","Long ","Dai ","Ji ","Pang ","Yang ","Ba ","Pi ","Wei ","[?] ","Xi ","Ji ","Mai ","Meng ","Meng ","Lei ","Li ","Huo ","Ai ","Fei ","Dai ","Long ","Ling ","Ai ","Feng ","Li ","Bao ","[?] ","He ","He ","Bing ","Qing ","Qing ","Jing ","Tian ","Zhen ","Jing ","Cheng ","Qing ","Jing ","Jing ","Dian ","Jing ","Tian ","Fei ","Fei ","Kao ","Mi ","Mian ","Mian ","Pao ","Ye ","Tian ","Hui ","Ye ","Ge ","Ding ","Cha ","Jian ","Ren ","Di ","Du ","Wu ","Ren ","Qin ","Jin ","Xue ","Niu ","Ba ","Yin ","Sa ","Na ","Mo ","Zu ","Da ","Ban ","Yi ","Yao ","Tao ","Tuo ","Jia ","Hong ","Pao ","Yang ","Tomo ","Yin ","Jia ","Tao ","Ji ","Xie ","An ","An ","Hen ","Gong ","Kohaze ","Da ","Qiao ","Ting ","Wan ","Ying ","Sui ","Tiao ","Qiao ","Xuan ","Kong ","Beng ","Ta ","Zhang ","Bing ","Kuo ","Ju ","La ","Xie ","Rou ","Bang ","Yi ","Qiu ","Qiu ","He ","Xiao ","Mu ","Ju ","Jian ","Bian ","Di ","Jian ","On ","Tao ","Gou ","Ta ","Bei ","Xie ","Pan ","Ge ","Bi ","Kuo ","Tang ","Lou ","Gui ","Qiao ","Xue ","Ji ","Jian ","Jiang ","Chan ","Da ","Huo ","Xian ","Qian ","Du ","Wa ","Jian ","Lan ","Wei ","Ren ","Fu ","Mei ","Juan ","Ge ","Wei ","Qiao ","Han ","Chang ","[?] ","Rou ","Xun ","She ","Wei ","Ge ","Bei ","Tao ","Gou ","Yun ","[?] ","Bi ","Wei ","Hui ","Du ","Wa ","Du ","Wei ","Ren ","Fu ","Han ","Wei ","Yun ","Tao ","Jiu ","Jiu ","Xian ","Xie ","Xian ","Ji ","Yin ","Za ","Yun ","Shao ","Le ","Peng ","Heng ","Ying ","Yun ","Peng ","Yin ","Yin ","Xiang "]});var s7=m((o4e,o7)=>{o7.exports=["Hu ","Ye ","Ding ","Qing ","Pan ","Xiang ","Shun ","Han ","Xu ","Yi ","Xu ","Gu ","Song ","Kui ","Qi ","Hang ","Yu ","Wan ","Ban ","Dun ","Di ","Dan ","Pan ","Po ","Ling ","Ce ","Jing ","Lei ","He ","Qiao ","E ","E ","Wei ","Jie ","Gua ","Shen ","Yi ","Shen ","Hai ","Dui ","Pian ","Ping ","Lei ","Fu ","Jia ","Tou ","Hui ","Kui ","Jia ","Le ","Tian ","Cheng ","Ying ","Jun ","Hu ","Han ","Jing ","Tui ","Tui ","Pin ","Lai ","Tui ","Zi ","Zi ","Chui ","Ding ","Lai ","Yan ","Han ","Jian ","Ke ","Cui ","Jiong ","Qin ","Yi ","Sai ","Ti ","E ","E ","Yan ","Hun ","Kan ","Yong ","Zhuan ","Yan ","Xian ","Xin ","Yi ","Yuan ","Sang ","Dian ","Dian ","Jiang ","Ku ","Lei ","Liao ","Piao ","Yi ","Man ","Qi ","Rao ","Hao ","Qiao ","Gu ","Xun ","Qian ","Hui ","Zhan ","Ru ","Hong ","Bin ","Xian ","Pin ","Lu ","Lan ","Nie ","Quan ","Ye ","Ding ","Qing ","Han ","Xiang ","Shun ","Xu ","Xu ","Wan ","Gu ","Dun ","Qi ","Ban ","Song ","Hang ","Yu ","Lu ","Ling ","Po ","Jing ","Jie ","Jia ","Tian ","Han ","Ying ","Jiong ","Hai ","Yi ","Pin ","Hui ","Tui ","Han ","Ying ","Ying ","Ke ","Ti ","Yong ","E ","Zhuan ","Yan ","E ","Nie ","Man ","Dian ","Sang ","Hao ","Lei ","Zhan ","Ru ","Pin ","Quan ","Feng ","Biao ","Oroshi ","Fu ","Xia ","Zhan ","Biao ","Sa ","Ba ","Tai ","Lie ","Gua ","Xuan ","Shao ","Ju ","Bi ","Si ","Wei ","Yang ","Yao ","Sou ","Kai ","Sao ","Fan ","Liu ","Xi ","Liao ","Piao ","Piao ","Liu ","Biao ","Biao ","Biao ","Liao ","[?] ","Se ","Feng ","Biao ","Feng ","Yang ","Zhan ","Biao ","Sa ","Ju ","Si ","Sou ","Yao ","Liu ","Piao ","Biao ","Biao ","Fei ","Fan ","Fei ","Fei ","Shi ","Shi ","Can ","Ji ","Ding ","Si ","Tuo ","Zhan ","Sun ","Xiang ","Tun ","Ren ","Yu ","Juan ","Chi ","Yin ","Fan ","Fan ","Sun ","Yin ","Zhu ","Yi ","Zhai ","Bi ","Jie ","Tao ","Liu ","Ci ","Tie ","Si ","Bao ","Shi ","Duo "]});var l7=m((s4e,a7)=>{a7.exports=["Hai ","Ren ","Tian ","Jiao ","Jia ","Bing ","Yao ","Tong ","Ci ","Xiang ","Yang ","Yang ","Er ","Yan ","Le ","Yi ","Can ","Bo ","Nei ","E ","Bu ","Jun ","Dou ","Su ","Yu ","Shi ","Yao ","Hun ","Guo ","Shi ","Jian ","Zhui ","Bing ","Xian ","Bu ","Ye ","Tan ","Fei ","Zhang ","Wei ","Guan ","E ","Nuan ","Hun ","Hu ","Huang ","Tie ","Hui ","Jian ","Hou ","He ","Xing ","Fen ","Wei ","Gu ","Cha ","Song ","Tang ","Bo ","Gao ","Xi ","Kui ","Liu ","Sou ","Tao ","Ye ","Yun ","Mo ","Tang ","Man ","Bi ","Yu ","Xiu ","Jin ","San ","Kui ","Zhuan ","Shan ","Chi ","Dan ","Yi ","Ji ","Rao ","Cheng ","Yong ","Tao ","Hui ","Xiang ","Zhan ","Fen ","Hai ","Meng ","Yan ","Mo ","Chan ","Xiang ","Luo ","Zuan ","Nang ","Shi ","Ding ","Ji ","Tuo ","Xing ","Tun ","Xi ","Ren ","Yu ","Chi ","Fan ","Yin ","Jian ","Shi ","Bao ","Si ","Duo ","Yi ","Er ","Rao ","Xiang ","Jia ","Le ","Jiao ","Yi ","Bing ","Bo ","Dou ","E ","Yu ","Nei ","Jun ","Guo ","Hun ","Xian ","Guan ","Cha ","Kui ","Gu ","Sou ","Chan ","Ye ","Mo ","Bo ","Liu ","Xiu ","Jin ","Man ","San ","Zhuan ","Nang ","Shou ","Kui ","Guo ","Xiang ","Fen ","Ba ","Ni ","Bi ","Bo ","Tu ","Han ","Fei ","Jian ","An ","Ai ","Fu ","Xian ","Wen ","Xin ","Fen ","Bin ","Xing ","Ma ","Yu ","Feng ","Han ","Di ","Tuo ","Tuo ","Chi ","Xun ","Zhu ","Zhi ","Pei ","Xin ","Ri ","Sa ","Yin ","Wen ","Zhi ","Dan ","Lu ","You ","Bo ","Bao ","Kuai ","Tuo ","Yi ","Qu ","[?] ","Qu ","Jiong ","Bo ","Zhao ","Yuan ","Peng ","Zhou ","Ju ","Zhu ","Nu ","Ju ","Pi ","Zang ","Jia ","Ling ","Zhen ","Tai ","Fu ","Yang ","Shi ","Bi ","Tuo ","Tuo ","Si ","Liu ","Ma ","Pian ","Tao ","Zhi ","Rong ","Teng ","Dong ","Xun ","Quan ","Shen ","Jiong ","Er ","Hai ","Bo ","Zhu ","Yin ","Luo ","Shuu ","Dan ","Xie ","Liu ","Ju ","Song ","Qin ","Mang ","Liang ","Han ","Tu ","Xuan ","Tui ","Jun "]});var c7=m((a4e,u7)=>{u7.exports=["E ","Cheng ","Xin ","Ai ","Lu ","Zhui ","Zhou ","She ","Pian ","Kun ","Tao ","Lai ","Zong ","Ke ","Qi ","Qi ","Yan ","Fei ","Sao ","Yan ","Jie ","Yao ","Wu ","Pian ","Cong ","Pian ","Qian ","Fei ","Huang ","Jian ","Huo ","Yu ","Ti ","Quan ","Xia ","Zong ","Kui ","Rou ","Si ","Gua ","Tuo ","Kui ","Sou ","Qian ","Cheng ","Zhi ","Liu ","Pang ","Teng ","Xi ","Cao ","Du ","Yan ","Yuan ","Zou ","Sao ","Shan ","Li ","Zhi ","Shuang ","Lu ","Xi ","Luo ","Zhang ","Mo ","Ao ","Can ","Piao ","Cong ","Qu ","Bi ","Zhi ","Yu ","Xu ","Hua ","Bo ","Su ","Xiao ","Lin ","Chan ","Dun ","Liu ","Tuo ","Zeng ","Tan ","Jiao ","Tie ","Yan ","Luo ","Zhan ","Jing ","Yi ","Ye ","Tuo ","Bin ","Zou ","Yan ","Peng ","Lu ","Teng ","Xiang ","Ji ","Shuang ","Ju ","Xi ","Huan ","Li ","Biao ","Ma ","Yu ","Tuo ","Xun ","Chi ","Qu ","Ri ","Bo ","Lu ","Zang ","Shi ","Si ","Fu ","Ju ","Zou ","Zhu ","Tuo ","Nu ","Jia ","Yi ","Tai ","Xiao ","Ma ","Yin ","Jiao ","Hua ","Luo ","Hai ","Pian ","Biao ","Li ","Cheng ","Yan ","Xin ","Qin ","Jun ","Qi ","Qi ","Ke ","Zhui ","Zong ","Su ","Can ","Pian ","Zhi ","Kui ","Sao ","Wu ","Ao ","Liu ","Qian ","Shan ","Piao ","Luo ","Cong ","Chan ","Zou ","Ji ","Shuang ","Xiang ","Gu ","Wei ","Wei ","Wei ","Yu ","Gan ","Yi ","Ang ","Tou ","Xie ","Bao ","Bi ","Chi ","Ti ","Di ","Ku ","Hai ","Qiao ","Gou ","Kua ","Ge ","Tui ","Geng ","Pian ","Bi ","Ke ","Ka ","Yu ","Sui ","Lou ","Bo ","Xiao ","Pang ","Bo ","Ci ","Kuan ","Bin ","Mo ","Liao ","Lou ","Nao ","Du ","Zang ","Sui ","Ti ","Bin ","Kuan ","Lu ","Gao ","Gao ","Qiao ","Kao ","Qiao ","Lao ","Zao ","Biao ","Kun ","Kun ","Ti ","Fang ","Xiu ","Ran ","Mao ","Dan ","Kun ","Bin ","Fa ","Tiao ","Peng ","Zi ","Fa ","Ran ","Ti ","Pao ","Pi ","Mao ","Fu ","Er ","Rong ","Qu ","Gong ","Xiu ","Gua ","Ji ","Peng ","Zhua ","Shao ","Sha "]});var d7=m((l4e,h7)=>{h7.exports=["Ti ","Li ","Bin ","Zong ","Ti ","Peng ","Song ","Zheng ","Quan ","Zong ","Shun ","Jian ","Duo ","Hu ","La ","Jiu ","Qi ","Lian ","Zhen ","Bin ","Peng ","Mo ","San ","Man ","Man ","Seng ","Xu ","Lie ","Qian ","Qian ","Nong ","Huan ","Kuai ","Ning ","Bin ","Lie ","Rang ","Dou ","Dou ","Nao ","Hong ","Xi ","Dou ","Han ","Dou ","Dou ","Jiu ","Chang ","Yu ","Yu ","Li ","Juan ","Fu ","Qian ","Gui ","Zong ","Liu ","Gui ","Shang ","Yu ","Gui ","Mei ","Ji ","Qi ","Jie ","Kui ","Hun ","Ba ","Po ","Mei ","Xu ","Yan ","Xiao ","Liang ","Yu ","Tui ","Qi ","Wang ","Liang ","Wei ","Jian ","Chi ","Piao ","Bi ","Mo ","Ji ","Xu ","Chou ","Yan ","Zhan ","Yu ","Dao ","Ren ","Ji ","Eri ","Gong ","Tuo ","Diao ","Ji ","Xu ","E ","E ","Sha ","Hang ","Tun ","Mo ","Jie ","Shen ","Fan ","Yuan ","Bi ","Lu ","Wen ","Hu ","Lu ","Za ","Fang ","Fen ","Na ","You ","Namazu ","Todo ","He ","Xia ","Qu ","Han ","Pi ","Ling ","Tuo ","Bo ","Qiu ","Ping ","Fu ","Bi ","Ji ","Wei ","Ju ","Diao ","Bo ","You ","Gun ","Pi ","Nian ","Xing ","Tai ","Bao ","Fu ","Zha ","Ju ","Gu ","Kajika ","Tong ","[?] ","Ta ","Jie ","Shu ","Hou ","Xiang ","Er ","An ","Wei ","Tiao ","Zhu ","Yin ","Lie ","Luo ","Tong ","Yi ","Qi ","Bing ","Wei ","Jiao ","Bu ","Gui ","Xian ","Ge ","Hui ","Bora ","Mate ","Kao ","Gori ","Duo ","Jun ","Ti ","Man ","Xiao ","Za ","Sha ","Qin ","Yu ","Nei ","Zhe ","Gun ","Geng ","Su ","Wu ","Qiu ","Ting ","Fu ","Wan ","You ","Li ","Sha ","Sha ","Gao ","Meng ","Ugui ","Asari ","Subashiri ","Kazunoko ","Yong ","Ni ","Zi ","Qi ","Qing ","Xiang ","Nei ","Chun ","Ji ","Diao ","Qie ","Gu ","Zhou ","Dong ","Lai ","Fei ","Ni ","Yi ","Kun ","Lu ","Jiu ","Chang ","Jing ","Lun ","Ling ","Zou ","Li ","Meng ","Zong ","Zhi ","Nian ","Shachi ","Dojou ","Sukesou ","Shi ","Shen ","Hun ","Shi ","Hou ","Xing ","Zhu ","La ","Zong ","Ji ","Bian ","Bian "]});var f7=m((u4e,g7)=>{g7.exports=["Huan ","Quan ","Ze ","Wei ","Wei ","Yu ","Qun ","Rou ","Die ","Huang ","Lian ","Yan ","Qiu ","Qiu ","Jian ","Bi ","E ","Yang ","Fu ","Sai ","Jian ","Xia ","Tuo ","Hu ","Muroaji ","Ruo ","Haraka ","Wen ","Jian ","Hao ","Wu ","Fang ","Sao ","Liu ","Ma ","Shi ","Shi ","Yin ","Z ","Teng ","Ta ","Yao ","Ge ","Rong ","Qian ","Qi ","Wen ","Ruo ","Hatahata ","Lian ","Ao ","Le ","Hui ","Min ","Ji ","Tiao ","Qu ","Jian ","Sao ","Man ","Xi ","Qiu ","Biao ","Ji ","Ji ","Zhu ","Jiang ","Qiu ","Zhuan ","Yong ","Zhang ","Kang ","Xue ","Bie ","Jue ","Qu ","Xiang ","Bo ","Jiao ","Xun ","Su ","Huang ","Zun ","Shan ","Shan ","Fan ","Jue ","Lin ","Xun ","Miao ","Xi ","Eso ","Kyou ","Fen ","Guan ","Hou ","Kuai ","Zei ","Sao ","Zhan ","Gan ","Gui ","Sheng ","Li ","Chang ","Hatahata ","Shiira ","Mutsu ","Ru ","Ji ","Xu ","Huo ","Shiira ","Li ","Lie ","Li ","Mie ","Zhen ","Xiang ","E ","Lu ","Guan ","Li ","Xian ","Yu ","Dao ","Ji ","You ","Tun ","Lu ","Fang ","Ba ","He ","Bo ","Ping ","Nian ","Lu ","You ","Zha ","Fu ","Bo ","Bao ","Hou ","Pi ","Tai ","Gui ","Jie ","Kao ","Wei ","Er ","Tong ","Ze ","Hou ","Kuai ","Ji ","Jiao ","Xian ","Za ","Xiang ","Xun ","Geng ","Li ","Lian ","Jian ","Li ","Shi ","Tiao ","Gun ","Sha ","Wan ","Jun ","Ji ","Yong ","Qing ","Ling ","Qi ","Zou ","Fei ","Kun ","Chang ","Gu ","Ni ","Nian ","Diao ","Jing ","Shen ","Shi ","Zi ","Fen ","Die ","Bi ","Chang ","Shi ","Wen ","Wei ","Sai ","E ","Qiu ","Fu ","Huang ","Quan ","Jiang ","Bian ","Sao ","Ao ","Qi ","Ta ","Yin ","Yao ","Fang ","Jian ","Le ","Biao ","Xue ","Bie ","Man ","Min ","Yong ","Wei ","Xi ","Jue ","Shan ","Lin ","Zun ","Huo ","Gan ","Li ","Zhan ","Guan ","Niao ","Yi ","Fu ","Li ","Jiu ","Bu ","Yan ","Fu ","Diao ","Ji ","Feng ","Nio ","Gan ","Shi ","Feng ","Ming ","Bao ","Yuan ","Zhi ","Hu ","Qin ","Fu ","Fen ","Wen ","Jian ","Shi ","Yu "]});var m7=m((c4e,p7)=>{p7.exports=["Fou ","Yiao ","Jue ","Jue ","Pi ","Huan ","Zhen ","Bao ","Yan ","Ya ","Zheng ","Fang ","Feng ","Wen ","Ou ","Te ","Jia ","Nu ","Ling ","Mie ","Fu ","Tuo ","Wen ","Li ","Bian ","Zhi ","Ge ","Yuan ","Zi ","Qu ","Xiao ","Zhi ","Dan ","Ju ","You ","Gu ","Zhong ","Yu ","Yang ","Rong ","Ya ","Tie ","Yu ","Shigi ","Ying ","Zhui ","Wu ","Er ","Gua ","Ai ","Zhi ","Yan ","Heng ","Jiao ","Ji ","Lie ","Zhu ","Ren ","Yi ","Hong ","Luo ","Ru ","Mou ","Ge ","Ren ","Jiao ","Xiu ","Zhou ","Zhi ","Luo ","Chidori ","Toki ","Ten ","Luan ","Jia ","Ji ","Yu ","Huan ","Tuo ","Bu ","Wu ","Juan ","Yu ","Bo ","Xun ","Xun ","Bi ","Xi ","Jun ","Ju ","Tu ","Jing ","Ti ","E ","E ","Kuang ","Hu ","Wu ","Shen ","Lai ","Ikaruga ","Kakesu ","Lu ","Ping ","Shu ","Fu ","An ","Zhao ","Peng ","Qin ","Qian ","Bei ","Diao ","Lu ","Que ","Jian ","Ju ","Tu ","Ya ","Yuan ","Qi ","Li ","Ye ","Zhui ","Kong ","Zhui ","Kun ","Sheng ","Qi ","Jing ","Yi ","Yi ","Jing ","Zi ","Lai ","Dong ","Qi ","Chun ","Geng ","Ju ","Qu ","Isuka ","Kikuitadaki ","Ji ","Shu ","[?] ","Chi ","Miao ","Rou ","An ","Qiu ","Ti ","Hu ","Ti ","E ","Jie ","Mao ","Fu ","Chun ","Tu ","Yan ","He ","Yuan ","Pian ","Yun ","Mei ","Hu ","Ying ","Dun ","Mu ","Ju ","Tsugumi ","Cang ","Fang ","Gu ","Ying ","Yuan ","Xuan ","Weng ","Shi ","He ","Chu ","Tang ","Xia ","Ruo ","Liu ","Ji ","Gu ","Jian ","Zhun ","Han ","Zi ","Zi ","Ni ","Yao ","Yan ","Ji ","Li ","Tian ","Kou ","Ti ","Ti ","Ni ","Tu ","Ma ","Jiao ","Gao ","Tian ","Chen ","Li ","Zhuan ","Zhe ","Ao ","Yao ","Yi ","Ou ","Chi ","Zhi ","Liao ","Rong ","Lou ","Bi ","Shuang ","Zhuo ","Yu ","Wu ","Jue ","Yin ","Quan ","Si ","Jiao ","Yi ","Hua ","Bi ","Ying ","Su ","Huang ","Fan ","Jiao ","Liao ","Yan ","Kao ","Jiu ","Xian ","Xian ","Tu ","Mai ","Zun ","Yu ","Ying ","Lu ","Tuan ","Xian ","Xue ","Yi ","Pi "]});var y7=m((h4e,b7)=>{b7.exports=["Shu ","Luo ","Qi ","Yi ","Ji ","Zhe ","Yu ","Zhan ","Ye ","Yang ","Pi ","Ning ","Huo ","Mi ","Ying ","Meng ","Di ","Yue ","Yu ","Lei ","Bao ","Lu ","He ","Long ","Shuang ","Yue ","Ying ","Guan ","Qu ","Li ","Luan ","Niao ","Jiu ","Ji ","Yuan ","Ming ","Shi ","Ou ","Ya ","Cang ","Bao ","Zhen ","Gu ","Dong ","Lu ","Ya ","Xiao ","Yang ","Ling ","Zhi ","Qu ","Yuan ","Xue ","Tuo ","Si ","Zhi ","Er ","Gua ","Xiu ","Heng ","Zhou ","Ge ","Luan ","Hong ","Wu ","Bo ","Li ","Juan ","Hu ","E ","Yu ","Xian ","Ti ","Wu ","Que ","Miao ","An ","Kun ","Bei ","Peng ","Qian ","Chun ","Geng ","Yuan ","Su ","Hu ","He ","E ","Gu ","Qiu ","Zi ","Mei ","Mu ","Ni ","Yao ","Weng ","Liu ","Ji ","Ni ","Jian ","He ","Yi ","Ying ","Zhe ","Liao ","Liao ","Jiao ","Jiu ","Yu ","Lu ","Xuan ","Zhan ","Ying ","Huo ","Meng ","Guan ","Shuang ","Lu ","Jin ","Ling ","Jian ","Xian ","Cuo ","Jian ","Jian ","Yan ","Cuo ","Lu ","You ","Cu ","Ji ","Biao ","Cu ","Biao ","Zhu ","Jun ","Zhu ","Jian ","Mi ","Mi ","Wu ","Liu ","Chen ","Jun ","Lin ","Ni ","Qi ","Lu ","Jiu ","Jun ","Jing ","Li ","Xiang ","Yan ","Jia ","Mi ","Li ","She ","Zhang ","Lin ","Jing ","Ji ","Ling ","Yan ","Cu ","Mai ","Mai ","Ge ","Chao ","Fu ","Mian ","Mian ","Fu ","Pao ","Qu ","Qu ","Mou ","Fu ","Xian ","Lai ","Qu ","Mian ","[?] ","Feng ","Fu ","Qu ","Mian ","Ma ","Mo ","Mo ","Hui ","Ma ","Zou ","Nen ","Fen ","Huang ","Huang ","Jin ","Guang ","Tian ","Tou ","Heng ","Xi ","Kuang ","Heng ","Shu ","Li ","Nian ","Chi ","Hei ","Hei ","Yi ","Qian ","Dan ","Xi ","Tuan ","Mo ","Mo ","Qian ","Dai ","Chu ","You ","Dian ","Yi ","Xia ","Yan ","Qu ","Mei ","Yan ","Jing ","Yu ","Li ","Dang ","Du ","Can ","Yin ","An ","Yan ","Tan ","An ","Zhen ","Dai ","Can ","Yi ","Mei ","Dan ","Yan ","Du ","Lu ","Zhi ","Fen ","Fu ","Fu ","Min ","Min ","Yuan "]});var w7=m((d4e,v7)=>{v7.exports=["Cu ","Qu ","Chao ","Wa ","Zhu ","Zhi ","Mang ","Ao ","Bie ","Tuo ","Bi ","Yuan ","Chao ","Tuo ","Ding ","Mi ","Nai ","Ding ","Zi ","Gu ","Gu ","Dong ","Fen ","Tao ","Yuan ","Pi ","Chang ","Gao ","Qi ","Yuan ","Tang ","Teng ","Shu ","Shu ","Fen ","Fei ","Wen ","Ba ","Diao ","Tuo ","Tong ","Qu ","Sheng ","Shi ","You ","Shi ","Ting ","Wu ","Nian ","Jing ","Hun ","Ju ","Yan ","Tu ","Ti ","Xi ","Xian ","Yan ","Lei ","Bi ","Yao ","Qiu ","Han ","Wu ","Wu ","Hou ","Xi ","Ge ","Zha ","Xiu ","Weng ","Zha ","Nong ","Nang ","Qi ","Zhai ","Ji ","Zi ","Ji ","Ji ","Qi ","Ji ","Chi ","Chen ","Chen ","He ","Ya ","Ken ","Xie ","Pao ","Cuo ","Shi ","Zi ","Chi ","Nian ","Ju ","Tiao ","Ling ","Ling ","Chu ","Quan ","Xie ","Ken ","Nie ","Jiu ","Yao ","Chuo ","Kun ","Yu ","Chu ","Yi ","Ni ","Cuo ","Zou ","Qu ","Nen ","Xian ","Ou ","E ","Wo ","Yi ","Chuo ","Zou ","Dian ","Chu ","Jin ","Ya ","Chi ","Chen ","He ","Ken ","Ju ","Ling ","Pao ","Tiao ","Zi ","Ken ","Yu ","Chuo ","Qu ","Wo ","Long ","Pang ","Gong ","Pang ","Yan ","Long ","Long ","Gong ","Kan ","Ta ","Ling ","Ta ","Long ","Gong ","Kan ","Gui ","Qiu ","Bie ","Gui ","Yue ","Chui ","He ","Jue ","Xie ","Yu ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var x7=m((g4e,D7)=>{D7.exports=["it","ix","i","ip","iet","iex","ie","iep","at","ax","a","ap","uox","uo","uop","ot","ox","o","op","ex","e","wu","bit","bix","bi","bip","biet","biex","bie","biep","bat","bax","ba","bap","buox","buo","buop","bot","box","bo","bop","bex","be","bep","but","bux","bu","bup","burx","bur","byt","byx","by","byp","byrx","byr","pit","pix","pi","pip","piex","pie","piep","pat","pax","pa","pap","puox","puo","puop","pot","pox","po","pop","put","pux","pu","pup","purx","pur","pyt","pyx","py","pyp","pyrx","pyr","bbit","bbix","bbi","bbip","bbiet","bbiex","bbie","bbiep","bbat","bbax","bba","bbap","bbuox","bbuo","bbuop","bbot","bbox","bbo","bbop","bbex","bbe","bbep","bbut","bbux","bbu","bbup","bburx","bbur","bbyt","bbyx","bby","bbyp","nbit","nbix","nbi","nbip","nbiex","nbie","nbiep","nbat","nbax","nba","nbap","nbot","nbox","nbo","nbop","nbut","nbux","nbu","nbup","nburx","nbur","nbyt","nbyx","nby","nbyp","nbyrx","nbyr","hmit","hmix","hmi","hmip","hmiex","hmie","hmiep","hmat","hmax","hma","hmap","hmuox","hmuo","hmuop","hmot","hmox","hmo","hmop","hmut","hmux","hmu","hmup","hmurx","hmur","hmyx","hmy","hmyp","hmyrx","hmyr","mit","mix","mi","mip","miex","mie","miep","mat","max","ma","map","muot","muox","muo","muop","mot","mox","mo","mop","mex","me","mut","mux","mu","mup","murx","mur","myt","myx","my","myp","fit","fix","fi","fip","fat","fax","fa","fap","fox","fo","fop","fut","fux","fu","fup","furx","fur","fyt","fyx","fy","fyp","vit","vix","vi","vip","viet","viex","vie","viep","vat","vax","va","vap","vot","vox","vo","vop","vex","vep","vut","vux","vu","vup","vurx","vur","vyt","vyx","vy","vyp","vyrx","vyr"]});var S7=m((f4e,C7)=>{C7.exports=["dit","dix","di","dip","diex","die","diep","dat","dax","da","dap","duox","duo","dot","dox","do","dop","dex","de","dep","dut","dux","du","dup","durx","dur","tit","tix","ti","tip","tiex","tie","tiep","tat","tax","ta","tap","tuot","tuox","tuo","tuop","tot","tox","to","top","tex","te","tep","tut","tux","tu","tup","turx","tur","ddit","ddix","ddi","ddip","ddiex","ddie","ddiep","ddat","ddax","dda","ddap","dduox","dduo","dduop","ddot","ddox","ddo","ddop","ddex","dde","ddep","ddut","ddux","ddu","ddup","ddurx","ddur","ndit","ndix","ndi","ndip","ndiex","ndie","ndat","ndax","nda","ndap","ndot","ndox","ndo","ndop","ndex","nde","ndep","ndut","ndux","ndu","ndup","ndurx","ndur","hnit","hnix","hni","hnip","hniet","hniex","hnie","hniep","hnat","hnax","hna","hnap","hnuox","hnuo","hnot","hnox","hnop","hnex","hne","hnep","hnut","nit","nix","ni","nip","niex","nie","niep","nax","na","nap","nuox","nuo","nuop","not","nox","no","nop","nex","ne","nep","nut","nux","nu","nup","nurx","nur","hlit","hlix","hli","hlip","hliex","hlie","hliep","hlat","hlax","hla","hlap","hluox","hluo","hluop","hlox","hlo","hlop","hlex","hle","hlep","hlut","hlux","hlu","hlup","hlurx","hlur","hlyt","hlyx","hly","hlyp","hlyrx","hlyr","lit","lix","li","lip","liet","liex","lie","liep","lat","lax","la","lap","luot","luox","luo","luop","lot","lox","lo","lop","lex","le","lep","lut","lux","lu","lup","lurx","lur","lyt","lyx","ly","lyp","lyrx","lyr","git","gix","gi","gip","giet","giex","gie","giep","gat","gax","ga","gap","guot","guox","guo","guop","got","gox","go","gop","get","gex","ge","gep","gut","gux","gu","gup","gurx","gur","kit","kix","ki","kip","kiex","kie","kiep","kat"]});var k7=m((p4e,T7)=>{T7.exports=["kax","ka","kap","kuox","kuo","kuop","kot","kox","ko","kop","ket","kex","ke","kep","kut","kux","ku","kup","kurx","kur","ggit","ggix","ggi","ggiex","ggie","ggiep","ggat","ggax","gga","ggap","gguot","gguox","gguo","gguop","ggot","ggox","ggo","ggop","gget","ggex","gge","ggep","ggut","ggux","ggu","ggup","ggurx","ggur","mgiex","mgie","mgat","mgax","mga","mgap","mguox","mguo","mguop","mgot","mgox","mgo","mgop","mgex","mge","mgep","mgut","mgux","mgu","mgup","mgurx","mgur","hxit","hxix","hxi","hxip","hxiet","hxiex","hxie","hxiep","hxat","hxax","hxa","hxap","hxuot","hxuox","hxuo","hxuop","hxot","hxox","hxo","hxop","hxex","hxe","hxep","ngiex","ngie","ngiep","ngat","ngax","nga","ngap","nguot","nguox","nguo","ngot","ngox","ngo","ngop","ngex","nge","ngep","hit","hiex","hie","hat","hax","ha","hap","huot","huox","huo","huop","hot","hox","ho","hop","hex","he","hep","wat","wax","wa","wap","wuox","wuo","wuop","wox","wo","wop","wex","we","wep","zit","zix","zi","zip","ziex","zie","ziep","zat","zax","za","zap","zuox","zuo","zuop","zot","zox","zo","zop","zex","ze","zep","zut","zux","zu","zup","zurx","zur","zyt","zyx","zy","zyp","zyrx","zyr","cit","cix","ci","cip","ciet","ciex","cie","ciep","cat","cax","ca","cap","cuox","cuo","cuop","cot","cox","co","cop","cex","ce","cep","cut","cux","cu","cup","curx","cur","cyt","cyx","cy","cyp","cyrx","cyr","zzit","zzix","zzi","zzip","zziet","zziex","zzie","zziep","zzat","zzax","zza","zzap","zzox","zzo","zzop","zzex","zze","zzep","zzux","zzu","zzup","zzurx","zzur","zzyt","zzyx","zzy","zzyp","zzyrx","zzyr","nzit","nzix","nzi","nzip","nziex","nzie","nziep","nzat","nzax","nza","nzap","nzuox","nzuo","nzox","nzop","nzex","nze","nzux","nzu"]});var P7=m((m4e,E7)=>{E7.exports=["nzup","nzurx","nzur","nzyt","nzyx","nzy","nzyp","nzyrx","nzyr","sit","six","si","sip","siex","sie","siep","sat","sax","sa","sap","suox","suo","suop","sot","sox","so","sop","sex","se","sep","sut","sux","su","sup","surx","sur","syt","syx","sy","syp","syrx","syr","ssit","ssix","ssi","ssip","ssiex","ssie","ssiep","ssat","ssax","ssa","ssap","ssot","ssox","sso","ssop","ssex","sse","ssep","ssut","ssux","ssu","ssup","ssyt","ssyx","ssy","ssyp","ssyrx","ssyr","zhat","zhax","zha","zhap","zhuox","zhuo","zhuop","zhot","zhox","zho","zhop","zhet","zhex","zhe","zhep","zhut","zhux","zhu","zhup","zhurx","zhur","zhyt","zhyx","zhy","zhyp","zhyrx","zhyr","chat","chax","cha","chap","chuot","chuox","chuo","chuop","chot","chox","cho","chop","chet","chex","che","chep","chux","chu","chup","churx","chur","chyt","chyx","chy","chyp","chyrx","chyr","rrax","rra","rruox","rruo","rrot","rrox","rro","rrop","rret","rrex","rre","rrep","rrut","rrux","rru","rrup","rrurx","rrur","rryt","rryx","rry","rryp","rryrx","rryr","nrat","nrax","nra","nrap","nrox","nro","nrop","nret","nrex","nre","nrep","nrut","nrux","nru","nrup","nrurx","nrur","nryt","nryx","nry","nryp","nryrx","nryr","shat","shax","sha","shap","shuox","shuo","shuop","shot","shox","sho","shop","shet","shex","she","shep","shut","shux","shu","shup","shurx","shur","shyt","shyx","shy","shyp","shyrx","shyr","rat","rax","ra","rap","ruox","ruo","ruop","rot","rox","ro","rop","rex","re","rep","rut","rux","ru","rup","rurx","rur","ryt","ryx","ry","ryp","ryrx","ryr","jit","jix","ji","jip","jiet","jiex","jie","jiep","juot","juox","juo","juop","jot","jox","jo","jop","jut","jux","ju","jup","jurx","jur","jyt","jyx","jy","jyp","jyrx","jyr","qit","qix","qi","qip"]});var R7=m((b4e,_7)=>{_7.exports=["qiet","qiex","qie","qiep","quot","quox","quo","quop","qot","qox","qo","qop","qut","qux","qu","qup","qurx","qur","qyt","qyx","qy","qyp","qyrx","qyr","jjit","jjix","jji","jjip","jjiet","jjiex","jjie","jjiep","jjuox","jjuo","jjuop","jjot","jjox","jjo","jjop","jjut","jjux","jju","jjup","jjurx","jjur","jjyt","jjyx","jjy","jjyp","njit","njix","nji","njip","njiet","njiex","njie","njiep","njuox","njuo","njot","njox","njo","njop","njux","nju","njup","njurx","njur","njyt","njyx","njy","njyp","njyrx","njyr","nyit","nyix","nyi","nyip","nyiet","nyiex","nyie","nyiep","nyuox","nyuo","nyuop","nyot","nyox","nyo","nyop","nyut","nyux","nyu","nyup","xit","xix","xi","xip","xiet","xiex","xie","xiep","xuox","xuo","xot","xox","xo","xop","xyt","xyx","xy","xyp","xyrx","xyr","yit","yix","yi","yip","yiet","yiex","yie","yiep","yuot","yuox","yuo","yuop","yot","yox","yo","yop","yut","yux","yu","yup","yurx","yur","yyt","yyx","yy","yyp","yyrx","yyr","[?]","[?]","[?]","Qot","Li","Kit","Nyip","Cyp","Ssi","Ggop","Gep","Mi","Hxit","Lyr","Bbut","Mop","Yo","Put","Hxuo","Tat","Ga","[?]","[?]","Ddur","Bur","Gguo","Nyop","Tu","Op","Jjut","Zot","Pyt","Hmo","Yit","Vur","Shy","Vep","Za","Jo","[?]","Jjy","Got","Jjie","Wo","Du","Shur","Lie","Cy","Cuop","Cip","Hxop","Shat","[?]","Shop","Che","Zziet","[?]","Ke","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var F7=m((y4e,L7)=>{L7.exports=["ga","gag","gagg","gags","gan","ganj","ganh","gad","gal","galg","galm","galb","gals","galt","galp","galh","gam","gab","gabs","gas","gass","gang","gaj","gac","gak","gat","gap","gah","gae","gaeg","gaegg","gaegs","gaen","gaenj","gaenh","gaed","gael","gaelg","gaelm","gaelb","gaels","gaelt","gaelp","gaelh","gaem","gaeb","gaebs","gaes","gaess","gaeng","gaej","gaec","gaek","gaet","gaep","gaeh","gya","gyag","gyagg","gyags","gyan","gyanj","gyanh","gyad","gyal","gyalg","gyalm","gyalb","gyals","gyalt","gyalp","gyalh","gyam","gyab","gyabs","gyas","gyass","gyang","gyaj","gyac","gyak","gyat","gyap","gyah","gyae","gyaeg","gyaegg","gyaegs","gyaen","gyaenj","gyaenh","gyaed","gyael","gyaelg","gyaelm","gyaelb","gyaels","gyaelt","gyaelp","gyaelh","gyaem","gyaeb","gyaebs","gyaes","gyaess","gyaeng","gyaej","gyaec","gyaek","gyaet","gyaep","gyaeh","geo","geog","geogg","geogs","geon","geonj","geonh","geod","geol","geolg","geolm","geolb","geols","geolt","geolp","geolh","geom","geob","geobs","geos","geoss","geong","geoj","geoc","geok","geot","geop","geoh","ge","geg","gegg","gegs","gen","genj","genh","ged","gel","gelg","gelm","gelb","gels","gelt","gelp","gelh","gem","geb","gebs","ges","gess","geng","gej","gec","gek","get","gep","geh","gyeo","gyeog","gyeogg","gyeogs","gyeon","gyeonj","gyeonh","gyeod","gyeol","gyeolg","gyeolm","gyeolb","gyeols","gyeolt","gyeolp","gyeolh","gyeom","gyeob","gyeobs","gyeos","gyeoss","gyeong","gyeoj","gyeoc","gyeok","gyeot","gyeop","gyeoh","gye","gyeg","gyegg","gyegs","gyen","gyenj","gyenh","gyed","gyel","gyelg","gyelm","gyelb","gyels","gyelt","gyelp","gyelh","gyem","gyeb","gyebs","gyes","gyess","gyeng","gyej","gyec","gyek","gyet","gyep","gyeh","go","gog","gogg","gogs","gon","gonj","gonh","god","gol","golg","golm","golb","gols","golt","golp","golh","gom","gob","gobs","gos","goss","gong","goj","goc","gok","got","gop","goh","gwa","gwag","gwagg","gwags"]});var j7=m((v4e,I7)=>{I7.exports=["gwan","gwanj","gwanh","gwad","gwal","gwalg","gwalm","gwalb","gwals","gwalt","gwalp","gwalh","gwam","gwab","gwabs","gwas","gwass","gwang","gwaj","gwac","gwak","gwat","gwap","gwah","gwae","gwaeg","gwaegg","gwaegs","gwaen","gwaenj","gwaenh","gwaed","gwael","gwaelg","gwaelm","gwaelb","gwaels","gwaelt","gwaelp","gwaelh","gwaem","gwaeb","gwaebs","gwaes","gwaess","gwaeng","gwaej","gwaec","gwaek","gwaet","gwaep","gwaeh","goe","goeg","goegg","goegs","goen","goenj","goenh","goed","goel","goelg","goelm","goelb","goels","goelt","goelp","goelh","goem","goeb","goebs","goes","goess","goeng","goej","goec","goek","goet","goep","goeh","gyo","gyog","gyogg","gyogs","gyon","gyonj","gyonh","gyod","gyol","gyolg","gyolm","gyolb","gyols","gyolt","gyolp","gyolh","gyom","gyob","gyobs","gyos","gyoss","gyong","gyoj","gyoc","gyok","gyot","gyop","gyoh","gu","gug","gugg","gugs","gun","gunj","gunh","gud","gul","gulg","gulm","gulb","guls","gult","gulp","gulh","gum","gub","gubs","gus","guss","gung","guj","guc","guk","gut","gup","guh","gweo","gweog","gweogg","gweogs","gweon","gweonj","gweonh","gweod","gweol","gweolg","gweolm","gweolb","gweols","gweolt","gweolp","gweolh","gweom","gweob","gweobs","gweos","gweoss","gweong","gweoj","gweoc","gweok","gweot","gweop","gweoh","gwe","gweg","gwegg","gwegs","gwen","gwenj","gwenh","gwed","gwel","gwelg","gwelm","gwelb","gwels","gwelt","gwelp","gwelh","gwem","gweb","gwebs","gwes","gwess","gweng","gwej","gwec","gwek","gwet","gwep","gweh","gwi","gwig","gwigg","gwigs","gwin","gwinj","gwinh","gwid","gwil","gwilg","gwilm","gwilb","gwils","gwilt","gwilp","gwilh","gwim","gwib","gwibs","gwis","gwiss","gwing","gwij","gwic","gwik","gwit","gwip","gwih","gyu","gyug","gyugg","gyugs","gyun","gyunj","gyunh","gyud","gyul","gyulg","gyulm","gyulb","gyuls","gyult","gyulp","gyulh","gyum","gyub","gyubs","gyus","gyuss","gyung","gyuj","gyuc","gyuk","gyut","gyup","gyuh","geu","geug","geugg","geugs","geun","geunj","geunh","geud"]});var O7=m((w4e,A7)=>{A7.exports=["geul","geulg","geulm","geulb","geuls","geult","geulp","geulh","geum","geub","geubs","geus","geuss","geung","geuj","geuc","geuk","geut","geup","geuh","gyi","gyig","gyigg","gyigs","gyin","gyinj","gyinh","gyid","gyil","gyilg","gyilm","gyilb","gyils","gyilt","gyilp","gyilh","gyim","gyib","gyibs","gyis","gyiss","gying","gyij","gyic","gyik","gyit","gyip","gyih","gi","gig","gigg","gigs","gin","ginj","ginh","gid","gil","gilg","gilm","gilb","gils","gilt","gilp","gilh","gim","gib","gibs","gis","giss","ging","gij","gic","gik","git","gip","gih","gga","ggag","ggagg","ggags","ggan","gganj","gganh","ggad","ggal","ggalg","ggalm","ggalb","ggals","ggalt","ggalp","ggalh","ggam","ggab","ggabs","ggas","ggass","ggang","ggaj","ggac","ggak","ggat","ggap","ggah","ggae","ggaeg","ggaegg","ggaegs","ggaen","ggaenj","ggaenh","ggaed","ggael","ggaelg","ggaelm","ggaelb","ggaels","ggaelt","ggaelp","ggaelh","ggaem","ggaeb","ggaebs","ggaes","ggaess","ggaeng","ggaej","ggaec","ggaek","ggaet","ggaep","ggaeh","ggya","ggyag","ggyagg","ggyags","ggyan","ggyanj","ggyanh","ggyad","ggyal","ggyalg","ggyalm","ggyalb","ggyals","ggyalt","ggyalp","ggyalh","ggyam","ggyab","ggyabs","ggyas","ggyass","ggyang","ggyaj","ggyac","ggyak","ggyat","ggyap","ggyah","ggyae","ggyaeg","ggyaegg","ggyaegs","ggyaen","ggyaenj","ggyaenh","ggyaed","ggyael","ggyaelg","ggyaelm","ggyaelb","ggyaels","ggyaelt","ggyaelp","ggyaelh","ggyaem","ggyaeb","ggyaebs","ggyaes","ggyaess","ggyaeng","ggyaej","ggyaec","ggyaek","ggyaet","ggyaep","ggyaeh","ggeo","ggeog","ggeogg","ggeogs","ggeon","ggeonj","ggeonh","ggeod","ggeol","ggeolg","ggeolm","ggeolb","ggeols","ggeolt","ggeolp","ggeolh","ggeom","ggeob","ggeobs","ggeos","ggeoss","ggeong","ggeoj","ggeoc","ggeok","ggeot","ggeop","ggeoh","gge","ggeg","ggegg","ggegs","ggen","ggenj","ggenh","gged","ggel","ggelg","ggelm","ggelb","ggels","ggelt","ggelp","ggelh","ggem","ggeb","ggebs","gges","ggess","ggeng","ggej","ggec","ggek","gget","ggep","ggeh","ggyeo","ggyeog","ggyeogg","ggyeogs","ggyeon","ggyeonj","ggyeonh","ggyeod","ggyeol","ggyeolg","ggyeolm","ggyeolb"]});var N7=m((D4e,M7)=>{M7.exports=["ggyeols","ggyeolt","ggyeolp","ggyeolh","ggyeom","ggyeob","ggyeobs","ggyeos","ggyeoss","ggyeong","ggyeoj","ggyeoc","ggyeok","ggyeot","ggyeop","ggyeoh","ggye","ggyeg","ggyegg","ggyegs","ggyen","ggyenj","ggyenh","ggyed","ggyel","ggyelg","ggyelm","ggyelb","ggyels","ggyelt","ggyelp","ggyelh","ggyem","ggyeb","ggyebs","ggyes","ggyess","ggyeng","ggyej","ggyec","ggyek","ggyet","ggyep","ggyeh","ggo","ggog","ggogg","ggogs","ggon","ggonj","ggonh","ggod","ggol","ggolg","ggolm","ggolb","ggols","ggolt","ggolp","ggolh","ggom","ggob","ggobs","ggos","ggoss","ggong","ggoj","ggoc","ggok","ggot","ggop","ggoh","ggwa","ggwag","ggwagg","ggwags","ggwan","ggwanj","ggwanh","ggwad","ggwal","ggwalg","ggwalm","ggwalb","ggwals","ggwalt","ggwalp","ggwalh","ggwam","ggwab","ggwabs","ggwas","ggwass","ggwang","ggwaj","ggwac","ggwak","ggwat","ggwap","ggwah","ggwae","ggwaeg","ggwaegg","ggwaegs","ggwaen","ggwaenj","ggwaenh","ggwaed","ggwael","ggwaelg","ggwaelm","ggwaelb","ggwaels","ggwaelt","ggwaelp","ggwaelh","ggwaem","ggwaeb","ggwaebs","ggwaes","ggwaess","ggwaeng","ggwaej","ggwaec","ggwaek","ggwaet","ggwaep","ggwaeh","ggoe","ggoeg","ggoegg","ggoegs","ggoen","ggoenj","ggoenh","ggoed","ggoel","ggoelg","ggoelm","ggoelb","ggoels","ggoelt","ggoelp","ggoelh","ggoem","ggoeb","ggoebs","ggoes","ggoess","ggoeng","ggoej","ggoec","ggoek","ggoet","ggoep","ggoeh","ggyo","ggyog","ggyogg","ggyogs","ggyon","ggyonj","ggyonh","ggyod","ggyol","ggyolg","ggyolm","ggyolb","ggyols","ggyolt","ggyolp","ggyolh","ggyom","ggyob","ggyobs","ggyos","ggyoss","ggyong","ggyoj","ggyoc","ggyok","ggyot","ggyop","ggyoh","ggu","ggug","ggugg","ggugs","ggun","ggunj","ggunh","ggud","ggul","ggulg","ggulm","ggulb","gguls","ggult","ggulp","ggulh","ggum","ggub","ggubs","ggus","gguss","ggung","gguj","gguc","gguk","ggut","ggup","gguh","ggweo","ggweog","ggweogg","ggweogs","ggweon","ggweonj","ggweonh","ggweod","ggweol","ggweolg","ggweolm","ggweolb","ggweols","ggweolt","ggweolp","ggweolh","ggweom","ggweob","ggweobs","ggweos","ggweoss","ggweong","ggweoj","ggweoc","ggweok","ggweot","ggweop","ggweoh","ggwe","ggweg","ggwegg","ggwegs","ggwen","ggwenj","ggwenh","ggwed","ggwel","ggwelg","ggwelm","ggwelb","ggwels","ggwelt","ggwelp","ggwelh"]});var H7=m((x4e,B7)=>{B7.exports=["ggwem","ggweb","ggwebs","ggwes","ggwess","ggweng","ggwej","ggwec","ggwek","ggwet","ggwep","ggweh","ggwi","ggwig","ggwigg","ggwigs","ggwin","ggwinj","ggwinh","ggwid","ggwil","ggwilg","ggwilm","ggwilb","ggwils","ggwilt","ggwilp","ggwilh","ggwim","ggwib","ggwibs","ggwis","ggwiss","ggwing","ggwij","ggwic","ggwik","ggwit","ggwip","ggwih","ggyu","ggyug","ggyugg","ggyugs","ggyun","ggyunj","ggyunh","ggyud","ggyul","ggyulg","ggyulm","ggyulb","ggyuls","ggyult","ggyulp","ggyulh","ggyum","ggyub","ggyubs","ggyus","ggyuss","ggyung","ggyuj","ggyuc","ggyuk","ggyut","ggyup","ggyuh","ggeu","ggeug","ggeugg","ggeugs","ggeun","ggeunj","ggeunh","ggeud","ggeul","ggeulg","ggeulm","ggeulb","ggeuls","ggeult","ggeulp","ggeulh","ggeum","ggeub","ggeubs","ggeus","ggeuss","ggeung","ggeuj","ggeuc","ggeuk","ggeut","ggeup","ggeuh","ggyi","ggyig","ggyigg","ggyigs","ggyin","ggyinj","ggyinh","ggyid","ggyil","ggyilg","ggyilm","ggyilb","ggyils","ggyilt","ggyilp","ggyilh","ggyim","ggyib","ggyibs","ggyis","ggyiss","ggying","ggyij","ggyic","ggyik","ggyit","ggyip","ggyih","ggi","ggig","ggigg","ggigs","ggin","gginj","gginh","ggid","ggil","ggilg","ggilm","ggilb","ggils","ggilt","ggilp","ggilh","ggim","ggib","ggibs","ggis","ggiss","gging","ggij","ggic","ggik","ggit","ggip","ggih","na","nag","nagg","nags","nan","nanj","nanh","nad","nal","nalg","nalm","nalb","nals","nalt","nalp","nalh","nam","nab","nabs","nas","nass","nang","naj","nac","nak","nat","nap","nah","nae","naeg","naegg","naegs","naen","naenj","naenh","naed","nael","naelg","naelm","naelb","naels","naelt","naelp","naelh","naem","naeb","naebs","naes","naess","naeng","naej","naec","naek","naet","naep","naeh","nya","nyag","nyagg","nyags","nyan","nyanj","nyanh","nyad","nyal","nyalg","nyalm","nyalb","nyals","nyalt","nyalp","nyalh","nyam","nyab","nyabs","nyas","nyass","nyang","nyaj","nyac","nyak","nyat","nyap","nyah","nyae","nyaeg","nyaegg","nyaegs","nyaen","nyaenj","nyaenh","nyaed","nyael","nyaelg","nyaelm","nyaelb","nyaels","nyaelt","nyaelp","nyaelh","nyaem","nyaeb","nyaebs","nyaes"]});var Y7=m((C4e,q7)=>{q7.exports=["nyaess","nyaeng","nyaej","nyaec","nyaek","nyaet","nyaep","nyaeh","neo","neog","neogg","neogs","neon","neonj","neonh","neod","neol","neolg","neolm","neolb","neols","neolt","neolp","neolh","neom","neob","neobs","neos","neoss","neong","neoj","neoc","neok","neot","neop","neoh","ne","neg","negg","negs","nen","nenj","nenh","ned","nel","nelg","nelm","nelb","nels","nelt","nelp","nelh","nem","neb","nebs","nes","ness","neng","nej","nec","nek","net","nep","neh","nyeo","nyeog","nyeogg","nyeogs","nyeon","nyeonj","nyeonh","nyeod","nyeol","nyeolg","nyeolm","nyeolb","nyeols","nyeolt","nyeolp","nyeolh","nyeom","nyeob","nyeobs","nyeos","nyeoss","nyeong","nyeoj","nyeoc","nyeok","nyeot","nyeop","nyeoh","nye","nyeg","nyegg","nyegs","nyen","nyenj","nyenh","nyed","nyel","nyelg","nyelm","nyelb","nyels","nyelt","nyelp","nyelh","nyem","nyeb","nyebs","nyes","nyess","nyeng","nyej","nyec","nyek","nyet","nyep","nyeh","no","nog","nogg","nogs","non","nonj","nonh","nod","nol","nolg","nolm","nolb","nols","nolt","nolp","nolh","nom","nob","nobs","nos","noss","nong","noj","noc","nok","not","nop","noh","nwa","nwag","nwagg","nwags","nwan","nwanj","nwanh","nwad","nwal","nwalg","nwalm","nwalb","nwals","nwalt","nwalp","nwalh","nwam","nwab","nwabs","nwas","nwass","nwang","nwaj","nwac","nwak","nwat","nwap","nwah","nwae","nwaeg","nwaegg","nwaegs","nwaen","nwaenj","nwaenh","nwaed","nwael","nwaelg","nwaelm","nwaelb","nwaels","nwaelt","nwaelp","nwaelh","nwaem","nwaeb","nwaebs","nwaes","nwaess","nwaeng","nwaej","nwaec","nwaek","nwaet","nwaep","nwaeh","noe","noeg","noegg","noegs","noen","noenj","noenh","noed","noel","noelg","noelm","noelb","noels","noelt","noelp","noelh","noem","noeb","noebs","noes","noess","noeng","noej","noec","noek","noet","noep","noeh","nyo","nyog","nyogg","nyogs","nyon","nyonj","nyonh","nyod","nyol","nyolg","nyolm","nyolb","nyols","nyolt","nyolp","nyolh","nyom","nyob","nyobs","nyos","nyoss","nyong","nyoj","nyoc"]});var Z7=m((S4e,W7)=>{W7.exports=["nyok","nyot","nyop","nyoh","nu","nug","nugg","nugs","nun","nunj","nunh","nud","nul","nulg","nulm","nulb","nuls","nult","nulp","nulh","num","nub","nubs","nus","nuss","nung","nuj","nuc","nuk","nut","nup","nuh","nweo","nweog","nweogg","nweogs","nweon","nweonj","nweonh","nweod","nweol","nweolg","nweolm","nweolb","nweols","nweolt","nweolp","nweolh","nweom","nweob","nweobs","nweos","nweoss","nweong","nweoj","nweoc","nweok","nweot","nweop","nweoh","nwe","nweg","nwegg","nwegs","nwen","nwenj","nwenh","nwed","nwel","nwelg","nwelm","nwelb","nwels","nwelt","nwelp","nwelh","nwem","nweb","nwebs","nwes","nwess","nweng","nwej","nwec","nwek","nwet","nwep","nweh","nwi","nwig","nwigg","nwigs","nwin","nwinj","nwinh","nwid","nwil","nwilg","nwilm","nwilb","nwils","nwilt","nwilp","nwilh","nwim","nwib","nwibs","nwis","nwiss","nwing","nwij","nwic","nwik","nwit","nwip","nwih","nyu","nyug","nyugg","nyugs","nyun","nyunj","nyunh","nyud","nyul","nyulg","nyulm","nyulb","nyuls","nyult","nyulp","nyulh","nyum","nyub","nyubs","nyus","nyuss","nyung","nyuj","nyuc","nyuk","nyut","nyup","nyuh","neu","neug","neugg","neugs","neun","neunj","neunh","neud","neul","neulg","neulm","neulb","neuls","neult","neulp","neulh","neum","neub","neubs","neus","neuss","neung","neuj","neuc","neuk","neut","neup","neuh","nyi","nyig","nyigg","nyigs","nyin","nyinj","nyinh","nyid","nyil","nyilg","nyilm","nyilb","nyils","nyilt","nyilp","nyilh","nyim","nyib","nyibs","nyis","nyiss","nying","nyij","nyic","nyik","nyit","nyip","nyih","ni","nig","nigg","nigs","nin","ninj","ninh","nid","nil","nilg","nilm","nilb","nils","nilt","nilp","nilh","nim","nib","nibs","nis","niss","ning","nij","nic","nik","nit","nip","nih","da","dag","dagg","dags","dan","danj","danh","dad","dal","dalg","dalm","dalb","dals","dalt","dalp","dalh","dam","dab","dabs","das","dass","dang","daj","dac","dak","dat","dap","dah"]});var $7=m((T4e,J7)=>{J7.exports=["dae","daeg","daegg","daegs","daen","daenj","daenh","daed","dael","daelg","daelm","daelb","daels","daelt","daelp","daelh","daem","daeb","daebs","daes","daess","daeng","daej","daec","daek","daet","daep","daeh","dya","dyag","dyagg","dyags","dyan","dyanj","dyanh","dyad","dyal","dyalg","dyalm","dyalb","dyals","dyalt","dyalp","dyalh","dyam","dyab","dyabs","dyas","dyass","dyang","dyaj","dyac","dyak","dyat","dyap","dyah","dyae","dyaeg","dyaegg","dyaegs","dyaen","dyaenj","dyaenh","dyaed","dyael","dyaelg","dyaelm","dyaelb","dyaels","dyaelt","dyaelp","dyaelh","dyaem","dyaeb","dyaebs","dyaes","dyaess","dyaeng","dyaej","dyaec","dyaek","dyaet","dyaep","dyaeh","deo","deog","deogg","deogs","deon","deonj","deonh","deod","deol","deolg","deolm","deolb","deols","deolt","deolp","deolh","deom","deob","deobs","deos","deoss","deong","deoj","deoc","deok","deot","deop","deoh","de","deg","degg","degs","den","denj","denh","ded","del","delg","delm","delb","dels","delt","delp","delh","dem","deb","debs","des","dess","deng","dej","dec","dek","det","dep","deh","dyeo","dyeog","dyeogg","dyeogs","dyeon","dyeonj","dyeonh","dyeod","dyeol","dyeolg","dyeolm","dyeolb","dyeols","dyeolt","dyeolp","dyeolh","dyeom","dyeob","dyeobs","dyeos","dyeoss","dyeong","dyeoj","dyeoc","dyeok","dyeot","dyeop","dyeoh","dye","dyeg","dyegg","dyegs","dyen","dyenj","dyenh","dyed","dyel","dyelg","dyelm","dyelb","dyels","dyelt","dyelp","dyelh","dyem","dyeb","dyebs","dyes","dyess","dyeng","dyej","dyec","dyek","dyet","dyep","dyeh","do","dog","dogg","dogs","don","donj","donh","dod","dol","dolg","dolm","dolb","dols","dolt","dolp","dolh","dom","dob","dobs","dos","doss","dong","doj","doc","dok","dot","dop","doh","dwa","dwag","dwagg","dwags","dwan","dwanj","dwanh","dwad","dwal","dwalg","dwalm","dwalb","dwals","dwalt","dwalp","dwalh","dwam","dwab","dwabs","dwas","dwass","dwang","dwaj","dwac","dwak","dwat","dwap","dwah","dwae","dwaeg","dwaegg","dwaegs"]});var U7=m((k4e,X7)=>{X7.exports=["dwaen","dwaenj","dwaenh","dwaed","dwael","dwaelg","dwaelm","dwaelb","dwaels","dwaelt","dwaelp","dwaelh","dwaem","dwaeb","dwaebs","dwaes","dwaess","dwaeng","dwaej","dwaec","dwaek","dwaet","dwaep","dwaeh","doe","doeg","doegg","doegs","doen","doenj","doenh","doed","doel","doelg","doelm","doelb","doels","doelt","doelp","doelh","doem","doeb","doebs","does","doess","doeng","doej","doec","doek","doet","doep","doeh","dyo","dyog","dyogg","dyogs","dyon","dyonj","dyonh","dyod","dyol","dyolg","dyolm","dyolb","dyols","dyolt","dyolp","dyolh","dyom","dyob","dyobs","dyos","dyoss","dyong","dyoj","dyoc","dyok","dyot","dyop","dyoh","du","dug","dugg","dugs","dun","dunj","dunh","dud","dul","dulg","dulm","dulb","duls","dult","dulp","dulh","dum","dub","dubs","dus","duss","dung","duj","duc","duk","dut","dup","duh","dweo","dweog","dweogg","dweogs","dweon","dweonj","dweonh","dweod","dweol","dweolg","dweolm","dweolb","dweols","dweolt","dweolp","dweolh","dweom","dweob","dweobs","dweos","dweoss","dweong","dweoj","dweoc","dweok","dweot","dweop","dweoh","dwe","dweg","dwegg","dwegs","dwen","dwenj","dwenh","dwed","dwel","dwelg","dwelm","dwelb","dwels","dwelt","dwelp","dwelh","dwem","dweb","dwebs","dwes","dwess","dweng","dwej","dwec","dwek","dwet","dwep","dweh","dwi","dwig","dwigg","dwigs","dwin","dwinj","dwinh","dwid","dwil","dwilg","dwilm","dwilb","dwils","dwilt","dwilp","dwilh","dwim","dwib","dwibs","dwis","dwiss","dwing","dwij","dwic","dwik","dwit","dwip","dwih","dyu","dyug","dyugg","dyugs","dyun","dyunj","dyunh","dyud","dyul","dyulg","dyulm","dyulb","dyuls","dyult","dyulp","dyulh","dyum","dyub","dyubs","dyus","dyuss","dyung","dyuj","dyuc","dyuk","dyut","dyup","dyuh","deu","deug","deugg","deugs","deun","deunj","deunh","deud","deul","deulg","deulm","deulb","deuls","deult","deulp","deulh","deum","deub","deubs","deus","deuss","deung","deuj","deuc","deuk","deut","deup","deuh","dyi","dyig","dyigg","dyigs","dyin","dyinj","dyinh","dyid"]});var Q7=m((E4e,G7)=>{G7.exports=["dyil","dyilg","dyilm","dyilb","dyils","dyilt","dyilp","dyilh","dyim","dyib","dyibs","dyis","dyiss","dying","dyij","dyic","dyik","dyit","dyip","dyih","di","dig","digg","digs","din","dinj","dinh","did","dil","dilg","dilm","dilb","dils","dilt","dilp","dilh","dim","dib","dibs","dis","diss","ding","dij","dic","dik","dit","dip","dih","dda","ddag","ddagg","ddags","ddan","ddanj","ddanh","ddad","ddal","ddalg","ddalm","ddalb","ddals","ddalt","ddalp","ddalh","ddam","ddab","ddabs","ddas","ddass","ddang","ddaj","ddac","ddak","ddat","ddap","ddah","ddae","ddaeg","ddaegg","ddaegs","ddaen","ddaenj","ddaenh","ddaed","ddael","ddaelg","ddaelm","ddaelb","ddaels","ddaelt","ddaelp","ddaelh","ddaem","ddaeb","ddaebs","ddaes","ddaess","ddaeng","ddaej","ddaec","ddaek","ddaet","ddaep","ddaeh","ddya","ddyag","ddyagg","ddyags","ddyan","ddyanj","ddyanh","ddyad","ddyal","ddyalg","ddyalm","ddyalb","ddyals","ddyalt","ddyalp","ddyalh","ddyam","ddyab","ddyabs","ddyas","ddyass","ddyang","ddyaj","ddyac","ddyak","ddyat","ddyap","ddyah","ddyae","ddyaeg","ddyaegg","ddyaegs","ddyaen","ddyaenj","ddyaenh","ddyaed","ddyael","ddyaelg","ddyaelm","ddyaelb","ddyaels","ddyaelt","ddyaelp","ddyaelh","ddyaem","ddyaeb","ddyaebs","ddyaes","ddyaess","ddyaeng","ddyaej","ddyaec","ddyaek","ddyaet","ddyaep","ddyaeh","ddeo","ddeog","ddeogg","ddeogs","ddeon","ddeonj","ddeonh","ddeod","ddeol","ddeolg","ddeolm","ddeolb","ddeols","ddeolt","ddeolp","ddeolh","ddeom","ddeob","ddeobs","ddeos","ddeoss","ddeong","ddeoj","ddeoc","ddeok","ddeot","ddeop","ddeoh","dde","ddeg","ddegg","ddegs","dden","ddenj","ddenh","dded","ddel","ddelg","ddelm","ddelb","ddels","ddelt","ddelp","ddelh","ddem","ddeb","ddebs","ddes","ddess","ddeng","ddej","ddec","ddek","ddet","ddep","ddeh","ddyeo","ddyeog","ddyeogg","ddyeogs","ddyeon","ddyeonj","ddyeonh","ddyeod","ddyeol","ddyeolg","ddyeolm","ddyeolb","ddyeols","ddyeolt","ddyeolp","ddyeolh","ddyeom","ddyeob","ddyeobs","ddyeos","ddyeoss","ddyeong","ddyeoj","ddyeoc","ddyeok","ddyeot","ddyeop","ddyeoh","ddye","ddyeg","ddyegg","ddyegs","ddyen","ddyenj","ddyenh","ddyed","ddyel","ddyelg","ddyelm","ddyelb"]});var z7=m((P4e,K7)=>{K7.exports=["ddyels","ddyelt","ddyelp","ddyelh","ddyem","ddyeb","ddyebs","ddyes","ddyess","ddyeng","ddyej","ddyec","ddyek","ddyet","ddyep","ddyeh","ddo","ddog","ddogg","ddogs","ddon","ddonj","ddonh","ddod","ddol","ddolg","ddolm","ddolb","ddols","ddolt","ddolp","ddolh","ddom","ddob","ddobs","ddos","ddoss","ddong","ddoj","ddoc","ddok","ddot","ddop","ddoh","ddwa","ddwag","ddwagg","ddwags","ddwan","ddwanj","ddwanh","ddwad","ddwal","ddwalg","ddwalm","ddwalb","ddwals","ddwalt","ddwalp","ddwalh","ddwam","ddwab","ddwabs","ddwas","ddwass","ddwang","ddwaj","ddwac","ddwak","ddwat","ddwap","ddwah","ddwae","ddwaeg","ddwaegg","ddwaegs","ddwaen","ddwaenj","ddwaenh","ddwaed","ddwael","ddwaelg","ddwaelm","ddwaelb","ddwaels","ddwaelt","ddwaelp","ddwaelh","ddwaem","ddwaeb","ddwaebs","ddwaes","ddwaess","ddwaeng","ddwaej","ddwaec","ddwaek","ddwaet","ddwaep","ddwaeh","ddoe","ddoeg","ddoegg","ddoegs","ddoen","ddoenj","ddoenh","ddoed","ddoel","ddoelg","ddoelm","ddoelb","ddoels","ddoelt","ddoelp","ddoelh","ddoem","ddoeb","ddoebs","ddoes","ddoess","ddoeng","ddoej","ddoec","ddoek","ddoet","ddoep","ddoeh","ddyo","ddyog","ddyogg","ddyogs","ddyon","ddyonj","ddyonh","ddyod","ddyol","ddyolg","ddyolm","ddyolb","ddyols","ddyolt","ddyolp","ddyolh","ddyom","ddyob","ddyobs","ddyos","ddyoss","ddyong","ddyoj","ddyoc","ddyok","ddyot","ddyop","ddyoh","ddu","ddug","ddugg","ddugs","ddun","ddunj","ddunh","ddud","ddul","ddulg","ddulm","ddulb","dduls","ddult","ddulp","ddulh","ddum","ddub","ddubs","ddus","dduss","ddung","dduj","dduc","dduk","ddut","ddup","dduh","ddweo","ddweog","ddweogg","ddweogs","ddweon","ddweonj","ddweonh","ddweod","ddweol","ddweolg","ddweolm","ddweolb","ddweols","ddweolt","ddweolp","ddweolh","ddweom","ddweob","ddweobs","ddweos","ddweoss","ddweong","ddweoj","ddweoc","ddweok","ddweot","ddweop","ddweoh","ddwe","ddweg","ddwegg","ddwegs","ddwen","ddwenj","ddwenh","ddwed","ddwel","ddwelg","ddwelm","ddwelb","ddwels","ddwelt","ddwelp","ddwelh","ddwem","ddweb","ddwebs","ddwes","ddwess","ddweng","ddwej","ddwec","ddwek","ddwet","ddwep","ddweh","ddwi","ddwig","ddwigg","ddwigs","ddwin","ddwinj","ddwinh","ddwid","ddwil","ddwilg","ddwilm","ddwilb","ddwils","ddwilt","ddwilp","ddwilh"]});var e9=m((_4e,V7)=>{V7.exports=["ddwim","ddwib","ddwibs","ddwis","ddwiss","ddwing","ddwij","ddwic","ddwik","ddwit","ddwip","ddwih","ddyu","ddyug","ddyugg","ddyugs","ddyun","ddyunj","ddyunh","ddyud","ddyul","ddyulg","ddyulm","ddyulb","ddyuls","ddyult","ddyulp","ddyulh","ddyum","ddyub","ddyubs","ddyus","ddyuss","ddyung","ddyuj","ddyuc","ddyuk","ddyut","ddyup","ddyuh","ddeu","ddeug","ddeugg","ddeugs","ddeun","ddeunj","ddeunh","ddeud","ddeul","ddeulg","ddeulm","ddeulb","ddeuls","ddeult","ddeulp","ddeulh","ddeum","ddeub","ddeubs","ddeus","ddeuss","ddeung","ddeuj","ddeuc","ddeuk","ddeut","ddeup","ddeuh","ddyi","ddyig","ddyigg","ddyigs","ddyin","ddyinj","ddyinh","ddyid","ddyil","ddyilg","ddyilm","ddyilb","ddyils","ddyilt","ddyilp","ddyilh","ddyim","ddyib","ddyibs","ddyis","ddyiss","ddying","ddyij","ddyic","ddyik","ddyit","ddyip","ddyih","ddi","ddig","ddigg","ddigs","ddin","ddinj","ddinh","ddid","ddil","ddilg","ddilm","ddilb","ddils","ddilt","ddilp","ddilh","ddim","ddib","ddibs","ddis","ddiss","dding","ddij","ddic","ddik","ddit","ddip","ddih","ra","rag","ragg","rags","ran","ranj","ranh","rad","ral","ralg","ralm","ralb","rals","ralt","ralp","ralh","ram","rab","rabs","ras","rass","rang","raj","rac","rak","rat","rap","rah","rae","raeg","raegg","raegs","raen","raenj","raenh","raed","rael","raelg","raelm","raelb","raels","raelt","raelp","raelh","raem","raeb","raebs","raes","raess","raeng","raej","raec","raek","raet","raep","raeh","rya","ryag","ryagg","ryags","ryan","ryanj","ryanh","ryad","ryal","ryalg","ryalm","ryalb","ryals","ryalt","ryalp","ryalh","ryam","ryab","ryabs","ryas","ryass","ryang","ryaj","ryac","ryak","ryat","ryap","ryah","ryae","ryaeg","ryaegg","ryaegs","ryaen","ryaenj","ryaenh","ryaed","ryael","ryaelg","ryaelm","ryaelb","ryaels","ryaelt","ryaelp","ryaelh","ryaem","ryaeb","ryaebs","ryaes","ryaess","ryaeng","ryaej","ryaec","ryaek","ryaet","ryaep","ryaeh","reo","reog","reogg","reogs","reon","reonj","reonh","reod","reol","reolg","reolm","reolb","reols","reolt","reolp","reolh","reom","reob","reobs","reos"]});var i9=m((R4e,t9)=>{t9.exports=["reoss","reong","reoj","reoc","reok","reot","reop","reoh","re","reg","regg","regs","ren","renj","renh","red","rel","relg","relm","relb","rels","relt","relp","relh","rem","reb","rebs","res","ress","reng","rej","rec","rek","ret","rep","reh","ryeo","ryeog","ryeogg","ryeogs","ryeon","ryeonj","ryeonh","ryeod","ryeol","ryeolg","ryeolm","ryeolb","ryeols","ryeolt","ryeolp","ryeolh","ryeom","ryeob","ryeobs","ryeos","ryeoss","ryeong","ryeoj","ryeoc","ryeok","ryeot","ryeop","ryeoh","rye","ryeg","ryegg","ryegs","ryen","ryenj","ryenh","ryed","ryel","ryelg","ryelm","ryelb","ryels","ryelt","ryelp","ryelh","ryem","ryeb","ryebs","ryes","ryess","ryeng","ryej","ryec","ryek","ryet","ryep","ryeh","ro","rog","rogg","rogs","ron","ronj","ronh","rod","rol","rolg","rolm","rolb","rols","rolt","rolp","rolh","rom","rob","robs","ros","ross","rong","roj","roc","rok","rot","rop","roh","rwa","rwag","rwagg","rwags","rwan","rwanj","rwanh","rwad","rwal","rwalg","rwalm","rwalb","rwals","rwalt","rwalp","rwalh","rwam","rwab","rwabs","rwas","rwass","rwang","rwaj","rwac","rwak","rwat","rwap","rwah","rwae","rwaeg","rwaegg","rwaegs","rwaen","rwaenj","rwaenh","rwaed","rwael","rwaelg","rwaelm","rwaelb","rwaels","rwaelt","rwaelp","rwaelh","rwaem","rwaeb","rwaebs","rwaes","rwaess","rwaeng","rwaej","rwaec","rwaek","rwaet","rwaep","rwaeh","roe","roeg","roegg","roegs","roen","roenj","roenh","roed","roel","roelg","roelm","roelb","roels","roelt","roelp","roelh","roem","roeb","roebs","roes","roess","roeng","roej","roec","roek","roet","roep","roeh","ryo","ryog","ryogg","ryogs","ryon","ryonj","ryonh","ryod","ryol","ryolg","ryolm","ryolb","ryols","ryolt","ryolp","ryolh","ryom","ryob","ryobs","ryos","ryoss","ryong","ryoj","ryoc","ryok","ryot","ryop","ryoh","ru","rug","rugg","rugs","run","runj","runh","rud","rul","rulg","rulm","rulb","ruls","rult","rulp","rulh","rum","rub","rubs","rus","russ","rung","ruj","ruc"]});var r9=m((L4e,n9)=>{n9.exports=["ruk","rut","rup","ruh","rweo","rweog","rweogg","rweogs","rweon","rweonj","rweonh","rweod","rweol","rweolg","rweolm","rweolb","rweols","rweolt","rweolp","rweolh","rweom","rweob","rweobs","rweos","rweoss","rweong","rweoj","rweoc","rweok","rweot","rweop","rweoh","rwe","rweg","rwegg","rwegs","rwen","rwenj","rwenh","rwed","rwel","rwelg","rwelm","rwelb","rwels","rwelt","rwelp","rwelh","rwem","rweb","rwebs","rwes","rwess","rweng","rwej","rwec","rwek","rwet","rwep","rweh","rwi","rwig","rwigg","rwigs","rwin","rwinj","rwinh","rwid","rwil","rwilg","rwilm","rwilb","rwils","rwilt","rwilp","rwilh","rwim","rwib","rwibs","rwis","rwiss","rwing","rwij","rwic","rwik","rwit","rwip","rwih","ryu","ryug","ryugg","ryugs","ryun","ryunj","ryunh","ryud","ryul","ryulg","ryulm","ryulb","ryuls","ryult","ryulp","ryulh","ryum","ryub","ryubs","ryus","ryuss","ryung","ryuj","ryuc","ryuk","ryut","ryup","ryuh","reu","reug","reugg","reugs","reun","reunj","reunh","reud","reul","reulg","reulm","reulb","reuls","reult","reulp","reulh","reum","reub","reubs","reus","reuss","reung","reuj","reuc","reuk","reut","reup","reuh","ryi","ryig","ryigg","ryigs","ryin","ryinj","ryinh","ryid","ryil","ryilg","ryilm","ryilb","ryils","ryilt","ryilp","ryilh","ryim","ryib","ryibs","ryis","ryiss","rying","ryij","ryic","ryik","ryit","ryip","ryih","ri","rig","rigg","rigs","rin","rinj","rinh","rid","ril","rilg","rilm","rilb","rils","rilt","rilp","rilh","rim","rib","ribs","ris","riss","ring","rij","ric","rik","rit","rip","rih","ma","mag","magg","mags","man","manj","manh","mad","mal","malg","malm","malb","mals","malt","malp","malh","mam","mab","mabs","mas","mass","mang","maj","mac","mak","mat","map","mah","mae","maeg","maegg","maegs","maen","maenj","maenh","maed","mael","maelg","maelm","maelb","maels","maelt","maelp","maelh","maem","maeb","maebs","maes","maess","maeng","maej","maec","maek","maet","maep","maeh"]});var s9=m((F4e,o9)=>{o9.exports=["mya","myag","myagg","myags","myan","myanj","myanh","myad","myal","myalg","myalm","myalb","myals","myalt","myalp","myalh","myam","myab","myabs","myas","myass","myang","myaj","myac","myak","myat","myap","myah","myae","myaeg","myaegg","myaegs","myaen","myaenj","myaenh","myaed","myael","myaelg","myaelm","myaelb","myaels","myaelt","myaelp","myaelh","myaem","myaeb","myaebs","myaes","myaess","myaeng","myaej","myaec","myaek","myaet","myaep","myaeh","meo","meog","meogg","meogs","meon","meonj","meonh","meod","meol","meolg","meolm","meolb","meols","meolt","meolp","meolh","meom","meob","meobs","meos","meoss","meong","meoj","meoc","meok","meot","meop","meoh","me","meg","megg","megs","men","menj","menh","med","mel","melg","melm","melb","mels","melt","melp","melh","mem","meb","mebs","mes","mess","meng","mej","mec","mek","met","mep","meh","myeo","myeog","myeogg","myeogs","myeon","myeonj","myeonh","myeod","myeol","myeolg","myeolm","myeolb","myeols","myeolt","myeolp","myeolh","myeom","myeob","myeobs","myeos","myeoss","myeong","myeoj","myeoc","myeok","myeot","myeop","myeoh","mye","myeg","myegg","myegs","myen","myenj","myenh","myed","myel","myelg","myelm","myelb","myels","myelt","myelp","myelh","myem","myeb","myebs","myes","myess","myeng","myej","myec","myek","myet","myep","myeh","mo","mog","mogg","mogs","mon","monj","monh","mod","mol","molg","molm","molb","mols","molt","molp","molh","mom","mob","mobs","mos","moss","mong","moj","moc","mok","mot","mop","moh","mwa","mwag","mwagg","mwags","mwan","mwanj","mwanh","mwad","mwal","mwalg","mwalm","mwalb","mwals","mwalt","mwalp","mwalh","mwam","mwab","mwabs","mwas","mwass","mwang","mwaj","mwac","mwak","mwat","mwap","mwah","mwae","mwaeg","mwaegg","mwaegs","mwaen","mwaenj","mwaenh","mwaed","mwael","mwaelg","mwaelm","mwaelb","mwaels","mwaelt","mwaelp","mwaelh","mwaem","mwaeb","mwaebs","mwaes","mwaess","mwaeng","mwaej","mwaec","mwaek","mwaet","mwaep","mwaeh","moe","moeg","moegg","moegs"]});var l9=m((I4e,a9)=>{a9.exports=["moen","moenj","moenh","moed","moel","moelg","moelm","moelb","moels","moelt","moelp","moelh","moem","moeb","moebs","moes","moess","moeng","moej","moec","moek","moet","moep","moeh","myo","myog","myogg","myogs","myon","myonj","myonh","myod","myol","myolg","myolm","myolb","myols","myolt","myolp","myolh","myom","myob","myobs","myos","myoss","myong","myoj","myoc","myok","myot","myop","myoh","mu","mug","mugg","mugs","mun","munj","munh","mud","mul","mulg","mulm","mulb","muls","mult","mulp","mulh","mum","mub","mubs","mus","muss","mung","muj","muc","muk","mut","mup","muh","mweo","mweog","mweogg","mweogs","mweon","mweonj","mweonh","mweod","mweol","mweolg","mweolm","mweolb","mweols","mweolt","mweolp","mweolh","mweom","mweob","mweobs","mweos","mweoss","mweong","mweoj","mweoc","mweok","mweot","mweop","mweoh","mwe","mweg","mwegg","mwegs","mwen","mwenj","mwenh","mwed","mwel","mwelg","mwelm","mwelb","mwels","mwelt","mwelp","mwelh","mwem","mweb","mwebs","mwes","mwess","mweng","mwej","mwec","mwek","mwet","mwep","mweh","mwi","mwig","mwigg","mwigs","mwin","mwinj","mwinh","mwid","mwil","mwilg","mwilm","mwilb","mwils","mwilt","mwilp","mwilh","mwim","mwib","mwibs","mwis","mwiss","mwing","mwij","mwic","mwik","mwit","mwip","mwih","myu","myug","myugg","myugs","myun","myunj","myunh","myud","myul","myulg","myulm","myulb","myuls","myult","myulp","myulh","myum","myub","myubs","myus","myuss","myung","myuj","myuc","myuk","myut","myup","myuh","meu","meug","meugg","meugs","meun","meunj","meunh","meud","meul","meulg","meulm","meulb","meuls","meult","meulp","meulh","meum","meub","meubs","meus","meuss","meung","meuj","meuc","meuk","meut","meup","meuh","myi","myig","myigg","myigs","myin","myinj","myinh","myid","myil","myilg","myilm","myilb","myils","myilt","myilp","myilh","myim","myib","myibs","myis","myiss","mying","myij","myic","myik","myit","myip","myih","mi","mig","migg","migs","min","minj","minh","mid"]});var c9=m((j4e,u9)=>{u9.exports=["mil","milg","milm","milb","mils","milt","milp","milh","mim","mib","mibs","mis","miss","ming","mij","mic","mik","mit","mip","mih","ba","bag","bagg","bags","ban","banj","banh","bad","bal","balg","balm","balb","bals","balt","balp","balh","bam","bab","babs","bas","bass","bang","baj","bac","bak","bat","bap","bah","bae","baeg","baegg","baegs","baen","baenj","baenh","baed","bael","baelg","baelm","baelb","baels","baelt","baelp","baelh","baem","baeb","baebs","baes","baess","baeng","baej","baec","baek","baet","baep","baeh","bya","byag","byagg","byags","byan","byanj","byanh","byad","byal","byalg","byalm","byalb","byals","byalt","byalp","byalh","byam","byab","byabs","byas","byass","byang","byaj","byac","byak","byat","byap","byah","byae","byaeg","byaegg","byaegs","byaen","byaenj","byaenh","byaed","byael","byaelg","byaelm","byaelb","byaels","byaelt","byaelp","byaelh","byaem","byaeb","byaebs","byaes","byaess","byaeng","byaej","byaec","byaek","byaet","byaep","byaeh","beo","beog","beogg","beogs","beon","beonj","beonh","beod","beol","beolg","beolm","beolb","beols","beolt","beolp","beolh","beom","beob","beobs","beos","beoss","beong","beoj","beoc","beok","beot","beop","beoh","be","beg","begg","begs","ben","benj","benh","bed","bel","belg","belm","belb","bels","belt","belp","belh","bem","beb","bebs","bes","bess","beng","bej","bec","bek","bet","bep","beh","byeo","byeog","byeogg","byeogs","byeon","byeonj","byeonh","byeod","byeol","byeolg","byeolm","byeolb","byeols","byeolt","byeolp","byeolh","byeom","byeob","byeobs","byeos","byeoss","byeong","byeoj","byeoc","byeok","byeot","byeop","byeoh","bye","byeg","byegg","byegs","byen","byenj","byenh","byed","byel","byelg","byelm","byelb","byels","byelt","byelp","byelh","byem","byeb","byebs","byes","byess","byeng","byej","byec","byek","byet","byep","byeh","bo","bog","bogg","bogs","bon","bonj","bonh","bod","bol","bolg","bolm","bolb"]});var d9=m((A4e,h9)=>{h9.exports=["bols","bolt","bolp","bolh","bom","bob","bobs","bos","boss","bong","boj","boc","bok","bot","bop","boh","bwa","bwag","bwagg","bwags","bwan","bwanj","bwanh","bwad","bwal","bwalg","bwalm","bwalb","bwals","bwalt","bwalp","bwalh","bwam","bwab","bwabs","bwas","bwass","bwang","bwaj","bwac","bwak","bwat","bwap","bwah","bwae","bwaeg","bwaegg","bwaegs","bwaen","bwaenj","bwaenh","bwaed","bwael","bwaelg","bwaelm","bwaelb","bwaels","bwaelt","bwaelp","bwaelh","bwaem","bwaeb","bwaebs","bwaes","bwaess","bwaeng","bwaej","bwaec","bwaek","bwaet","bwaep","bwaeh","boe","boeg","boegg","boegs","boen","boenj","boenh","boed","boel","boelg","boelm","boelb","boels","boelt","boelp","boelh","boem","boeb","boebs","boes","boess","boeng","boej","boec","boek","boet","boep","boeh","byo","byog","byogg","byogs","byon","byonj","byonh","byod","byol","byolg","byolm","byolb","byols","byolt","byolp","byolh","byom","byob","byobs","byos","byoss","byong","byoj","byoc","byok","byot","byop","byoh","bu","bug","bugg","bugs","bun","bunj","bunh","bud","bul","bulg","bulm","bulb","buls","bult","bulp","bulh","bum","bub","bubs","bus","buss","bung","buj","buc","buk","but","bup","buh","bweo","bweog","bweogg","bweogs","bweon","bweonj","bweonh","bweod","bweol","bweolg","bweolm","bweolb","bweols","bweolt","bweolp","bweolh","bweom","bweob","bweobs","bweos","bweoss","bweong","bweoj","bweoc","bweok","bweot","bweop","bweoh","bwe","bweg","bwegg","bwegs","bwen","bwenj","bwenh","bwed","bwel","bwelg","bwelm","bwelb","bwels","bwelt","bwelp","bwelh","bwem","bweb","bwebs","bwes","bwess","bweng","bwej","bwec","bwek","bwet","bwep","bweh","bwi","bwig","bwigg","bwigs","bwin","bwinj","bwinh","bwid","bwil","bwilg","bwilm","bwilb","bwils","bwilt","bwilp","bwilh","bwim","bwib","bwibs","bwis","bwiss","bwing","bwij","bwic","bwik","bwit","bwip","bwih","byu","byug","byugg","byugs","byun","byunj","byunh","byud","byul","byulg","byulm","byulb","byuls","byult","byulp","byulh"]});var f9=m((O4e,g9)=>{g9.exports=["byum","byub","byubs","byus","byuss","byung","byuj","byuc","byuk","byut","byup","byuh","beu","beug","beugg","beugs","beun","beunj","beunh","beud","beul","beulg","beulm","beulb","beuls","beult","beulp","beulh","beum","beub","beubs","beus","beuss","beung","beuj","beuc","beuk","beut","beup","beuh","byi","byig","byigg","byigs","byin","byinj","byinh","byid","byil","byilg","byilm","byilb","byils","byilt","byilp","byilh","byim","byib","byibs","byis","byiss","bying","byij","byic","byik","byit","byip","byih","bi","big","bigg","bigs","bin","binj","binh","bid","bil","bilg","bilm","bilb","bils","bilt","bilp","bilh","bim","bib","bibs","bis","biss","bing","bij","bic","bik","bit","bip","bih","bba","bbag","bbagg","bbags","bban","bbanj","bbanh","bbad","bbal","bbalg","bbalm","bbalb","bbals","bbalt","bbalp","bbalh","bbam","bbab","bbabs","bbas","bbass","bbang","bbaj","bbac","bbak","bbat","bbap","bbah","bbae","bbaeg","bbaegg","bbaegs","bbaen","bbaenj","bbaenh","bbaed","bbael","bbaelg","bbaelm","bbaelb","bbaels","bbaelt","bbaelp","bbaelh","bbaem","bbaeb","bbaebs","bbaes","bbaess","bbaeng","bbaej","bbaec","bbaek","bbaet","bbaep","bbaeh","bbya","bbyag","bbyagg","bbyags","bbyan","bbyanj","bbyanh","bbyad","bbyal","bbyalg","bbyalm","bbyalb","bbyals","bbyalt","bbyalp","bbyalh","bbyam","bbyab","bbyabs","bbyas","bbyass","bbyang","bbyaj","bbyac","bbyak","bbyat","bbyap","bbyah","bbyae","bbyaeg","bbyaegg","bbyaegs","bbyaen","bbyaenj","bbyaenh","bbyaed","bbyael","bbyaelg","bbyaelm","bbyaelb","bbyaels","bbyaelt","bbyaelp","bbyaelh","bbyaem","bbyaeb","bbyaebs","bbyaes","bbyaess","bbyaeng","bbyaej","bbyaec","bbyaek","bbyaet","bbyaep","bbyaeh","bbeo","bbeog","bbeogg","bbeogs","bbeon","bbeonj","bbeonh","bbeod","bbeol","bbeolg","bbeolm","bbeolb","bbeols","bbeolt","bbeolp","bbeolh","bbeom","bbeob","bbeobs","bbeos","bbeoss","bbeong","bbeoj","bbeoc","bbeok","bbeot","bbeop","bbeoh","bbe","bbeg","bbegg","bbegs","bben","bbenj","bbenh","bbed","bbel","bbelg","bbelm","bbelb","bbels","bbelt","bbelp","bbelh","bbem","bbeb","bbebs","bbes"]});var m9=m((M4e,p9)=>{p9.exports=["bbess","bbeng","bbej","bbec","bbek","bbet","bbep","bbeh","bbyeo","bbyeog","bbyeogg","bbyeogs","bbyeon","bbyeonj","bbyeonh","bbyeod","bbyeol","bbyeolg","bbyeolm","bbyeolb","bbyeols","bbyeolt","bbyeolp","bbyeolh","bbyeom","bbyeob","bbyeobs","bbyeos","bbyeoss","bbyeong","bbyeoj","bbyeoc","bbyeok","bbyeot","bbyeop","bbyeoh","bbye","bbyeg","bbyegg","bbyegs","bbyen","bbyenj","bbyenh","bbyed","bbyel","bbyelg","bbyelm","bbyelb","bbyels","bbyelt","bbyelp","bbyelh","bbyem","bbyeb","bbyebs","bbyes","bbyess","bbyeng","bbyej","bbyec","bbyek","bbyet","bbyep","bbyeh","bbo","bbog","bbogg","bbogs","bbon","bbonj","bbonh","bbod","bbol","bbolg","bbolm","bbolb","bbols","bbolt","bbolp","bbolh","bbom","bbob","bbobs","bbos","bboss","bbong","bboj","bboc","bbok","bbot","bbop","bboh","bbwa","bbwag","bbwagg","bbwags","bbwan","bbwanj","bbwanh","bbwad","bbwal","bbwalg","bbwalm","bbwalb","bbwals","bbwalt","bbwalp","bbwalh","bbwam","bbwab","bbwabs","bbwas","bbwass","bbwang","bbwaj","bbwac","bbwak","bbwat","bbwap","bbwah","bbwae","bbwaeg","bbwaegg","bbwaegs","bbwaen","bbwaenj","bbwaenh","bbwaed","bbwael","bbwaelg","bbwaelm","bbwaelb","bbwaels","bbwaelt","bbwaelp","bbwaelh","bbwaem","bbwaeb","bbwaebs","bbwaes","bbwaess","bbwaeng","bbwaej","bbwaec","bbwaek","bbwaet","bbwaep","bbwaeh","bboe","bboeg","bboegg","bboegs","bboen","bboenj","bboenh","bboed","bboel","bboelg","bboelm","bboelb","bboels","bboelt","bboelp","bboelh","bboem","bboeb","bboebs","bboes","bboess","bboeng","bboej","bboec","bboek","bboet","bboep","bboeh","bbyo","bbyog","bbyogg","bbyogs","bbyon","bbyonj","bbyonh","bbyod","bbyol","bbyolg","bbyolm","bbyolb","bbyols","bbyolt","bbyolp","bbyolh","bbyom","bbyob","bbyobs","bbyos","bbyoss","bbyong","bbyoj","bbyoc","bbyok","bbyot","bbyop","bbyoh","bbu","bbug","bbugg","bbugs","bbun","bbunj","bbunh","bbud","bbul","bbulg","bbulm","bbulb","bbuls","bbult","bbulp","bbulh","bbum","bbub","bbubs","bbus","bbuss","bbung","bbuj","bbuc","bbuk","bbut","bbup","bbuh","bbweo","bbweog","bbweogg","bbweogs","bbweon","bbweonj","bbweonh","bbweod","bbweol","bbweolg","bbweolm","bbweolb","bbweols","bbweolt","bbweolp","bbweolh","bbweom","bbweob","bbweobs","bbweos","bbweoss","bbweong","bbweoj","bbweoc"]});var y9=m((N4e,b9)=>{b9.exports=["bbweok","bbweot","bbweop","bbweoh","bbwe","bbweg","bbwegg","bbwegs","bbwen","bbwenj","bbwenh","bbwed","bbwel","bbwelg","bbwelm","bbwelb","bbwels","bbwelt","bbwelp","bbwelh","bbwem","bbweb","bbwebs","bbwes","bbwess","bbweng","bbwej","bbwec","bbwek","bbwet","bbwep","bbweh","bbwi","bbwig","bbwigg","bbwigs","bbwin","bbwinj","bbwinh","bbwid","bbwil","bbwilg","bbwilm","bbwilb","bbwils","bbwilt","bbwilp","bbwilh","bbwim","bbwib","bbwibs","bbwis","bbwiss","bbwing","bbwij","bbwic","bbwik","bbwit","bbwip","bbwih","bbyu","bbyug","bbyugg","bbyugs","bbyun","bbyunj","bbyunh","bbyud","bbyul","bbyulg","bbyulm","bbyulb","bbyuls","bbyult","bbyulp","bbyulh","bbyum","bbyub","bbyubs","bbyus","bbyuss","bbyung","bbyuj","bbyuc","bbyuk","bbyut","bbyup","bbyuh","bbeu","bbeug","bbeugg","bbeugs","bbeun","bbeunj","bbeunh","bbeud","bbeul","bbeulg","bbeulm","bbeulb","bbeuls","bbeult","bbeulp","bbeulh","bbeum","bbeub","bbeubs","bbeus","bbeuss","bbeung","bbeuj","bbeuc","bbeuk","bbeut","bbeup","bbeuh","bbyi","bbyig","bbyigg","bbyigs","bbyin","bbyinj","bbyinh","bbyid","bbyil","bbyilg","bbyilm","bbyilb","bbyils","bbyilt","bbyilp","bbyilh","bbyim","bbyib","bbyibs","bbyis","bbyiss","bbying","bbyij","bbyic","bbyik","bbyit","bbyip","bbyih","bbi","bbig","bbigg","bbigs","bbin","bbinj","bbinh","bbid","bbil","bbilg","bbilm","bbilb","bbils","bbilt","bbilp","bbilh","bbim","bbib","bbibs","bbis","bbiss","bbing","bbij","bbic","bbik","bbit","bbip","bbih","sa","sag","sagg","sags","san","sanj","sanh","sad","sal","salg","salm","salb","sals","salt","salp","salh","sam","sab","sabs","sas","sass","sang","saj","sac","sak","sat","sap","sah","sae","saeg","saegg","saegs","saen","saenj","saenh","saed","sael","saelg","saelm","saelb","saels","saelt","saelp","saelh","saem","saeb","saebs","saes","saess","saeng","saej","saec","saek","saet","saep","saeh","sya","syag","syagg","syags","syan","syanj","syanh","syad","syal","syalg","syalm","syalb","syals","syalt","syalp","syalh","syam","syab","syabs","syas","syass","syang","syaj","syac","syak","syat","syap","syah"]});var w9=m((B4e,v9)=>{v9.exports=["syae","syaeg","syaegg","syaegs","syaen","syaenj","syaenh","syaed","syael","syaelg","syaelm","syaelb","syaels","syaelt","syaelp","syaelh","syaem","syaeb","syaebs","syaes","syaess","syaeng","syaej","syaec","syaek","syaet","syaep","syaeh","seo","seog","seogg","seogs","seon","seonj","seonh","seod","seol","seolg","seolm","seolb","seols","seolt","seolp","seolh","seom","seob","seobs","seos","seoss","seong","seoj","seoc","seok","seot","seop","seoh","se","seg","segg","segs","sen","senj","senh","sed","sel","selg","selm","selb","sels","selt","selp","selh","sem","seb","sebs","ses","sess","seng","sej","sec","sek","set","sep","seh","syeo","syeog","syeogg","syeogs","syeon","syeonj","syeonh","syeod","syeol","syeolg","syeolm","syeolb","syeols","syeolt","syeolp","syeolh","syeom","syeob","syeobs","syeos","syeoss","syeong","syeoj","syeoc","syeok","syeot","syeop","syeoh","sye","syeg","syegg","syegs","syen","syenj","syenh","syed","syel","syelg","syelm","syelb","syels","syelt","syelp","syelh","syem","syeb","syebs","syes","syess","syeng","syej","syec","syek","syet","syep","syeh","so","sog","sogg","sogs","son","sonj","sonh","sod","sol","solg","solm","solb","sols","solt","solp","solh","som","sob","sobs","sos","soss","song","soj","soc","sok","sot","sop","soh","swa","swag","swagg","swags","swan","swanj","swanh","swad","swal","swalg","swalm","swalb","swals","swalt","swalp","swalh","swam","swab","swabs","swas","swass","swang","swaj","swac","swak","swat","swap","swah","swae","swaeg","swaegg","swaegs","swaen","swaenj","swaenh","swaed","swael","swaelg","swaelm","swaelb","swaels","swaelt","swaelp","swaelh","swaem","swaeb","swaebs","swaes","swaess","swaeng","swaej","swaec","swaek","swaet","swaep","swaeh","soe","soeg","soegg","soegs","soen","soenj","soenh","soed","soel","soelg","soelm","soelb","soels","soelt","soelp","soelh","soem","soeb","soebs","soes","soess","soeng","soej","soec","soek","soet","soep","soeh","syo","syog","syogg","syogs"]});var x9=m((H4e,D9)=>{D9.exports=["syon","syonj","syonh","syod","syol","syolg","syolm","syolb","syols","syolt","syolp","syolh","syom","syob","syobs","syos","syoss","syong","syoj","syoc","syok","syot","syop","syoh","su","sug","sugg","sugs","sun","sunj","sunh","sud","sul","sulg","sulm","sulb","suls","sult","sulp","sulh","sum","sub","subs","sus","suss","sung","suj","suc","suk","sut","sup","suh","sweo","sweog","sweogg","sweogs","sweon","sweonj","sweonh","sweod","sweol","sweolg","sweolm","sweolb","sweols","sweolt","sweolp","sweolh","sweom","sweob","sweobs","sweos","sweoss","sweong","sweoj","sweoc","sweok","sweot","sweop","sweoh","swe","sweg","swegg","swegs","swen","swenj","swenh","swed","swel","swelg","swelm","swelb","swels","swelt","swelp","swelh","swem","sweb","swebs","swes","swess","sweng","swej","swec","swek","swet","swep","sweh","swi","swig","swigg","swigs","swin","swinj","swinh","swid","swil","swilg","swilm","swilb","swils","swilt","swilp","swilh","swim","swib","swibs","swis","swiss","swing","swij","swic","swik","swit","swip","swih","syu","syug","syugg","syugs","syun","syunj","syunh","syud","syul","syulg","syulm","syulb","syuls","syult","syulp","syulh","syum","syub","syubs","syus","syuss","syung","syuj","syuc","syuk","syut","syup","syuh","seu","seug","seugg","seugs","seun","seunj","seunh","seud","seul","seulg","seulm","seulb","seuls","seult","seulp","seulh","seum","seub","seubs","seus","seuss","seung","seuj","seuc","seuk","seut","seup","seuh","syi","syig","syigg","syigs","syin","syinj","syinh","syid","syil","syilg","syilm","syilb","syils","syilt","syilp","syilh","syim","syib","syibs","syis","syiss","sying","syij","syic","syik","syit","syip","syih","si","sig","sigg","sigs","sin","sinj","sinh","sid","sil","silg","silm","silb","sils","silt","silp","silh","sim","sib","sibs","sis","siss","sing","sij","sic","sik","sit","sip","sih","ssa","ssag","ssagg","ssags","ssan","ssanj","ssanh","ssad"]});var S9=m((q4e,C9)=>{C9.exports=["ssal","ssalg","ssalm","ssalb","ssals","ssalt","ssalp","ssalh","ssam","ssab","ssabs","ssas","ssass","ssang","ssaj","ssac","ssak","ssat","ssap","ssah","ssae","ssaeg","ssaegg","ssaegs","ssaen","ssaenj","ssaenh","ssaed","ssael","ssaelg","ssaelm","ssaelb","ssaels","ssaelt","ssaelp","ssaelh","ssaem","ssaeb","ssaebs","ssaes","ssaess","ssaeng","ssaej","ssaec","ssaek","ssaet","ssaep","ssaeh","ssya","ssyag","ssyagg","ssyags","ssyan","ssyanj","ssyanh","ssyad","ssyal","ssyalg","ssyalm","ssyalb","ssyals","ssyalt","ssyalp","ssyalh","ssyam","ssyab","ssyabs","ssyas","ssyass","ssyang","ssyaj","ssyac","ssyak","ssyat","ssyap","ssyah","ssyae","ssyaeg","ssyaegg","ssyaegs","ssyaen","ssyaenj","ssyaenh","ssyaed","ssyael","ssyaelg","ssyaelm","ssyaelb","ssyaels","ssyaelt","ssyaelp","ssyaelh","ssyaem","ssyaeb","ssyaebs","ssyaes","ssyaess","ssyaeng","ssyaej","ssyaec","ssyaek","ssyaet","ssyaep","ssyaeh","sseo","sseog","sseogg","sseogs","sseon","sseonj","sseonh","sseod","sseol","sseolg","sseolm","sseolb","sseols","sseolt","sseolp","sseolh","sseom","sseob","sseobs","sseos","sseoss","sseong","sseoj","sseoc","sseok","sseot","sseop","sseoh","sse","sseg","ssegg","ssegs","ssen","ssenj","ssenh","ssed","ssel","sselg","sselm","sselb","ssels","sselt","sselp","sselh","ssem","sseb","ssebs","sses","ssess","sseng","ssej","ssec","ssek","sset","ssep","sseh","ssyeo","ssyeog","ssyeogg","ssyeogs","ssyeon","ssyeonj","ssyeonh","ssyeod","ssyeol","ssyeolg","ssyeolm","ssyeolb","ssyeols","ssyeolt","ssyeolp","ssyeolh","ssyeom","ssyeob","ssyeobs","ssyeos","ssyeoss","ssyeong","ssyeoj","ssyeoc","ssyeok","ssyeot","ssyeop","ssyeoh","ssye","ssyeg","ssyegg","ssyegs","ssyen","ssyenj","ssyenh","ssyed","ssyel","ssyelg","ssyelm","ssyelb","ssyels","ssyelt","ssyelp","ssyelh","ssyem","ssyeb","ssyebs","ssyes","ssyess","ssyeng","ssyej","ssyec","ssyek","ssyet","ssyep","ssyeh","sso","ssog","ssogg","ssogs","sson","ssonj","ssonh","ssod","ssol","ssolg","ssolm","ssolb","ssols","ssolt","ssolp","ssolh","ssom","ssob","ssobs","ssos","ssoss","ssong","ssoj","ssoc","ssok","ssot","ssop","ssoh","sswa","sswag","sswagg","sswags","sswan","sswanj","sswanh","sswad","sswal","sswalg","sswalm","sswalb"]});var k9=m((Y4e,T9)=>{T9.exports=["sswals","sswalt","sswalp","sswalh","sswam","sswab","sswabs","sswas","sswass","sswang","sswaj","sswac","sswak","sswat","sswap","sswah","sswae","sswaeg","sswaegg","sswaegs","sswaen","sswaenj","sswaenh","sswaed","sswael","sswaelg","sswaelm","sswaelb","sswaels","sswaelt","sswaelp","sswaelh","sswaem","sswaeb","sswaebs","sswaes","sswaess","sswaeng","sswaej","sswaec","sswaek","sswaet","sswaep","sswaeh","ssoe","ssoeg","ssoegg","ssoegs","ssoen","ssoenj","ssoenh","ssoed","ssoel","ssoelg","ssoelm","ssoelb","ssoels","ssoelt","ssoelp","ssoelh","ssoem","ssoeb","ssoebs","ssoes","ssoess","ssoeng","ssoej","ssoec","ssoek","ssoet","ssoep","ssoeh","ssyo","ssyog","ssyogg","ssyogs","ssyon","ssyonj","ssyonh","ssyod","ssyol","ssyolg","ssyolm","ssyolb","ssyols","ssyolt","ssyolp","ssyolh","ssyom","ssyob","ssyobs","ssyos","ssyoss","ssyong","ssyoj","ssyoc","ssyok","ssyot","ssyop","ssyoh","ssu","ssug","ssugg","ssugs","ssun","ssunj","ssunh","ssud","ssul","ssulg","ssulm","ssulb","ssuls","ssult","ssulp","ssulh","ssum","ssub","ssubs","ssus","ssuss","ssung","ssuj","ssuc","ssuk","ssut","ssup","ssuh","ssweo","ssweog","ssweogg","ssweogs","ssweon","ssweonj","ssweonh","ssweod","ssweol","ssweolg","ssweolm","ssweolb","ssweols","ssweolt","ssweolp","ssweolh","ssweom","ssweob","ssweobs","ssweos","ssweoss","ssweong","ssweoj","ssweoc","ssweok","ssweot","ssweop","ssweoh","sswe","ssweg","sswegg","sswegs","sswen","sswenj","sswenh","sswed","sswel","sswelg","sswelm","sswelb","sswels","sswelt","sswelp","sswelh","sswem","ssweb","sswebs","sswes","sswess","ssweng","sswej","sswec","sswek","sswet","sswep","ssweh","sswi","sswig","sswigg","sswigs","sswin","sswinj","sswinh","sswid","sswil","sswilg","sswilm","sswilb","sswils","sswilt","sswilp","sswilh","sswim","sswib","sswibs","sswis","sswiss","sswing","sswij","sswic","sswik","sswit","sswip","sswih","ssyu","ssyug","ssyugg","ssyugs","ssyun","ssyunj","ssyunh","ssyud","ssyul","ssyulg","ssyulm","ssyulb","ssyuls","ssyult","ssyulp","ssyulh","ssyum","ssyub","ssyubs","ssyus","ssyuss","ssyung","ssyuj","ssyuc","ssyuk","ssyut","ssyup","ssyuh","sseu","sseug","sseugg","sseugs","sseun","sseunj","sseunh","sseud","sseul","sseulg","sseulm","sseulb","sseuls","sseult","sseulp","sseulh"]});var P9=m((W4e,E9)=>{E9.exports=["sseum","sseub","sseubs","sseus","sseuss","sseung","sseuj","sseuc","sseuk","sseut","sseup","sseuh","ssyi","ssyig","ssyigg","ssyigs","ssyin","ssyinj","ssyinh","ssyid","ssyil","ssyilg","ssyilm","ssyilb","ssyils","ssyilt","ssyilp","ssyilh","ssyim","ssyib","ssyibs","ssyis","ssyiss","ssying","ssyij","ssyic","ssyik","ssyit","ssyip","ssyih","ssi","ssig","ssigg","ssigs","ssin","ssinj","ssinh","ssid","ssil","ssilg","ssilm","ssilb","ssils","ssilt","ssilp","ssilh","ssim","ssib","ssibs","ssis","ssiss","ssing","ssij","ssic","ssik","ssit","ssip","ssih","a","ag","agg","ags","an","anj","anh","ad","al","alg","alm","alb","als","alt","alp","alh","am","ab","abs","as","ass","ang","aj","ac","ak","at","ap","ah","ae","aeg","aegg","aegs","aen","aenj","aenh","aed","ael","aelg","aelm","aelb","aels","aelt","aelp","aelh","aem","aeb","aebs","aes","aess","aeng","aej","aec","aek","aet","aep","aeh","ya","yag","yagg","yags","yan","yanj","yanh","yad","yal","yalg","yalm","yalb","yals","yalt","yalp","yalh","yam","yab","yabs","yas","yass","yang","yaj","yac","yak","yat","yap","yah","yae","yaeg","yaegg","yaegs","yaen","yaenj","yaenh","yaed","yael","yaelg","yaelm","yaelb","yaels","yaelt","yaelp","yaelh","yaem","yaeb","yaebs","yaes","yaess","yaeng","yaej","yaec","yaek","yaet","yaep","yaeh","eo","eog","eogg","eogs","eon","eonj","eonh","eod","eol","eolg","eolm","eolb","eols","eolt","eolp","eolh","eom","eob","eobs","eos","eoss","eong","eoj","eoc","eok","eot","eop","eoh","e","eg","egg","egs","en","enj","enh","ed","el","elg","elm","elb","els","elt","elp","elh","em","eb","ebs","es","ess","eng","ej","ec","ek","et","ep","eh","yeo","yeog","yeogg","yeogs","yeon","yeonj","yeonh","yeod","yeol","yeolg","yeolm","yeolb","yeols","yeolt","yeolp","yeolh","yeom","yeob","yeobs","yeos"]});var R9=m((Z4e,_9)=>{_9.exports=["yeoss","yeong","yeoj","yeoc","yeok","yeot","yeop","yeoh","ye","yeg","yegg","yegs","yen","yenj","yenh","yed","yel","yelg","yelm","yelb","yels","yelt","yelp","yelh","yem","yeb","yebs","yes","yess","yeng","yej","yec","yek","yet","yep","yeh","o","og","ogg","ogs","on","onj","onh","od","ol","olg","olm","olb","ols","olt","olp","olh","om","ob","obs","os","oss","ong","oj","oc","ok","ot","op","oh","wa","wag","wagg","wags","wan","wanj","wanh","wad","wal","walg","walm","walb","wals","walt","walp","walh","wam","wab","wabs","was","wass","wang","waj","wac","wak","wat","wap","wah","wae","waeg","waegg","waegs","waen","waenj","waenh","waed","wael","waelg","waelm","waelb","waels","waelt","waelp","waelh","waem","waeb","waebs","waes","waess","waeng","waej","waec","waek","waet","waep","waeh","oe","oeg","oegg","oegs","oen","oenj","oenh","oed","oel","oelg","oelm","oelb","oels","oelt","oelp","oelh","oem","oeb","oebs","oes","oess","oeng","oej","oec","oek","oet","oep","oeh","yo","yog","yogg","yogs","yon","yonj","yonh","yod","yol","yolg","yolm","yolb","yols","yolt","yolp","yolh","yom","yob","yobs","yos","yoss","yong","yoj","yoc","yok","yot","yop","yoh","u","ug","ugg","ugs","un","unj","unh","ud","ul","ulg","ulm","ulb","uls","ult","ulp","ulh","um","ub","ubs","us","uss","ung","uj","uc","uk","ut","up","uh","weo","weog","weogg","weogs","weon","weonj","weonh","weod","weol","weolg","weolm","weolb","weols","weolt","weolp","weolh","weom","weob","weobs","weos","weoss","weong","weoj","weoc","weok","weot","weop","weoh","we","weg","wegg","wegs","wen","wenj","wenh","wed","wel","welg","welm","welb","wels","welt","welp","welh","wem","web","webs","wes","wess","weng","wej","wec"]});var F9=m((J4e,L9)=>{L9.exports=["wek","wet","wep","weh","wi","wig","wigg","wigs","win","winj","winh","wid","wil","wilg","wilm","wilb","wils","wilt","wilp","wilh","wim","wib","wibs","wis","wiss","wing","wij","wic","wik","wit","wip","wih","yu","yug","yugg","yugs","yun","yunj","yunh","yud","yul","yulg","yulm","yulb","yuls","yult","yulp","yulh","yum","yub","yubs","yus","yuss","yung","yuj","yuc","yuk","yut","yup","yuh","eu","eug","eugg","eugs","eun","eunj","eunh","eud","eul","eulg","eulm","eulb","euls","eult","eulp","eulh","eum","eub","eubs","eus","euss","eung","euj","euc","euk","eut","eup","euh","yi","yig","yigg","yigs","yin","yinj","yinh","yid","yil","yilg","yilm","yilb","yils","yilt","yilp","yilh","yim","yib","yibs","yis","yiss","ying","yij","yic","yik","yit","yip","yih","i","ig","igg","igs","in","inj","inh","id","il","ilg","ilm","ilb","ils","ilt","ilp","ilh","im","ib","ibs","is","iss","ing","ij","ic","ik","it","ip","ih","ja","jag","jagg","jags","jan","janj","janh","jad","jal","jalg","jalm","jalb","jals","jalt","jalp","jalh","jam","jab","jabs","jas","jass","jang","jaj","jac","jak","jat","jap","jah","jae","jaeg","jaegg","jaegs","jaen","jaenj","jaenh","jaed","jael","jaelg","jaelm","jaelb","jaels","jaelt","jaelp","jaelh","jaem","jaeb","jaebs","jaes","jaess","jaeng","jaej","jaec","jaek","jaet","jaep","jaeh","jya","jyag","jyagg","jyags","jyan","jyanj","jyanh","jyad","jyal","jyalg","jyalm","jyalb","jyals","jyalt","jyalp","jyalh","jyam","jyab","jyabs","jyas","jyass","jyang","jyaj","jyac","jyak","jyat","jyap","jyah","jyae","jyaeg","jyaegg","jyaegs","jyaen","jyaenj","jyaenh","jyaed","jyael","jyaelg","jyaelm","jyaelb","jyaels","jyaelt","jyaelp","jyaelh","jyaem","jyaeb","jyaebs","jyaes","jyaess","jyaeng","jyaej","jyaec","jyaek","jyaet","jyaep","jyaeh"]});var j9=m(($4e,I9)=>{I9.exports=["jeo","jeog","jeogg","jeogs","jeon","jeonj","jeonh","jeod","jeol","jeolg","jeolm","jeolb","jeols","jeolt","jeolp","jeolh","jeom","jeob","jeobs","jeos","jeoss","jeong","jeoj","jeoc","jeok","jeot","jeop","jeoh","je","jeg","jegg","jegs","jen","jenj","jenh","jed","jel","jelg","jelm","jelb","jels","jelt","jelp","jelh","jem","jeb","jebs","jes","jess","jeng","jej","jec","jek","jet","jep","jeh","jyeo","jyeog","jyeogg","jyeogs","jyeon","jyeonj","jyeonh","jyeod","jyeol","jyeolg","jyeolm","jyeolb","jyeols","jyeolt","jyeolp","jyeolh","jyeom","jyeob","jyeobs","jyeos","jyeoss","jyeong","jyeoj","jyeoc","jyeok","jyeot","jyeop","jyeoh","jye","jyeg","jyegg","jyegs","jyen","jyenj","jyenh","jyed","jyel","jyelg","jyelm","jyelb","jyels","jyelt","jyelp","jyelh","jyem","jyeb","jyebs","jyes","jyess","jyeng","jyej","jyec","jyek","jyet","jyep","jyeh","jo","jog","jogg","jogs","jon","jonj","jonh","jod","jol","jolg","jolm","jolb","jols","jolt","jolp","jolh","jom","job","jobs","jos","joss","jong","joj","joc","jok","jot","jop","joh","jwa","jwag","jwagg","jwags","jwan","jwanj","jwanh","jwad","jwal","jwalg","jwalm","jwalb","jwals","jwalt","jwalp","jwalh","jwam","jwab","jwabs","jwas","jwass","jwang","jwaj","jwac","jwak","jwat","jwap","jwah","jwae","jwaeg","jwaegg","jwaegs","jwaen","jwaenj","jwaenh","jwaed","jwael","jwaelg","jwaelm","jwaelb","jwaels","jwaelt","jwaelp","jwaelh","jwaem","jwaeb","jwaebs","jwaes","jwaess","jwaeng","jwaej","jwaec","jwaek","jwaet","jwaep","jwaeh","joe","joeg","joegg","joegs","joen","joenj","joenh","joed","joel","joelg","joelm","joelb","joels","joelt","joelp","joelh","joem","joeb","joebs","joes","joess","joeng","joej","joec","joek","joet","joep","joeh","jyo","jyog","jyogg","jyogs","jyon","jyonj","jyonh","jyod","jyol","jyolg","jyolm","jyolb","jyols","jyolt","jyolp","jyolh","jyom","jyob","jyobs","jyos","jyoss","jyong","jyoj","jyoc","jyok","jyot","jyop","jyoh","ju","jug","jugg","jugs"]});var O9=m((X4e,A9)=>{A9.exports=["jun","junj","junh","jud","jul","julg","julm","julb","juls","jult","julp","julh","jum","jub","jubs","jus","juss","jung","juj","juc","juk","jut","jup","juh","jweo","jweog","jweogg","jweogs","jweon","jweonj","jweonh","jweod","jweol","jweolg","jweolm","jweolb","jweols","jweolt","jweolp","jweolh","jweom","jweob","jweobs","jweos","jweoss","jweong","jweoj","jweoc","jweok","jweot","jweop","jweoh","jwe","jweg","jwegg","jwegs","jwen","jwenj","jwenh","jwed","jwel","jwelg","jwelm","jwelb","jwels","jwelt","jwelp","jwelh","jwem","jweb","jwebs","jwes","jwess","jweng","jwej","jwec","jwek","jwet","jwep","jweh","jwi","jwig","jwigg","jwigs","jwin","jwinj","jwinh","jwid","jwil","jwilg","jwilm","jwilb","jwils","jwilt","jwilp","jwilh","jwim","jwib","jwibs","jwis","jwiss","jwing","jwij","jwic","jwik","jwit","jwip","jwih","jyu","jyug","jyugg","jyugs","jyun","jyunj","jyunh","jyud","jyul","jyulg","jyulm","jyulb","jyuls","jyult","jyulp","jyulh","jyum","jyub","jyubs","jyus","jyuss","jyung","jyuj","jyuc","jyuk","jyut","jyup","jyuh","jeu","jeug","jeugg","jeugs","jeun","jeunj","jeunh","jeud","jeul","jeulg","jeulm","jeulb","jeuls","jeult","jeulp","jeulh","jeum","jeub","jeubs","jeus","jeuss","jeung","jeuj","jeuc","jeuk","jeut","jeup","jeuh","jyi","jyig","jyigg","jyigs","jyin","jyinj","jyinh","jyid","jyil","jyilg","jyilm","jyilb","jyils","jyilt","jyilp","jyilh","jyim","jyib","jyibs","jyis","jyiss","jying","jyij","jyic","jyik","jyit","jyip","jyih","ji","jig","jigg","jigs","jin","jinj","jinh","jid","jil","jilg","jilm","jilb","jils","jilt","jilp","jilh","jim","jib","jibs","jis","jiss","jing","jij","jic","jik","jit","jip","jih","jja","jjag","jjagg","jjags","jjan","jjanj","jjanh","jjad","jjal","jjalg","jjalm","jjalb","jjals","jjalt","jjalp","jjalh","jjam","jjab","jjabs","jjas","jjass","jjang","jjaj","jjac","jjak","jjat","jjap","jjah","jjae","jjaeg","jjaegg","jjaegs","jjaen","jjaenj","jjaenh","jjaed"]});var N9=m((U4e,M9)=>{M9.exports=["jjael","jjaelg","jjaelm","jjaelb","jjaels","jjaelt","jjaelp","jjaelh","jjaem","jjaeb","jjaebs","jjaes","jjaess","jjaeng","jjaej","jjaec","jjaek","jjaet","jjaep","jjaeh","jjya","jjyag","jjyagg","jjyags","jjyan","jjyanj","jjyanh","jjyad","jjyal","jjyalg","jjyalm","jjyalb","jjyals","jjyalt","jjyalp","jjyalh","jjyam","jjyab","jjyabs","jjyas","jjyass","jjyang","jjyaj","jjyac","jjyak","jjyat","jjyap","jjyah","jjyae","jjyaeg","jjyaegg","jjyaegs","jjyaen","jjyaenj","jjyaenh","jjyaed","jjyael","jjyaelg","jjyaelm","jjyaelb","jjyaels","jjyaelt","jjyaelp","jjyaelh","jjyaem","jjyaeb","jjyaebs","jjyaes","jjyaess","jjyaeng","jjyaej","jjyaec","jjyaek","jjyaet","jjyaep","jjyaeh","jjeo","jjeog","jjeogg","jjeogs","jjeon","jjeonj","jjeonh","jjeod","jjeol","jjeolg","jjeolm","jjeolb","jjeols","jjeolt","jjeolp","jjeolh","jjeom","jjeob","jjeobs","jjeos","jjeoss","jjeong","jjeoj","jjeoc","jjeok","jjeot","jjeop","jjeoh","jje","jjeg","jjegg","jjegs","jjen","jjenj","jjenh","jjed","jjel","jjelg","jjelm","jjelb","jjels","jjelt","jjelp","jjelh","jjem","jjeb","jjebs","jjes","jjess","jjeng","jjej","jjec","jjek","jjet","jjep","jjeh","jjyeo","jjyeog","jjyeogg","jjyeogs","jjyeon","jjyeonj","jjyeonh","jjyeod","jjyeol","jjyeolg","jjyeolm","jjyeolb","jjyeols","jjyeolt","jjyeolp","jjyeolh","jjyeom","jjyeob","jjyeobs","jjyeos","jjyeoss","jjyeong","jjyeoj","jjyeoc","jjyeok","jjyeot","jjyeop","jjyeoh","jjye","jjyeg","jjyegg","jjyegs","jjyen","jjyenj","jjyenh","jjyed","jjyel","jjyelg","jjyelm","jjyelb","jjyels","jjyelt","jjyelp","jjyelh","jjyem","jjyeb","jjyebs","jjyes","jjyess","jjyeng","jjyej","jjyec","jjyek","jjyet","jjyep","jjyeh","jjo","jjog","jjogg","jjogs","jjon","jjonj","jjonh","jjod","jjol","jjolg","jjolm","jjolb","jjols","jjolt","jjolp","jjolh","jjom","jjob","jjobs","jjos","jjoss","jjong","jjoj","jjoc","jjok","jjot","jjop","jjoh","jjwa","jjwag","jjwagg","jjwags","jjwan","jjwanj","jjwanh","jjwad","jjwal","jjwalg","jjwalm","jjwalb","jjwals","jjwalt","jjwalp","jjwalh","jjwam","jjwab","jjwabs","jjwas","jjwass","jjwang","jjwaj","jjwac","jjwak","jjwat","jjwap","jjwah","jjwae","jjwaeg","jjwaegg","jjwaegs","jjwaen","jjwaenj","jjwaenh","jjwaed","jjwael","jjwaelg","jjwaelm","jjwaelb"]});var H9=m((G4e,B9)=>{B9.exports=["jjwaels","jjwaelt","jjwaelp","jjwaelh","jjwaem","jjwaeb","jjwaebs","jjwaes","jjwaess","jjwaeng","jjwaej","jjwaec","jjwaek","jjwaet","jjwaep","jjwaeh","jjoe","jjoeg","jjoegg","jjoegs","jjoen","jjoenj","jjoenh","jjoed","jjoel","jjoelg","jjoelm","jjoelb","jjoels","jjoelt","jjoelp","jjoelh","jjoem","jjoeb","jjoebs","jjoes","jjoess","jjoeng","jjoej","jjoec","jjoek","jjoet","jjoep","jjoeh","jjyo","jjyog","jjyogg","jjyogs","jjyon","jjyonj","jjyonh","jjyod","jjyol","jjyolg","jjyolm","jjyolb","jjyols","jjyolt","jjyolp","jjyolh","jjyom","jjyob","jjyobs","jjyos","jjyoss","jjyong","jjyoj","jjyoc","jjyok","jjyot","jjyop","jjyoh","jju","jjug","jjugg","jjugs","jjun","jjunj","jjunh","jjud","jjul","jjulg","jjulm","jjulb","jjuls","jjult","jjulp","jjulh","jjum","jjub","jjubs","jjus","jjuss","jjung","jjuj","jjuc","jjuk","jjut","jjup","jjuh","jjweo","jjweog","jjweogg","jjweogs","jjweon","jjweonj","jjweonh","jjweod","jjweol","jjweolg","jjweolm","jjweolb","jjweols","jjweolt","jjweolp","jjweolh","jjweom","jjweob","jjweobs","jjweos","jjweoss","jjweong","jjweoj","jjweoc","jjweok","jjweot","jjweop","jjweoh","jjwe","jjweg","jjwegg","jjwegs","jjwen","jjwenj","jjwenh","jjwed","jjwel","jjwelg","jjwelm","jjwelb","jjwels","jjwelt","jjwelp","jjwelh","jjwem","jjweb","jjwebs","jjwes","jjwess","jjweng","jjwej","jjwec","jjwek","jjwet","jjwep","jjweh","jjwi","jjwig","jjwigg","jjwigs","jjwin","jjwinj","jjwinh","jjwid","jjwil","jjwilg","jjwilm","jjwilb","jjwils","jjwilt","jjwilp","jjwilh","jjwim","jjwib","jjwibs","jjwis","jjwiss","jjwing","jjwij","jjwic","jjwik","jjwit","jjwip","jjwih","jjyu","jjyug","jjyugg","jjyugs","jjyun","jjyunj","jjyunh","jjyud","jjyul","jjyulg","jjyulm","jjyulb","jjyuls","jjyult","jjyulp","jjyulh","jjyum","jjyub","jjyubs","jjyus","jjyuss","jjyung","jjyuj","jjyuc","jjyuk","jjyut","jjyup","jjyuh","jjeu","jjeug","jjeugg","jjeugs","jjeun","jjeunj","jjeunh","jjeud","jjeul","jjeulg","jjeulm","jjeulb","jjeuls","jjeult","jjeulp","jjeulh","jjeum","jjeub","jjeubs","jjeus","jjeuss","jjeung","jjeuj","jjeuc","jjeuk","jjeut","jjeup","jjeuh","jjyi","jjyig","jjyigg","jjyigs","jjyin","jjyinj","jjyinh","jjyid","jjyil","jjyilg","jjyilm","jjyilb","jjyils","jjyilt","jjyilp","jjyilh"]});var Y9=m((Q4e,q9)=>{q9.exports=["jjyim","jjyib","jjyibs","jjyis","jjyiss","jjying","jjyij","jjyic","jjyik","jjyit","jjyip","jjyih","jji","jjig","jjigg","jjigs","jjin","jjinj","jjinh","jjid","jjil","jjilg","jjilm","jjilb","jjils","jjilt","jjilp","jjilh","jjim","jjib","jjibs","jjis","jjiss","jjing","jjij","jjic","jjik","jjit","jjip","jjih","ca","cag","cagg","cags","can","canj","canh","cad","cal","calg","calm","calb","cals","calt","calp","calh","cam","cab","cabs","cas","cass","cang","caj","cac","cak","cat","cap","cah","cae","caeg","caegg","caegs","caen","caenj","caenh","caed","cael","caelg","caelm","caelb","caels","caelt","caelp","caelh","caem","caeb","caebs","caes","caess","caeng","caej","caec","caek","caet","caep","caeh","cya","cyag","cyagg","cyags","cyan","cyanj","cyanh","cyad","cyal","cyalg","cyalm","cyalb","cyals","cyalt","cyalp","cyalh","cyam","cyab","cyabs","cyas","cyass","cyang","cyaj","cyac","cyak","cyat","cyap","cyah","cyae","cyaeg","cyaegg","cyaegs","cyaen","cyaenj","cyaenh","cyaed","cyael","cyaelg","cyaelm","cyaelb","cyaels","cyaelt","cyaelp","cyaelh","cyaem","cyaeb","cyaebs","cyaes","cyaess","cyaeng","cyaej","cyaec","cyaek","cyaet","cyaep","cyaeh","ceo","ceog","ceogg","ceogs","ceon","ceonj","ceonh","ceod","ceol","ceolg","ceolm","ceolb","ceols","ceolt","ceolp","ceolh","ceom","ceob","ceobs","ceos","ceoss","ceong","ceoj","ceoc","ceok","ceot","ceop","ceoh","ce","ceg","cegg","cegs","cen","cenj","cenh","ced","cel","celg","celm","celb","cels","celt","celp","celh","cem","ceb","cebs","ces","cess","ceng","cej","cec","cek","cet","cep","ceh","cyeo","cyeog","cyeogg","cyeogs","cyeon","cyeonj","cyeonh","cyeod","cyeol","cyeolg","cyeolm","cyeolb","cyeols","cyeolt","cyeolp","cyeolh","cyeom","cyeob","cyeobs","cyeos","cyeoss","cyeong","cyeoj","cyeoc","cyeok","cyeot","cyeop","cyeoh","cye","cyeg","cyegg","cyegs","cyen","cyenj","cyenh","cyed","cyel","cyelg","cyelm","cyelb","cyels","cyelt","cyelp","cyelh","cyem","cyeb","cyebs","cyes"]});var Z9=m((K4e,W9)=>{W9.exports=["cyess","cyeng","cyej","cyec","cyek","cyet","cyep","cyeh","co","cog","cogg","cogs","con","conj","conh","cod","col","colg","colm","colb","cols","colt","colp","colh","com","cob","cobs","cos","coss","cong","coj","coc","cok","cot","cop","coh","cwa","cwag","cwagg","cwags","cwan","cwanj","cwanh","cwad","cwal","cwalg","cwalm","cwalb","cwals","cwalt","cwalp","cwalh","cwam","cwab","cwabs","cwas","cwass","cwang","cwaj","cwac","cwak","cwat","cwap","cwah","cwae","cwaeg","cwaegg","cwaegs","cwaen","cwaenj","cwaenh","cwaed","cwael","cwaelg","cwaelm","cwaelb","cwaels","cwaelt","cwaelp","cwaelh","cwaem","cwaeb","cwaebs","cwaes","cwaess","cwaeng","cwaej","cwaec","cwaek","cwaet","cwaep","cwaeh","coe","coeg","coegg","coegs","coen","coenj","coenh","coed","coel","coelg","coelm","coelb","coels","coelt","coelp","coelh","coem","coeb","coebs","coes","coess","coeng","coej","coec","coek","coet","coep","coeh","cyo","cyog","cyogg","cyogs","cyon","cyonj","cyonh","cyod","cyol","cyolg","cyolm","cyolb","cyols","cyolt","cyolp","cyolh","cyom","cyob","cyobs","cyos","cyoss","cyong","cyoj","cyoc","cyok","cyot","cyop","cyoh","cu","cug","cugg","cugs","cun","cunj","cunh","cud","cul","culg","culm","culb","culs","cult","culp","culh","cum","cub","cubs","cus","cuss","cung","cuj","cuc","cuk","cut","cup","cuh","cweo","cweog","cweogg","cweogs","cweon","cweonj","cweonh","cweod","cweol","cweolg","cweolm","cweolb","cweols","cweolt","cweolp","cweolh","cweom","cweob","cweobs","cweos","cweoss","cweong","cweoj","cweoc","cweok","cweot","cweop","cweoh","cwe","cweg","cwegg","cwegs","cwen","cwenj","cwenh","cwed","cwel","cwelg","cwelm","cwelb","cwels","cwelt","cwelp","cwelh","cwem","cweb","cwebs","cwes","cwess","cweng","cwej","cwec","cwek","cwet","cwep","cweh","cwi","cwig","cwigg","cwigs","cwin","cwinj","cwinh","cwid","cwil","cwilg","cwilm","cwilb","cwils","cwilt","cwilp","cwilh","cwim","cwib","cwibs","cwis","cwiss","cwing","cwij","cwic"]});var $9=m((z4e,J9)=>{J9.exports=["cwik","cwit","cwip","cwih","cyu","cyug","cyugg","cyugs","cyun","cyunj","cyunh","cyud","cyul","cyulg","cyulm","cyulb","cyuls","cyult","cyulp","cyulh","cyum","cyub","cyubs","cyus","cyuss","cyung","cyuj","cyuc","cyuk","cyut","cyup","cyuh","ceu","ceug","ceugg","ceugs","ceun","ceunj","ceunh","ceud","ceul","ceulg","ceulm","ceulb","ceuls","ceult","ceulp","ceulh","ceum","ceub","ceubs","ceus","ceuss","ceung","ceuj","ceuc","ceuk","ceut","ceup","ceuh","cyi","cyig","cyigg","cyigs","cyin","cyinj","cyinh","cyid","cyil","cyilg","cyilm","cyilb","cyils","cyilt","cyilp","cyilh","cyim","cyib","cyibs","cyis","cyiss","cying","cyij","cyic","cyik","cyit","cyip","cyih","ci","cig","cigg","cigs","cin","cinj","cinh","cid","cil","cilg","cilm","cilb","cils","cilt","cilp","cilh","cim","cib","cibs","cis","ciss","cing","cij","cic","cik","cit","cip","cih","ka","kag","kagg","kags","kan","kanj","kanh","kad","kal","kalg","kalm","kalb","kals","kalt","kalp","kalh","kam","kab","kabs","kas","kass","kang","kaj","kac","kak","kat","kap","kah","kae","kaeg","kaegg","kaegs","kaen","kaenj","kaenh","kaed","kael","kaelg","kaelm","kaelb","kaels","kaelt","kaelp","kaelh","kaem","kaeb","kaebs","kaes","kaess","kaeng","kaej","kaec","kaek","kaet","kaep","kaeh","kya","kyag","kyagg","kyags","kyan","kyanj","kyanh","kyad","kyal","kyalg","kyalm","kyalb","kyals","kyalt","kyalp","kyalh","kyam","kyab","kyabs","kyas","kyass","kyang","kyaj","kyac","kyak","kyat","kyap","kyah","kyae","kyaeg","kyaegg","kyaegs","kyaen","kyaenj","kyaenh","kyaed","kyael","kyaelg","kyaelm","kyaelb","kyaels","kyaelt","kyaelp","kyaelh","kyaem","kyaeb","kyaebs","kyaes","kyaess","kyaeng","kyaej","kyaec","kyaek","kyaet","kyaep","kyaeh","keo","keog","keogg","keogs","keon","keonj","keonh","keod","keol","keolg","keolm","keolb","keols","keolt","keolp","keolh","keom","keob","keobs","keos","keoss","keong","keoj","keoc","keok","keot","keop","keoh"]});var U9=m((V4e,X9)=>{X9.exports=["ke","keg","kegg","kegs","ken","kenj","kenh","ked","kel","kelg","kelm","kelb","kels","kelt","kelp","kelh","kem","keb","kebs","kes","kess","keng","kej","kec","kek","ket","kep","keh","kyeo","kyeog","kyeogg","kyeogs","kyeon","kyeonj","kyeonh","kyeod","kyeol","kyeolg","kyeolm","kyeolb","kyeols","kyeolt","kyeolp","kyeolh","kyeom","kyeob","kyeobs","kyeos","kyeoss","kyeong","kyeoj","kyeoc","kyeok","kyeot","kyeop","kyeoh","kye","kyeg","kyegg","kyegs","kyen","kyenj","kyenh","kyed","kyel","kyelg","kyelm","kyelb","kyels","kyelt","kyelp","kyelh","kyem","kyeb","kyebs","kyes","kyess","kyeng","kyej","kyec","kyek","kyet","kyep","kyeh","ko","kog","kogg","kogs","kon","konj","konh","kod","kol","kolg","kolm","kolb","kols","kolt","kolp","kolh","kom","kob","kobs","kos","koss","kong","koj","koc","kok","kot","kop","koh","kwa","kwag","kwagg","kwags","kwan","kwanj","kwanh","kwad","kwal","kwalg","kwalm","kwalb","kwals","kwalt","kwalp","kwalh","kwam","kwab","kwabs","kwas","kwass","kwang","kwaj","kwac","kwak","kwat","kwap","kwah","kwae","kwaeg","kwaegg","kwaegs","kwaen","kwaenj","kwaenh","kwaed","kwael","kwaelg","kwaelm","kwaelb","kwaels","kwaelt","kwaelp","kwaelh","kwaem","kwaeb","kwaebs","kwaes","kwaess","kwaeng","kwaej","kwaec","kwaek","kwaet","kwaep","kwaeh","koe","koeg","koegg","koegs","koen","koenj","koenh","koed","koel","koelg","koelm","koelb","koels","koelt","koelp","koelh","koem","koeb","koebs","koes","koess","koeng","koej","koec","koek","koet","koep","koeh","kyo","kyog","kyogg","kyogs","kyon","kyonj","kyonh","kyod","kyol","kyolg","kyolm","kyolb","kyols","kyolt","kyolp","kyolh","kyom","kyob","kyobs","kyos","kyoss","kyong","kyoj","kyoc","kyok","kyot","kyop","kyoh","ku","kug","kugg","kugs","kun","kunj","kunh","kud","kul","kulg","kulm","kulb","kuls","kult","kulp","kulh","kum","kub","kubs","kus","kuss","kung","kuj","kuc","kuk","kut","kup","kuh","kweo","kweog","kweogg","kweogs"]});var Q9=m((eQe,G9)=>{G9.exports=["kweon","kweonj","kweonh","kweod","kweol","kweolg","kweolm","kweolb","kweols","kweolt","kweolp","kweolh","kweom","kweob","kweobs","kweos","kweoss","kweong","kweoj","kweoc","kweok","kweot","kweop","kweoh","kwe","kweg","kwegg","kwegs","kwen","kwenj","kwenh","kwed","kwel","kwelg","kwelm","kwelb","kwels","kwelt","kwelp","kwelh","kwem","kweb","kwebs","kwes","kwess","kweng","kwej","kwec","kwek","kwet","kwep","kweh","kwi","kwig","kwigg","kwigs","kwin","kwinj","kwinh","kwid","kwil","kwilg","kwilm","kwilb","kwils","kwilt","kwilp","kwilh","kwim","kwib","kwibs","kwis","kwiss","kwing","kwij","kwic","kwik","kwit","kwip","kwih","kyu","kyug","kyugg","kyugs","kyun","kyunj","kyunh","kyud","kyul","kyulg","kyulm","kyulb","kyuls","kyult","kyulp","kyulh","kyum","kyub","kyubs","kyus","kyuss","kyung","kyuj","kyuc","kyuk","kyut","kyup","kyuh","keu","keug","keugg","keugs","keun","keunj","keunh","keud","keul","keulg","keulm","keulb","keuls","keult","keulp","keulh","keum","keub","keubs","keus","keuss","keung","keuj","keuc","keuk","keut","keup","keuh","kyi","kyig","kyigg","kyigs","kyin","kyinj","kyinh","kyid","kyil","kyilg","kyilm","kyilb","kyils","kyilt","kyilp","kyilh","kyim","kyib","kyibs","kyis","kyiss","kying","kyij","kyic","kyik","kyit","kyip","kyih","ki","kig","kigg","kigs","kin","kinj","kinh","kid","kil","kilg","kilm","kilb","kils","kilt","kilp","kilh","kim","kib","kibs","kis","kiss","king","kij","kic","kik","kit","kip","kih","ta","tag","tagg","tags","tan","tanj","tanh","tad","tal","talg","talm","talb","tals","talt","talp","talh","tam","tab","tabs","tas","tass","tang","taj","tac","tak","tat","tap","tah","tae","taeg","taegg","taegs","taen","taenj","taenh","taed","tael","taelg","taelm","taelb","taels","taelt","taelp","taelh","taem","taeb","taebs","taes","taess","taeng","taej","taec","taek","taet","taep","taeh","tya","tyag","tyagg","tyags","tyan","tyanj","tyanh","tyad"]});var z9=m((tQe,K9)=>{K9.exports=["tyal","tyalg","tyalm","tyalb","tyals","tyalt","tyalp","tyalh","tyam","tyab","tyabs","tyas","tyass","tyang","tyaj","tyac","tyak","tyat","tyap","tyah","tyae","tyaeg","tyaegg","tyaegs","tyaen","tyaenj","tyaenh","tyaed","tyael","tyaelg","tyaelm","tyaelb","tyaels","tyaelt","tyaelp","tyaelh","tyaem","tyaeb","tyaebs","tyaes","tyaess","tyaeng","tyaej","tyaec","tyaek","tyaet","tyaep","tyaeh","teo","teog","teogg","teogs","teon","teonj","teonh","teod","teol","teolg","teolm","teolb","teols","teolt","teolp","teolh","teom","teob","teobs","teos","teoss","teong","teoj","teoc","teok","teot","teop","teoh","te","teg","tegg","tegs","ten","tenj","tenh","ted","tel","telg","telm","telb","tels","telt","telp","telh","tem","teb","tebs","tes","tess","teng","tej","tec","tek","tet","tep","teh","tyeo","tyeog","tyeogg","tyeogs","tyeon","tyeonj","tyeonh","tyeod","tyeol","tyeolg","tyeolm","tyeolb","tyeols","tyeolt","tyeolp","tyeolh","tyeom","tyeob","tyeobs","tyeos","tyeoss","tyeong","tyeoj","tyeoc","tyeok","tyeot","tyeop","tyeoh","tye","tyeg","tyegg","tyegs","tyen","tyenj","tyenh","tyed","tyel","tyelg","tyelm","tyelb","tyels","tyelt","tyelp","tyelh","tyem","tyeb","tyebs","tyes","tyess","tyeng","tyej","tyec","tyek","tyet","tyep","tyeh","to","tog","togg","togs","ton","tonj","tonh","tod","tol","tolg","tolm","tolb","tols","tolt","tolp","tolh","tom","tob","tobs","tos","toss","tong","toj","toc","tok","tot","top","toh","twa","twag","twagg","twags","twan","twanj","twanh","twad","twal","twalg","twalm","twalb","twals","twalt","twalp","twalh","twam","twab","twabs","twas","twass","twang","twaj","twac","twak","twat","twap","twah","twae","twaeg","twaegg","twaegs","twaen","twaenj","twaenh","twaed","twael","twaelg","twaelm","twaelb","twaels","twaelt","twaelp","twaelh","twaem","twaeb","twaebs","twaes","twaess","twaeng","twaej","twaec","twaek","twaet","twaep","twaeh","toe","toeg","toegg","toegs","toen","toenj","toenh","toed","toel","toelg","toelm","toelb"]});var eV=m((iQe,V9)=>{V9.exports=["toels","toelt","toelp","toelh","toem","toeb","toebs","toes","toess","toeng","toej","toec","toek","toet","toep","toeh","tyo","tyog","tyogg","tyogs","tyon","tyonj","tyonh","tyod","tyol","tyolg","tyolm","tyolb","tyols","tyolt","tyolp","tyolh","tyom","tyob","tyobs","tyos","tyoss","tyong","tyoj","tyoc","tyok","tyot","tyop","tyoh","tu","tug","tugg","tugs","tun","tunj","tunh","tud","tul","tulg","tulm","tulb","tuls","tult","tulp","tulh","tum","tub","tubs","tus","tuss","tung","tuj","tuc","tuk","tut","tup","tuh","tweo","tweog","tweogg","tweogs","tweon","tweonj","tweonh","tweod","tweol","tweolg","tweolm","tweolb","tweols","tweolt","tweolp","tweolh","tweom","tweob","tweobs","tweos","tweoss","tweong","tweoj","tweoc","tweok","tweot","tweop","tweoh","twe","tweg","twegg","twegs","twen","twenj","twenh","twed","twel","twelg","twelm","twelb","twels","twelt","twelp","twelh","twem","tweb","twebs","twes","twess","tweng","twej","twec","twek","twet","twep","tweh","twi","twig","twigg","twigs","twin","twinj","twinh","twid","twil","twilg","twilm","twilb","twils","twilt","twilp","twilh","twim","twib","twibs","twis","twiss","twing","twij","twic","twik","twit","twip","twih","tyu","tyug","tyugg","tyugs","tyun","tyunj","tyunh","tyud","tyul","tyulg","tyulm","tyulb","tyuls","tyult","tyulp","tyulh","tyum","tyub","tyubs","tyus","tyuss","tyung","tyuj","tyuc","tyuk","tyut","tyup","tyuh","teu","teug","teugg","teugs","teun","teunj","teunh","teud","teul","teulg","teulm","teulb","teuls","teult","teulp","teulh","teum","teub","teubs","teus","teuss","teung","teuj","teuc","teuk","teut","teup","teuh","tyi","tyig","tyigg","tyigs","tyin","tyinj","tyinh","tyid","tyil","tyilg","tyilm","tyilb","tyils","tyilt","tyilp","tyilh","tyim","tyib","tyibs","tyis","tyiss","tying","tyij","tyic","tyik","tyit","tyip","tyih","ti","tig","tigg","tigs","tin","tinj","tinh","tid","til","tilg","tilm","tilb","tils","tilt","tilp","tilh"]});var iV=m((nQe,tV)=>{tV.exports=["tim","tib","tibs","tis","tiss","ting","tij","tic","tik","tit","tip","tih","pa","pag","pagg","pags","pan","panj","panh","pad","pal","palg","palm","palb","pals","palt","palp","palh","pam","pab","pabs","pas","pass","pang","paj","pac","pak","pat","pap","pah","pae","paeg","paegg","paegs","paen","paenj","paenh","paed","pael","paelg","paelm","paelb","paels","paelt","paelp","paelh","paem","paeb","paebs","paes","paess","paeng","paej","paec","paek","paet","paep","paeh","pya","pyag","pyagg","pyags","pyan","pyanj","pyanh","pyad","pyal","pyalg","pyalm","pyalb","pyals","pyalt","pyalp","pyalh","pyam","pyab","pyabs","pyas","pyass","pyang","pyaj","pyac","pyak","pyat","pyap","pyah","pyae","pyaeg","pyaegg","pyaegs","pyaen","pyaenj","pyaenh","pyaed","pyael","pyaelg","pyaelm","pyaelb","pyaels","pyaelt","pyaelp","pyaelh","pyaem","pyaeb","pyaebs","pyaes","pyaess","pyaeng","pyaej","pyaec","pyaek","pyaet","pyaep","pyaeh","peo","peog","peogg","peogs","peon","peonj","peonh","peod","peol","peolg","peolm","peolb","peols","peolt","peolp","peolh","peom","peob","peobs","peos","peoss","peong","peoj","peoc","peok","peot","peop","peoh","pe","peg","pegg","pegs","pen","penj","penh","ped","pel","pelg","pelm","pelb","pels","pelt","pelp","pelh","pem","peb","pebs","pes","pess","peng","pej","pec","pek","pet","pep","peh","pyeo","pyeog","pyeogg","pyeogs","pyeon","pyeonj","pyeonh","pyeod","pyeol","pyeolg","pyeolm","pyeolb","pyeols","pyeolt","pyeolp","pyeolh","pyeom","pyeob","pyeobs","pyeos","pyeoss","pyeong","pyeoj","pyeoc","pyeok","pyeot","pyeop","pyeoh","pye","pyeg","pyegg","pyegs","pyen","pyenj","pyenh","pyed","pyel","pyelg","pyelm","pyelb","pyels","pyelt","pyelp","pyelh","pyem","pyeb","pyebs","pyes","pyess","pyeng","pyej","pyec","pyek","pyet","pyep","pyeh","po","pog","pogg","pogs","pon","ponj","ponh","pod","pol","polg","polm","polb","pols","polt","polp","polh","pom","pob","pobs","pos"]});var rV=m((rQe,nV)=>{nV.exports=["poss","pong","poj","poc","pok","pot","pop","poh","pwa","pwag","pwagg","pwags","pwan","pwanj","pwanh","pwad","pwal","pwalg","pwalm","pwalb","pwals","pwalt","pwalp","pwalh","pwam","pwab","pwabs","pwas","pwass","pwang","pwaj","pwac","pwak","pwat","pwap","pwah","pwae","pwaeg","pwaegg","pwaegs","pwaen","pwaenj","pwaenh","pwaed","pwael","pwaelg","pwaelm","pwaelb","pwaels","pwaelt","pwaelp","pwaelh","pwaem","pwaeb","pwaebs","pwaes","pwaess","pwaeng","pwaej","pwaec","pwaek","pwaet","pwaep","pwaeh","poe","poeg","poegg","poegs","poen","poenj","poenh","poed","poel","poelg","poelm","poelb","poels","poelt","poelp","poelh","poem","poeb","poebs","poes","poess","poeng","poej","poec","poek","poet","poep","poeh","pyo","pyog","pyogg","pyogs","pyon","pyonj","pyonh","pyod","pyol","pyolg","pyolm","pyolb","pyols","pyolt","pyolp","pyolh","pyom","pyob","pyobs","pyos","pyoss","pyong","pyoj","pyoc","pyok","pyot","pyop","pyoh","pu","pug","pugg","pugs","pun","punj","punh","pud","pul","pulg","pulm","pulb","puls","pult","pulp","pulh","pum","pub","pubs","pus","puss","pung","puj","puc","puk","put","pup","puh","pweo","pweog","pweogg","pweogs","pweon","pweonj","pweonh","pweod","pweol","pweolg","pweolm","pweolb","pweols","pweolt","pweolp","pweolh","pweom","pweob","pweobs","pweos","pweoss","pweong","pweoj","pweoc","pweok","pweot","pweop","pweoh","pwe","pweg","pwegg","pwegs","pwen","pwenj","pwenh","pwed","pwel","pwelg","pwelm","pwelb","pwels","pwelt","pwelp","pwelh","pwem","pweb","pwebs","pwes","pwess","pweng","pwej","pwec","pwek","pwet","pwep","pweh","pwi","pwig","pwigg","pwigs","pwin","pwinj","pwinh","pwid","pwil","pwilg","pwilm","pwilb","pwils","pwilt","pwilp","pwilh","pwim","pwib","pwibs","pwis","pwiss","pwing","pwij","pwic","pwik","pwit","pwip","pwih","pyu","pyug","pyugg","pyugs","pyun","pyunj","pyunh","pyud","pyul","pyulg","pyulm","pyulb","pyuls","pyult","pyulp","pyulh","pyum","pyub","pyubs","pyus","pyuss","pyung","pyuj","pyuc"]});var sV=m((oQe,oV)=>{oV.exports=["pyuk","pyut","pyup","pyuh","peu","peug","peugg","peugs","peun","peunj","peunh","peud","peul","peulg","peulm","peulb","peuls","peult","peulp","peulh","peum","peub","peubs","peus","peuss","peung","peuj","peuc","peuk","peut","peup","peuh","pyi","pyig","pyigg","pyigs","pyin","pyinj","pyinh","pyid","pyil","pyilg","pyilm","pyilb","pyils","pyilt","pyilp","pyilh","pyim","pyib","pyibs","pyis","pyiss","pying","pyij","pyic","pyik","pyit","pyip","pyih","pi","pig","pigg","pigs","pin","pinj","pinh","pid","pil","pilg","pilm","pilb","pils","pilt","pilp","pilh","pim","pib","pibs","pis","piss","ping","pij","pic","pik","pit","pip","pih","ha","hag","hagg","hags","han","hanj","hanh","had","hal","halg","halm","halb","hals","halt","halp","halh","ham","hab","habs","has","hass","hang","haj","hac","hak","hat","hap","hah","hae","haeg","haegg","haegs","haen","haenj","haenh","haed","hael","haelg","haelm","haelb","haels","haelt","haelp","haelh","haem","haeb","haebs","haes","haess","haeng","haej","haec","haek","haet","haep","haeh","hya","hyag","hyagg","hyags","hyan","hyanj","hyanh","hyad","hyal","hyalg","hyalm","hyalb","hyals","hyalt","hyalp","hyalh","hyam","hyab","hyabs","hyas","hyass","hyang","hyaj","hyac","hyak","hyat","hyap","hyah","hyae","hyaeg","hyaegg","hyaegs","hyaen","hyaenj","hyaenh","hyaed","hyael","hyaelg","hyaelm","hyaelb","hyaels","hyaelt","hyaelp","hyaelh","hyaem","hyaeb","hyaebs","hyaes","hyaess","hyaeng","hyaej","hyaec","hyaek","hyaet","hyaep","hyaeh","heo","heog","heogg","heogs","heon","heonj","heonh","heod","heol","heolg","heolm","heolb","heols","heolt","heolp","heolh","heom","heob","heobs","heos","heoss","heong","heoj","heoc","heok","heot","heop","heoh","he","heg","hegg","hegs","hen","henj","henh","hed","hel","helg","helm","helb","hels","helt","help","helh","hem","heb","hebs","hes","hess","heng","hej","hec","hek","het","hep","heh"]});var lV=m((sQe,aV)=>{aV.exports=["hyeo","hyeog","hyeogg","hyeogs","hyeon","hyeonj","hyeonh","hyeod","hyeol","hyeolg","hyeolm","hyeolb","hyeols","hyeolt","hyeolp","hyeolh","hyeom","hyeob","hyeobs","hyeos","hyeoss","hyeong","hyeoj","hyeoc","hyeok","hyeot","hyeop","hyeoh","hye","hyeg","hyegg","hyegs","hyen","hyenj","hyenh","hyed","hyel","hyelg","hyelm","hyelb","hyels","hyelt","hyelp","hyelh","hyem","hyeb","hyebs","hyes","hyess","hyeng","hyej","hyec","hyek","hyet","hyep","hyeh","ho","hog","hogg","hogs","hon","honj","honh","hod","hol","holg","holm","holb","hols","holt","holp","holh","hom","hob","hobs","hos","hoss","hong","hoj","hoc","hok","hot","hop","hoh","hwa","hwag","hwagg","hwags","hwan","hwanj","hwanh","hwad","hwal","hwalg","hwalm","hwalb","hwals","hwalt","hwalp","hwalh","hwam","hwab","hwabs","hwas","hwass","hwang","hwaj","hwac","hwak","hwat","hwap","hwah","hwae","hwaeg","hwaegg","hwaegs","hwaen","hwaenj","hwaenh","hwaed","hwael","hwaelg","hwaelm","hwaelb","hwaels","hwaelt","hwaelp","hwaelh","hwaem","hwaeb","hwaebs","hwaes","hwaess","hwaeng","hwaej","hwaec","hwaek","hwaet","hwaep","hwaeh","hoe","hoeg","hoegg","hoegs","hoen","hoenj","hoenh","hoed","hoel","hoelg","hoelm","hoelb","hoels","hoelt","hoelp","hoelh","hoem","hoeb","hoebs","hoes","hoess","hoeng","hoej","hoec","hoek","hoet","hoep","hoeh","hyo","hyog","hyogg","hyogs","hyon","hyonj","hyonh","hyod","hyol","hyolg","hyolm","hyolb","hyols","hyolt","hyolp","hyolh","hyom","hyob","hyobs","hyos","hyoss","hyong","hyoj","hyoc","hyok","hyot","hyop","hyoh","hu","hug","hugg","hugs","hun","hunj","hunh","hud","hul","hulg","hulm","hulb","huls","hult","hulp","hulh","hum","hub","hubs","hus","huss","hung","huj","huc","huk","hut","hup","huh","hweo","hweog","hweogg","hweogs","hweon","hweonj","hweonh","hweod","hweol","hweolg","hweolm","hweolb","hweols","hweolt","hweolp","hweolh","hweom","hweob","hweobs","hweos","hweoss","hweong","hweoj","hweoc","hweok","hweot","hweop","hweoh","hwe","hweg","hwegg","hwegs"]});var cV=m((aQe,uV)=>{uV.exports=["hwen","hwenj","hwenh","hwed","hwel","hwelg","hwelm","hwelb","hwels","hwelt","hwelp","hwelh","hwem","hweb","hwebs","hwes","hwess","hweng","hwej","hwec","hwek","hwet","hwep","hweh","hwi","hwig","hwigg","hwigs","hwin","hwinj","hwinh","hwid","hwil","hwilg","hwilm","hwilb","hwils","hwilt","hwilp","hwilh","hwim","hwib","hwibs","hwis","hwiss","hwing","hwij","hwic","hwik","hwit","hwip","hwih","hyu","hyug","hyugg","hyugs","hyun","hyunj","hyunh","hyud","hyul","hyulg","hyulm","hyulb","hyuls","hyult","hyulp","hyulh","hyum","hyub","hyubs","hyus","hyuss","hyung","hyuj","hyuc","hyuk","hyut","hyup","hyuh","heu","heug","heugg","heugs","heun","heunj","heunh","heud","heul","heulg","heulm","heulb","heuls","heult","heulp","heulh","heum","heub","heubs","heus","heuss","heung","heuj","heuc","heuk","heut","heup","heuh","hyi","hyig","hyigg","hyigs","hyin","hyinj","hyinh","hyid","hyil","hyilg","hyilm","hyilb","hyils","hyilt","hyilp","hyilh","hyim","hyib","hyibs","hyis","hyiss","hying","hyij","hyic","hyik","hyit","hyip","hyih","hi","hig","higg","higs","hin","hinj","hinh","hid","hil","hilg","hilm","hilb","hils","hilt","hilp","hilh","him","hib","hibs","his","hiss","hing","hij","hic","hik","hit","hip","hih","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var dV=m((lQe,hV)=>{hV.exports=["Kay ","Kayng ","Ke ","Ko ","Kol ","Koc ","Kwi ","Kwi ","Kyun ","Kul ","Kum ","Na ","Na ","Na ","La ","Na ","Na ","Na ","Na ","Na ","Nak ","Nak ","Nak ","Nak ","Nak ","Nak ","Nak ","Nan ","Nan ","Nan ","Nan ","Nan ","Nan ","Nam ","Nam ","Nam ","Nam ","Nap ","Nap ","Nap ","Nang ","Nang ","Nang ","Nang ","Nang ","Nay ","Nayng ","No ","No ","No ","No ","No ","No ","No ","No ","No ","No ","No ","No ","Nok ","Nok ","Nok ","Nok ","Nok ","Nok ","Non ","Nong ","Nong ","Nong ","Nong ","Noy ","Noy ","Noy ","Noy ","Nwu ","Nwu ","Nwu ","Nwu ","Nwu ","Nwu ","Nwu ","Nwu ","Nuk ","Nuk ","Num ","Nung ","Nung ","Nung ","Nung ","Nung ","Twu ","La ","Lak ","Lak ","Lan ","Lyeng ","Lo ","Lyul ","Li ","Pey ","Pen ","Pyen ","Pwu ","Pwul ","Pi ","Sak ","Sak ","Sam ","Sayk ","Sayng ","Sep ","Sey ","Sway ","Sin ","Sim ","Sip ","Ya ","Yak ","Yak ","Yang ","Yang ","Yang ","Yang ","Yang ","Yang ","Yang ","Yang ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Ye ","Yek ","Yek ","Yek ","Yek ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yen ","Yel ","Yel ","Yel ","Yel ","Yel ","Yel ","Yem ","Yem ","Yem ","Yem ","Yem ","Yep ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yeng ","Yey ","Yey ","Yey ","Yey ","O ","Yo ","Yo ","Yo ","Yo ","Yo ","Yo ","Yo ","Yo ","Yo ","Yo ","Yong ","Wun ","Wen ","Yu ","Yu ","Yu ","Yu ","Yu ","Yu ","Yu ","Yu ","Yu ","Yu ","Yuk ","Yuk ","Yuk ","Yun ","Yun ","Yun ","Yun ","Yul ","Yul ","Yul ","Yul ","Yung ","I ","I ","I ","I ","I ","I ","I ","I ","I ","I ","I ","I ","I ","I ","Ik ","Ik ","In ","In ","In ","In ","In ","In ","In ","Im ","Im ","Im ","Ip ","Ip ","Ip ","Cang ","Cek ","Ci ","Cip ","Cha ","Chek "]});var fV=m((uQe,gV)=>{gV.exports=["Chey ","Thak ","Thak ","Thang ","Thayk ","Thong ","Pho ","Phok ","Hang ","Hang ","Hyen ","Hwak ","Wu ","Huo ","[?] ","[?] ","Zhong ","[?] ","Qing ","[?] ","[?] ","Xi ","Zhu ","Yi ","Li ","Shen ","Xiang ","Fu ","Jing ","Jing ","Yu ","[?] ","Hagi ","[?] ","Zhu ","[?] ","[?] ","Yi ","Du ","[?] ","[?] ","[?] ","Fan ","Si ","Guan ","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]"]});var mV=m((cQe,pV)=>{pV.exports=["ff","fi","fl","ffi","ffl","st","st","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","mn","me","mi","vn","mkh","[?]","[?]","[?]","[?]","[?]","yi","","ay","`","","d","h","k","l","m","m","t","+","sh","s","sh","s","a","a","","b","g","d","h","v","z","[?]","t","y","k","k","l","[?]","l","[?]","n","n","[?]","p","p","[?]","ts","ts","r","sh","t","vo","b","k","p","l","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]});var yV=m((hQe,bV)=>{bV.exports=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]});var wV=m((dQe,vV)=>{vV.exports=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","","","","","","","","","","[?]","[?]","[?]"]});var xV=m((gQe,DV)=>{DV.exports=["[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","","","","~","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","..","--","-","_","_","(",") ","{","} ","[","] ","[(",")] ","<<",">> ","<","> ","[","] ","{","}","[?]","[?]","[?]","[?]","","","","","","","",",",",",".","",";",":","?","!","-","(",")","{","}","{","}","#","&","*","+","-","<",">","=","","\\","$","%","@","[?]","[?]","[?]","[?]","","","","[?]","","[?]","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","[?]","[?]",""]});var SV=m((fQe,CV)=>{CV.exports=["[?]","!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","[?]","[?]",".","[","]",",","*","wo","a","i","u","e","o","ya","yu","yo","tu","+","a","i","u","e","o","ka","ki","ku","ke","ko","sa","si","su","se","so","ta","ti","tu","te","to","na","ni","nu","ne","no","ha","hi","hu","he","ho","ma","mi","mu","me","mo","ya","yu","yo","ra","ri","ru","re","ro","wa","n",":",";","","g","gg","gs","n","nj","nh","d","dd","r","lg","lm","lb","ls","lt","lp","rh","m","b","bb","bs","s","ss","","j","jj","c","k","t","p","h","[?]","[?]","[?]","a","ae","ya","yae","eo","e","[?]","[?]","yeo","ye","o","wa","wae","oe","[?]","[?]","yo","u","weo","we","wi","yu","[?]","[?]","eu","yi","i","[?]","[?]","[?]","/C","PS","!","-","|","Y=","W=","[?]","|","-","|","-","|","#","O","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","[?]","{","|","}","","","",""]});var kV=m((pQe,TV)=>{"use strict";var R={},C0e=/(?![\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})./g;TV.exports=function(n){return n.replace(C0e,S0e)};function S0e(n){var e=k0e(n);if(e>65535)return"_";var t=e>>8,i=e&255;if(t>24&&t<30||t>215&&t<249)return"";if(!R[t])switch(T0e(t)){case"00":R[t]=Z4();break;case"01":R[t]=$4();break;case"02":R[t]=U4();break;case"03":R[t]=Q4();break;case"04":R[t]=z4();break;case"05":R[t]=eQ();break;case"06":R[t]=iQ();break;case"07":R[t]=rQ();break;case"09":R[t]=sQ();break;case"0a":R[t]=lQ();break;case"0b":R[t]=cQ();break;case"0c":R[t]=dQ();break;case"0d":R[t]=fQ();break;case"0e":R[t]=mQ();break;case"0f":R[t]=yQ();break;case"10":R[t]=wQ();break;case"11":R[t]=xQ();break;case"12":R[t]=SQ();break;case"13":R[t]=kQ();break;case"14":R[t]=PQ();break;case"15":R[t]=RQ();break;case"16":R[t]=FQ();break;case"17":R[t]=jQ();break;case"18":R[t]=OQ();break;case"1e":R[t]=NQ();break;case"1f":R[t]=HQ();break;case"20":R[t]=YQ();break;case"21":R[t]=ZQ();break;case"22":R[t]=$Q();break;case"23":R[t]=UQ();break;case"24":R[t]=QQ();break;case"25":R[t]=zQ();break;case"26":R[t]=eK();break;case"27":R[t]=iK();break;case"28":R[t]=rK();break;case"2e":R[t]=sK();break;case"2f":R[t]=lK();break;case"30":R[t]=cK();break;case"31":R[t]=dK();break;case"32":R[t]=fK();break;case"33":R[t]=mK();break;case"4d":R[t]=yK();break;case"4e":R[t]=wK();break;case"4f":R[t]=xK();break;case"50":R[t]=SK();break;case"51":R[t]=kK();break;case"52":R[t]=PK();break;case"53":R[t]=RK();break;case"54":R[t]=FK();break;case"55":R[t]=jK();break;case"56":R[t]=OK();break;case"57":R[t]=NK();break;case"58":R[t]=HK();break;case"59":R[t]=YK();break;case"5a":R[t]=ZK();break;case"5b":R[t]=$K();break;case"5c":R[t]=UK();break;case"5d":R[t]=QK();break;case"5e":R[t]=zK();break;case"5f":R[t]=ez();break;case"60":R[t]=iz();break;case"61":R[t]=rz();break;case"62":R[t]=sz();break;case"63":R[t]=lz();break;case"64":R[t]=cz();break;case"65":R[t]=dz();break;case"66":R[t]=fz();break;case"67":R[t]=mz();break;case"68":R[t]=yz();break;case"69":R[t]=wz();break;case"6a":R[t]=xz();break;case"6b":R[t]=Sz();break;case"6c":R[t]=kz();break;case"6d":R[t]=Pz();break;case"6e":R[t]=Rz();break;case"6f":R[t]=Fz();break;case"70":R[t]=jz();break;case"71":R[t]=Oz();break;case"72":R[t]=Nz();break;case"73":R[t]=Hz();break;case"74":R[t]=Yz();break;case"75":R[t]=Zz();break;case"76":R[t]=$z();break;case"77":R[t]=Uz();break;case"78":R[t]=Qz();break;case"79":R[t]=zz();break;case"7a":R[t]=e5();break;case"7b":R[t]=i5();break;case"7c":R[t]=r5();break;case"7d":R[t]=s5();break;case"7e":R[t]=l5();break;case"7f":R[t]=c5();break;case"80":R[t]=d5();break;case"81":R[t]=f5();break;case"82":R[t]=m5();break;case"83":R[t]=y5();break;case"84":R[t]=w5();break;case"85":R[t]=x5();break;case"86":R[t]=S5();break;case"87":R[t]=k5();break;case"88":R[t]=P5();break;case"89":R[t]=R5();break;case"8a":R[t]=F5();break;case"8b":R[t]=j5();break;case"8c":R[t]=O5();break;case"8d":R[t]=N5();break;case"8e":R[t]=H5();break;case"8f":R[t]=Y5();break;case"90":R[t]=Z5();break;case"91":R[t]=$5();break;case"92":R[t]=U5();break;case"93":R[t]=Q5();break;case"94":R[t]=z5();break;case"95":R[t]=e7();break;case"96":R[t]=i7();break;case"97":R[t]=r7();break;case"98":R[t]=s7();break;case"99":R[t]=l7();break;case"9a":R[t]=c7();break;case"9b":R[t]=d7();break;case"9c":R[t]=f7();break;case"9d":R[t]=m7();break;case"9e":R[t]=y7();break;case"9f":R[t]=w7();break;case"a0":R[t]=x7();break;case"a1":R[t]=S7();break;case"a2":R[t]=k7();break;case"a3":R[t]=P7();break;case"a4":R[t]=R7();break;case"ac":R[t]=F7();break;case"ad":R[t]=j7();break;case"ae":R[t]=O7();break;case"af":R[t]=N7();break;case"b0":R[t]=H7();break;case"b1":R[t]=Y7();break;case"b2":R[t]=Z7();break;case"b3":R[t]=$7();break;case"b4":R[t]=U7();break;case"b5":R[t]=Q7();break;case"b6":R[t]=z7();break;case"b7":R[t]=e9();break;case"b8":R[t]=i9();break;case"b9":R[t]=r9();break;case"ba":R[t]=s9();break;case"bb":R[t]=l9();break;case"bc":R[t]=c9();break;case"bd":R[t]=d9();break;case"be":R[t]=f9();break;case"bf":R[t]=m9();break;case"c0":R[t]=y9();break;case"c1":R[t]=w9();break;case"c2":R[t]=x9();break;case"c3":R[t]=S9();break;case"c4":R[t]=k9();break;case"c5":R[t]=P9();break;case"c6":R[t]=R9();break;case"c7":R[t]=F9();break;case"c8":R[t]=j9();break;case"c9":R[t]=O9();break;case"ca":R[t]=N9();break;case"cb":R[t]=H9();break;case"cc":R[t]=Y9();break;case"cd":R[t]=Z9();break;case"ce":R[t]=$9();break;case"cf":R[t]=U9();break;case"d0":R[t]=Q9();break;case"d1":R[t]=z9();break;case"d2":R[t]=eV();break;case"d3":R[t]=iV();break;case"d4":R[t]=rV();break;case"d5":R[t]=sV();break;case"d6":R[t]=lV();break;case"d7":R[t]=cV();break;case"f9":R[t]=dV();break;case"fa":R[t]=fV();break;case"fb":R[t]=mV();break;case"fc":R[t]=yV();break;case"fd":R[t]=wV();break;case"fe":R[t]=xV();break;case"ff":R[t]=SV();break;default:return""}return R[t][i]}function T0e(n){return(n+256).toString(16).substr(-2)}function k0e(n){for(var e,t,i,r,o,s,a;Array.isArray(n);)n=n[0];switch(n.length){case 1:return Do(n);case 2:return e=Do(n.substr(0,1)),t=Do(n.substr(1,1)),o=(e&3)<<6|t&63,s=(e&28)>>2,s<<8|o;case 3:return e=Do(n.substr(0,1)),t=Do(n.substr(1,1)),i=Do(n.substr(2,1)),o=(t&3)<<6|i&63,s=(e&15)<<4|(t&60)>>2,s<<8|o;default:return e=Do(n.substr(0,1)),t=Do(n.substr(1,1)),i=Do(n.substr(2,1)),r=Do(n.substr(3,1)),o=(i&3)<<6|r&63,s=(t&15)<<4|(i&60)>>2,a=(e&7)<<5|(t&48)>>4,a<<16|s<<8|o}}function Do(n){var e=n+"",t=e.charCodeAt(0);if(55296<=t&&t<=56319){var i=t;if(e.length===1)return t;var r=e.charCodeAt(1);return(i-55296)*1024+(r-56320)+65536}return 56320<=t&&t<=57343,t}});var EV=_(()=>{"use strict"});async function RV(n,e,t,i=""){if(e=="vim")return(await n.eval(t)).toString();if(e=="shell"){let o=await(0,_V.promisify)(PV.exec)(t);return o.stdout.replace(/\s*$/,"")||o.stderr}let r=[`snip._reset("${zf(i)}")`];return r.push(...t.split(/\r?\n/).map(o=>o.replace(/\t/g," "))),await kh(n,r),await n.call("pyxeval","str(snip.rv)")}function aD(n){let{range:e,regex:t,line:i}=n,r=[];if(t&&e!=null){let o=i.slice(e.start.character,e.end.character);r.push(`pattern = re.compile("${zf(t)}")`),r.push(`match = pattern.search("${zf(o)}")`)}else r.push("match = None");return r.join(` -`)}function LV(n){let{range:e,context:t,line:i}=n,r=["import re, os, vim, string, random",`path = vim.eval('expand("%:p")') or ""`,"fn = os.path.basename(path)"];t?(r.push("snip = ContextSnippet()"),r.push(`context = ${t}`)):r.push("context = True");let o=`(${e.start.line},${Buffer.byteLength(i.slice(0,e.start.character))})`,s=`(${e.start.line},${Buffer.byteLength(i.slice(0,e.end.character))})`,a=i.match(/^\s*/)[0];return r.push(`snip = SnippetUtil("${zf(a)}", ${o}, ${s}, context)`),r}async function kh(n,e){try{await n.command(`pyx ${P0e(e.join(` -`))}`)}catch(t){let i=new Error(t instanceof Error?t.message:t.toString());throw i.stack=`Error on execute python code: -${e.join(` -`)} -`+(t instanceof Error?t.stack:t),i}}function Vf(n){let e=Object.keys(n),t=e.length?Math.max.apply(null,e.map(r=>Number(r))):0,i=new Array(t).fill('""');for(let[r,o]of Object.entries(n))i[r]=`"${zf(o)}"`;return`t = (${i.join(",")},)`}function P0e(n,e=!1){if(!E0e&&e===!1)return n;let t=["import traceback, vim","vim.vars['errmsg'] = ''","try:"];return t.push(...n.split(` -`).map(i=>" "+i)),t.push("except Exception as e:"),t.push(" vim.vars['errmsg'] = traceback.format_exc()"),t.join(` -`)}function zf(n){return n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\t/g,"\\t").replace(/\n/g,"\\n")}function FV(n){if(n.indexOf("\\z")!==-1)throw new Error("pattern \\z not supported");if(n.indexOf("(?s)")!==-1)throw new Error("pattern (?s) not supported");if(n.indexOf("(?x)")!==-1)throw new Error("pattern (?x) not supported");if(n.indexOf(` -`)!==-1)throw new Error("pattern \\n not supported");if(R0e.test(n))throw new Error("pattern (?id/name)yes-pattern|no-pattern not supported");return n.replace(j0e,(e,t)=>e=="\\A"?"^":e.startsWith("(?#")?"":e.startsWith("(?P<")?"(?"+e.slice(3):e.startsWith("(?P=")?`\\k<${t}>`:"")}var PV,_V,bQe,E0e,_0e,R0e,L0e,F0e,I0e,j0e,I_=_(()=>{"use strict";PV=require("child_process"),_V=require("util"),bQe=q()("snippets-eval"),E0e=process.env.VIM_NODE_RPC=="1";_0e=/\\A/,R0e=/\(\?\(\w+\).+\|/,L0e=/\(\?#.*?\)/,F0e=/\(\?P<\w+>.*?\)/,I0e=/\(\?P=(\w+)\)/,j0e=new RegExp(`${L0e.source}|${_0e.source}|${F0e.source}|${I0e.source}`,"g")});function IV(n,e){let t=[...n];for(;t.length>0;){let i=t.shift();if(!e(i))break;t.unshift(...i.children)}}function N0e(n,e=[]){let t="",i=n.length,r=0,o=!1,s=!1;for(;r{"use strict";jV=C(kV());Go();EV();Pe();I_();A0e=q()("snippets-parser"),O0e=["d","g","i","m","s","u","y"],Hr=class{static isDigitCharacter(e){return e>=48&&e<=57}static isVariableCharacter(e){return e===95||e>=97&&e<=122||e>=65&&e<=90}constructor(){this.text("")}text(e){this.value=e,this.pos=0}tokenText(e){return this.value.substr(e.pos,e.len)}next(){if(this.pos>=this.value.length)return{type:14,pos:this.pos,len:0};let e=this.pos,t=0,i=this.value.charCodeAt(e),r;if(r=Hr._table[i],typeof r=="number")return this.pos+=1,{type:r,pos:e,len:1};if(Hr.isDigitCharacter(i)){r=8;do t+=1,i=this.value.charCodeAt(e+t);while(Hr.isDigitCharacter(i));return this.pos+=t,{type:r,pos:e,len:t}}if(Hr.isVariableCharacter(i)){r=9;do i=this.value.charCodeAt(e+ ++t);while(Hr.isVariableCharacter(i)||Hr.isDigitCharacter(i));return this.pos+=t,{type:r,pos:e,len:t}}r=10;do t+=1,i=this.value.charCodeAt(e+t);while(!isNaN(i)&&typeof Hr._table[i]>"u"&&!Hr.isDigitCharacter(i)&&!Hr.isVariableCharacter(i));return this.pos+=t,{type:r,pos:e,len:t}}},j_=Hr;j_._table={[36]:0,[58]:1,[44]:2,[123]:3,[125]:4,[92]:5,[47]:6,[124]:7,[43]:11,[45]:12,[63]:13,[40]:15,[41]:16,[96]:17,[33]:18};cs=class{constructor(){this._children=[]}appendChild(e){return e instanceof wt&&this._children[this._children.length-1]instanceof wt?this._children[this._children.length-1].value+=e.value:(e.parent=this,this._children.push(e)),this}setOnlyChild(e){e.parent=this,this._children=[e]}replaceChildren(e){for(let t of e)t.parent=this;this._children=e}get children(){return this._children}get snippet(){let e=this;for(;;){if(!e)return;if(e instanceof ip)return e;e=e.parent}}toString(){return this.children.reduce((e,t)=>e+t.toString(),"")}len(){return 0}},wt=class extends cs{constructor(e){super();this.value=e}static escape(e){return e.replace(/\$|}|\\/g,"\\$&")}toString(){return this.value}toTextmateString(){return wt.escape(this.value)}len(){return this.value.length}clone(){return new wt(this.value)}},us=class extends cs{constructor(e,t,i){super();this.code=e;this.kind=t;this._value="";this._related=[];if(t==="python"){let{_related:r}=this,o,s=/\bt\[(\d+)\]/g;for(;o=s.exec(e),o!=null;){let a=parseInt(o[1],10);r.includes(a)||r.push(a)}}i!==void 0&&(this._value=i)}get related(){return this._related}update(e){if(this.kind!=="python")return;let t=new Set;this.code=this.code.replace(/\bt\[(\d+)\]/g,(i,r)=>{let o=Number(r),s=e.has(o)?e.get(o):o;return t.add(s),`t[${s}]`}),this._related=Array.from(t)}get index(){if(this.parent instanceof nt)return this.parent.index}async resolve(e){if(!this.code.length)return;let t=await RV(e,this.kind,this.code,this._value);t!=null&&(this._value=t)}len(){return this._value.length}toString(){return this._value}get value(){return this._value}toTextmateString(){let e="";return this.kind=="python"?e="!p ":this.kind=="shell"?e="":this.kind=="vim"&&(e="!v "),"`"+e+this.code+"`"}clone(){return new us(this.code,this.kind,this.value)}},A_=class extends cs{},nt=class extends A_{constructor(e){super();this.index=e;this.primary=!1}get isFinalTabstop(){return this.index===0}get choice(){return this._children.length===1&&this._children[0]instanceof ep?this._children[0]:void 0}toTextmateString(){let e="";return this.transform&&(e=this.transform.toTextmateString()),this.children.length===0&&!this.transform?`$${this.index}`:this.children.length===0?`\${${this.index}${e}}`:this.choice?`\${${this.index}|${this.choice.toTextmateString()}|${e}}`:`\${${this.index}:${this.children.map(t=>t.toTextmateString()).join("")}${e}}`}clone(){let e=new nt(this.index);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map(t=>t.clone()),e}},ep=class extends cs{constructor(){super(...arguments);this.options=[]}appendChild(e){return e instanceof wt&&(e.parent=this,this.options.push(e)),this}toString(){return this.options[0].value}toTextmateString(){return this.options.map(e=>e.value.replace(/\||,/g,"\\$&")).join(",")}len(){return this.options[0].len()}clone(){let e=new ep;for(let t of this.options)e.appendChild(t);return e}},lD=class extends cs{constructor(){super(...arguments);this.ascii=!1;this.ultisnip=!1}resolve(e){let t=!1,i=e.replace(this.regexp,(...r)=>(t=!0,this._replace(r.slice(0,-2))));return!t&&this._children.some(r=>r instanceof hr&&Boolean(r.elseValue))&&(i=this._replace([])),i}_replace(e){let t="",i=[];for(let r of this._children)if(r instanceof hr){let o=r.resolve(e[r.index]||"");if(this.ultisnip&&o.indexOf("\\")!==-1){let s=t.length;i.push(...wH(o,"\\").map(a=>a+s))}t+=o}else r instanceof tp?t+=r.resolve(e[r.index]):t+=r.toString();return this.ascii&&(t=(0,jV.default)(t)),this.ultisnip?N0e(t,i):t}toString(){return""}toTextmateString(){return`/${this.regexp.source}/${this.children.map(e=>e.toTextmateString())}/${(this.regexp.ignoreCase?"i":"")+(this.regexp.global?"g":"")}`}clone(){let e=new lD;return e.regexp=new RegExp(this.regexp.source,(this.regexp.ignoreCase?"i":"")+(this.regexp.global?"g":"")),e._children=this.children.map(t=>t.clone()),e}},tp=class extends cs{constructor(e,t,i){super();this.index=e;this.ifValue=t;this.elseValue=i}resolve(e){return e?this.ifValue:this.elseValue}toTextmateString(){return"(?"+this.index+":"+this.ifValue+(this.elseValue?":"+this.elseValue:"")+")"}clone(){return new tp(this.index,this.ifValue,this.elseValue)}},hr=class extends cs{constructor(e,t,i,r){super();this.index=e;this.shorthandName=t;this.ifValue=i;this.elseValue=r}resolve(e){return this.shorthandName==="upcase"?e?e.toLocaleUpperCase():"":this.shorthandName==="downcase"?e?e.toLocaleLowerCase():"":this.shorthandName==="capitalize"?e?e[0].toLocaleUpperCase()+e.substr(1):"":this.shorthandName==="pascalcase"?e?this._toPascalCase(e):"":Boolean(e)&&typeof this.ifValue=="string"?this.ifValue:!e&&typeof this.elseValue=="string"?this.elseValue:e||""}_toPascalCase(e){let t=e.match(/[a-z]+/gi);return t?t.map(i=>i.charAt(0).toUpperCase()+i.substr(1).toLowerCase()).join(""):e}toTextmateString(){let e="${";return e+=this.index,this.shorthandName?e+=`:/${this.shorthandName}`:this.ifValue&&this.elseValue?e+=`:?${this.ifValue}:${this.elseValue}`:this.ifValue?e+=`:+${this.ifValue}`:this.elseValue&&(e+=`:-${this.elseValue}`),e+="}",e}clone(){return new hr(this.index,this.shorthandName,this.ifValue,this.elseValue)}},xo=class extends A_{constructor(e,t){super();this.name=e;this._resolved=!1;typeof t=="boolean"&&(this._resolved=t)}get resolved(){return this._resolved}async resolve(e){let t=await e.resolve(this);if(this._resolved=!0,t&&t.includes(` -`)){let i="";this.snippet.walk(l=>{if(l==this)return!1;if(l instanceof wt){let u=l.toString().split(/\r?\n/);i=u[u.length-1].match(/^\s*/)[0]}return!0});let r=t.split(` -`),o=r.filter(l=>l.length>0).map(l=>l.match(/^\s*/)[0]),s=o.length==0?"":o.reduce((l,u)=>l.lengthu==0||l.length==0||!l.startsWith(s)?l:i+l.slice(s.length)).join(` -`)}return this.transform&&(t=this.transform.resolve(t||"")),t!==void 0?(this._children=[new wt(t)],!0):!1}toTextmateString(){let e="";return this.transform&&(e=this.transform.toTextmateString()),this.children.length===0?`\${${this.name}${e}}`:`\${${this.name}:${this.children.map(t=>t.toTextmateString()).join("")}${e}}`}clone(){let e=new xo(this.name,this.resolved);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map(t=>t.clone()),e}};ip=class extends cs{constructor(e){super();this.ultisnip=e===!0}get hasPython(){return this.ultisnip?this.pyBlocks.length>0:!1}get hasCodeBlock(){if(!this.ultisnip)return!1;let{pyBlocks:e,otherBlocks:t}=this;return e.length>0||t.length>0}get values(){if(this._values)return this._values;let e={},t=0;this.placeholders.forEach(i=>{t=Math.max(i.index,t),i.transform==null&&(i.primary||e[i.index]===void 0)&&(e[i.index]=i.toString())});for(let i=0;i<=t;i++)e[i]===void 0&&(e[i]="");return this._values=e,e}get orderedPyIndexBlocks(){let e=[],t=this.pyBlocks.filter(s=>typeof s.index=="number");if(t.length==0)return e;let i=t.map(s=>s.index),r=[],o=s=>{let{related:a}=s;return a.length==0||a.every(l=>!i.includes(l)||r.includes(l))?(r.push(s.index),e.push(s),!0):!1};for(;t.length>0;){let s=!1;for(let a of t)o(a)&&(s=!0);if(!s)break;t=t.filter(a=>!r.includes(a.index))}return e}async evalCodeBlocks(e,t){let{pyBlocks:i,otherBlocks:r}=this;if(await Promise.all(r.map(o=>{let s=o.value;return o.resolve(e).then(()=>{o.parent instanceof nt&&s!==o.value&&this.onPlaceholderUpdate(o.parent)})})),i.length){let o=Vf(this.values);await kh(e,[...t,o]);for(let a of i){let l=a.value;await a.resolve(e),l!==a.value&&a.parent instanceof nt&&(this.onPlaceholderUpdate(a.parent),await kh(e,[Vf(this.values)]))}for(let a of this.orderedPyIndexBlocks)await this.updatePyIndexBlock(e,a);let s=i.filter(a=>a.index===void 0&&a.related.length>0);for(let a of s)await a.resolve(e)}}async updatePythonCodes(e,t){let i;if(t instanceof nt)i=t.index;else for(;t.parent;){if(t instanceof nt){i=t.index;break}t=t.parent}if(i===void 0)return;let r=this.getDependentPyIndexBlocks(i);await kh(e,[Vf(this.values)]);for(let s of r)await this.updatePyIndexBlock(e,s);let o=this.pyBlocks.filter(s=>s.index===void 0&&s.related.length>0);for(let s of o)await s.resolve(e)}getDependentPyIndexBlocks(e){let t=[],i=[],r=this.pyBlocks.filter(s=>typeof s.index=="number"),o=s=>{let a=r.filter(l=>!i.includes(l.index)&&l.related.includes(s));a.length>0&&(t.push(...a),a.forEach(l=>{o(l.index)}))};return o(e),t}async updatePyIndexBlock(e,t){let i=t.value;await t.resolve(e),i!==t.value&&(t.parent instanceof nt&&this.onPlaceholderUpdate(t.parent),await kh(e,[Vf(this.values)]))}get placeholderInfo(){if(!this._placeholders){let e=[],t=[],i=[],r=[];this.walk(o=>{if(o instanceof nt)r.push(o);else if(o instanceof xo){let s=o.name.charCodeAt(0);(s<65||s>90)&&e.push(o)}else o instanceof us&&(o.kind==="python"?t.push(o):i.push(o));return!0}),this._placeholders={placeholders:r,pyBlocks:t,otherBlocks:i,variables:e}}return this._placeholders}get variables(){return this.placeholderInfo.variables}get placeholders(){return this.placeholderInfo.placeholders}get pyBlocks(){return this.placeholderInfo.pyBlocks}get otherBlocks(){return this.placeholderInfo.otherBlocks}get maxIndexNumber(){let{placeholders:e}=this;return e.reduce((t,i)=>Math.max(t,i.index),0)}get first(){var o,s;let{placeholders:e,variables:t}=this,[i,r]=rW(e.filter(a=>!a.transform),a=>a.index!==0);if(i.length){let a=Math.min.apply(null,i.map(u=>u.index)),l=i.filter(u=>u.index==a);return(o=l.find(u=>u.primary))!=null?o:l[0]}return t.length?t[0]:(s=r.find(a=>a.primary))!=null?s:r[0]}insertSnippet(e,t,i,r){let o=t instanceof nt?t.index:this.maxIndexNumber+1,[s,a]=i,l=r?aD(r):void 0,u=new Fa(!!r,l).parse(e,!0),c=u.maxIndexNumber+1,h=new Map;for(let p of u.placeholders){let b=p.index;p.isFinalTabstop?p.index=c+o:p.index=p.index+o,h.set(b,p.index)}r&&u.pyBlocks.forEach(p=>{p.update(h)});let d=new Map;this.walk(p=>{if(p instanceof nt&&p.index>o){let b=p.index;p.index=p.index+c,d.set(b,p.index)}return!0}),this.hasPython&&this.walk(p=>(p instanceof us&&p.update(d),!0));let g=u.first,f=u.children.slice();return s&&f.unshift(new wt(s)),a&&f.push(new wt(a)),this.replace(t,f),g}async update(e,t,i){this.resetMarker(t,i),this.hasPython&&await this.updatePythonCodes(e,t)}deleteText(e,t){let i=0,r,o=e+t,s=0;if(this.walk(d=>{let g=d.len();return d instanceof wt&&e>=i&&i+g>=o?(r=d,s=e-i,!1):(i+=g,!0)}),!r)return!1;let a=r.parent,l=r.value,u=l.slice(0,s)+l.slice(s+t),c=a.children.slice(),h=c.indexOf(r);return c.splice(h,1,new wt(u)),a.replaceChildren(c),!0}resetMarker(e,t){let i;e instanceof nt?i=this.placeholders.filter(r=>r.index==e.index):i=this.variables.filter(r=>r.name==e.name);for(let r of i){let o=r.transform?r.transform.resolve(t):t;r.setOnlyChild(new wt(o||""))}this.synchronizeParents(i),this.reset()}onPlaceholderUpdate(e){let t=e.toString(),i;e instanceof nt?(this.values[e.index]=t,i=this.placeholders.filter(r=>r.index==e.index)):i=this.variables.filter(r=>r.name==e.name);for(let r of i){if(r===e)continue;let o=r.transform?r.transform.resolve(t):t;r.setOnlyChild(new wt(o||""))}this.synchronizeParents(i)}synchronizeParents(e){let t=[];e.forEach(i=>{let r=i.parent;r instanceof nt&&!t.includes(r)&&t.push(r)}),t.forEach(i=>{this.onPlaceholderUpdate(i)})}offset(e){let t=0,i=!1;return this.walk(r=>r===e?(i=!0,!1):(t+=r.len(),!0)),i?t:-1}fullLen(e){let t=0;return IV([e],i=>(t+=i.len(),!0)),t}getTextBefore(e,t){let i="",r=o=>{let s=o.parent;if(!s)return;let a="";for(let l of s.children){if(l===o)break;a=a+l.toString()}i=a+i,s!=t&&r(s)};return r(e),i}enclosingPlaceholders(e){let t=[],{parent:i}=e;for(;i;)i instanceof nt&&t.push(i),i=i.parent;return t}async resolveVariables(e){let t=[];this.walk(i=>(i instanceof xo&&!i.resolved&&t.push(i),!0)),t.length&&(await Promise.all(t.map(i=>i.resolve(e))),this.synchronizeParents(t))}appendChild(e){return this.reset(),super.appendChild(e)}replace(e,t){e.replaceChildren(t),(e instanceof nt||e instanceof xo)&&this.onPlaceholderUpdate(e),this.reset()}reset(){this._placeholders=void 0,this._values=void 0}toTextmateString(){return this.children.reduce((e,t)=>e+t.toTextmateString(),"")}clone(){let e=new ip(this.ultisnip);return e._children=this.children.map(t=>t.clone()),e}walk(e){IV(this.children,e)}},Fa=class{constructor(e,t){this.ultisnip=e;this.matchCode=t;this._scanner=new j_}static escape(e){return e.replace(/\$|}|\\/g,"\\$&")}static isPlainText(e){let t=new Fa().parse(e.replace(/\$0$/,""),!1);return t.children.length==1&&t.children[0]instanceof wt}text(e){return this.parse(e,!1).toString()}parse(e,t){this._scanner.text(e),this._token=this._scanner.next();let i=new ip(this.ultisnip);for(;this._parse(i););let r=new Map,o=[],s=[],a=!1;i.walk(c=>(c instanceof nt&&(c.index==0&&(a=!0),c.children.some(h=>h instanceof nt)?s.push(c):!r.has(c.index)&&c.children.length>0?(c.primary=!0,r.set(c.index,c.toString())):o.push(c)),!0));let l=s.map(c=>c.index);for(let c of o)if(r.has(c.index)){let h=r.get(c.index),d=new wt(c.transform?c.transform.resolve(h):h);c.setOnlyChild(d)}else if(!l.includes(c.index))if(c.transform){let h=new wt(c.transform.resolve(""));c.setOnlyChild(h)}else c.primary=!0,r.set(c.index,"");let u=()=>{let c=new Set;for(let h of s)if(h.children.every(d=>!(d instanceof nt)||r.has(d.index))){let d=h.toString();r.set(h.index,d);for(let g of o.filter(f=>f.index==h.index)){let f=new wt(g.transform?g.transform.resolve(d):d);g.setOnlyChild(f)}c.add(h.index)}s=s.filter(h=>!c.has(h.index)),!(s.length==0||!c.size)&&u()};return u(),!a&&t&&i.appendChild(new nt(0)),i}_accept(e,t){if(e===void 0||this._token.type===e){let i=t?this._scanner.tokenText(this._token):!0;return this._token=this._scanner.next(),i}return!1}_backTo(e){return this._scanner.pos=e.pos+e.len,this._token=e,!1}_until(e,t=!1){if(this._token.type===14)return!1;let i=this._token,r;for(;this._token.type!==e||t&&(r==null?void 0:r.type)===5;)if(t&&(r=this._token),this._token=this._scanner.next(),this._token.type===14)return!1;let o=this._scanner.value.substring(i.pos,this._token.pos);return this._token=this._scanner.next(),o}_parse(e){return this._parseEscaped(e)||this._parseCodeBlock(e)||this._parseTabstopOrVariableName(e)||this._parseComplexPlaceholder(e)||this._parseComplexVariable(e)||this._parseAnything(e)}_parseEscaped(e){let t;return(t=this._accept(5,!0))?(t=this._accept(0,!0)||this._accept(4,!0)||this._accept(5,!0)||this.ultisnip&&this._accept(3,!0)||this.ultisnip&&this._accept(17,!0)||t,e.appendChild(new wt(t)),!0):!1}_parseTabstopOrVariableName(e){let t,i=this._token;return this._accept(0)&&(t=this._accept(9,!0)||this._accept(8,!0))?(e.appendChild(/^\d+$/.test(t)?new nt(Number(t)):new xo(t)),!0):this._backTo(i)}_parseComplexPlaceholder(e){let t,i=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(8,!0))))return this._backTo(i);let o=new nt(Number(t));if(this._accept(1))for(;;){if(this._accept(4))return e.appendChild(o),!0;if(!this._parse(o))return e.appendChild(new wt("${"+t+":")),o.children.forEach(e.appendChild,e),!0}else if(o.index>0&&this._accept(7)){let s=new ep;for(;;){if(this._parseChoiceElement(s)){if(this._accept(2))continue;if(this._accept(7)&&(o.appendChild(s),this._accept(4)))return e.appendChild(o),!0}return this._backTo(i),!1}}else return this._accept(6)?this._parseTransform(o)?(e.appendChild(o),!0):(this._backTo(i),!1):this._accept(4)?(e.appendChild(o),!0):this._backTo(i)}_parseChoiceElement(e){let t=this._token,i=[];for(;!(this._token.type===2||this._token.type===7);){let r;if((r=this._accept(5,!0))?r=this._accept(2,!0)||this._accept(7,!0)||this._accept(5,!0)||r:r=this._accept(void 0,!0),!r)return this._backTo(t),!1;i.push(r)}return i.length===0?(this._backTo(t),!1):(e.appendChild(new wt(i.join(""))),!0)}_parseComplexVariable(e){let t,i=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(9,!0))))return this._backTo(i);let o=new xo(t);if(this._accept(1))for(;;){if(this._accept(4))return e.appendChild(o),!0;if(!this._parse(o))return e.appendChild(new wt("${"+t+":")),o.children.forEach(e.appendChild,e),!0}else return this._accept(6)?this._parseTransform(o)?(e.appendChild(o),!0):(this._backTo(i),!1):this._accept(4)?(e.appendChild(o),!0):this._backTo(i)}_parseTransform(e){let t=new lD;t.ultisnip=this.ultisnip===!0;let i="",r="";for(;!this._accept(6);){let s;if(s=this._accept(5,!0)){s=this._accept(6,!0)||s,i+=s;continue}if(this._token.type!==14){i+=this._accept(void 0,!0);continue}return!1}for(;!this._accept(6);){let s;if(s=this._accept(5,!0)){s=this._accept(6,!0)||s,t.appendChild(new wt(s));continue}if(!(this._parseFormatString(t)||this._parseConditionString(t)||this._parseAnything(t)))return!1}let o=!1;for(;!this._accept(4);){if(this._token.type!==14){let s=this._accept(void 0,!0);s=="a"?o=!0:(O0e.includes(s)||A0e.error(`Unknown regex option: ${s}`),r+=s);continue}return!1}try{o&&(t.ascii=!0),this.ultisnip&&(i=FV(i)),t.regexp=new RegExp(i,r)}catch{return!1}return e.transform=t,!0}_parseConditionString(e){if(!this.ultisnip)return!1;let t=this._token;if(!this._accept(15))return!1;if(!this._accept(13))return this._backTo(t),!1;let i=this._accept(8,!0);if(!i)return this._backTo(t),!1;if(!this._accept(1))return this._backTo(t),!1;let r=this._until(16,!0);if(r){let o=0;for(;o!/^\s*$/.test(u));let a=s[0]?s[0].match(/^\s*/)[0]:"";a.length&&s.every(u=>u.startsWith(a))&&(s=s.map(u=>u.slice(a.length))),a==" "&&s[0].startsWith(a)&&(s[0]=s[0].slice(1));let l=new us(o+s.join(` -`),"python");e.appendChild(l)}return!0}}return this._backTo(t),!1}_parseAnything(e){if(this._token.type!==14){let t=this._scanner.tokenText(this._token);return e.appendChild(new wt(t)),this._accept(void 0),!0}return!1}},M0e=[":","(",")","{","}"]});function O_(n,e){let{range:t,newText:i}=n,r=e.length,o=i.length;if(r===0||o===0)return n;let{start:s,end:a}=t,l=0;for(let d=1;d<=Math.min(o,r)&&i[d-1]===e[d-1];d++)l=d;let u=0,c=Math.min(o-l,r-l);if(c>0)for(let d=1;d<=c&&i[o-d]===e[r-d];d++)u=d;let h=u==0?i.slice(l):i.slice(l,-u);return l>0&&(s=_i(s,i.slice(0,l))),u>0&&(a=_i(t.start,e.slice(0,-u))),Ni.TextEdit.replace(Ni.Range.create(s,a),h)}function AV(n,e,t){let i=Ni.Range.create(n,_i(n,t));return ut(e,i)==0}function OV(n,e,t){var o;if(t.lines.length=0;s--){let a=(o=t.lines[s])!=null?o:"";if(s===n.line){let l=e.lines[s].slice(0,n.character);if(!a.startsWith(l)){r=!1;break}}else if(a!==e.lines[s]){r=!1;break}}return r}function MV(n,e,t){let i=e.lines.length;if(t.lines.length{let l=s.match(/^\s*/)[0],u=l,c=l.startsWith(" ");return c&&t.insertSpaces?u=r.repeat(l.length):!c&&!t.insertSpaces&&(u=r.repeat(l.length/o)),(a==0||s.length==0?"":e)+u+s.slice(l.length)}),i.join(` -`)}function HV(n){return!!(/^\s/.test(n)||n.indexOf(` -`)!==-1)}var Ni,FQe,cD,M_=_(()=>{"use strict";Ni=C(H());Ec();yt();jr();I_();uD();FQe=q()("snippets-snipet"),cD=class{constructor(e,t,i,r){this.snippetString=e;this.position=t;this.nvim=i;this.resolver=r}async init(e,t=!1){let i=e?aD(e):void 0,o=new Fa(!!e,i).parse(this.snippetString,!0);this.tmSnippet=o,await this.resolve(e),this.synchronize(),t||(this.nvim.call("coc#compat#del_var",["coc_selected_text"],!0),this.nvim.call("coc#compat#del_var",["coc_last_placeholder"],!0))}async resolve(e){let{snippet:t}=this.tmSnippet,{resolver:i,nvim:r}=this;if(i&&await t.resolveVariables(i),e&&e.noPython!==!0){let o=[];t.hasPython&&(o=LV(e)),await t.evalCodeBlocks(r,o)}}getRanges(e){let t=e.marker;if(e.value.length==0)return[];let r=this._placeholders.filter(l=>l.index==e.index).map(l=>l.range),o=this.tmSnippet.enclosingPlaceholders(t),s,a=t.parent;if(t instanceof nt){let l=t.index;s=this.tmSnippet.placeholders.filter(u=>u.index==l&&u.parent==a)}else{let l=t.name;s=this.tmSnippet.variables.filter(u=>u.name==l&&u.parent==a)}return o.forEach(l=>{let u=this._placeholders.filter(c=>c.index==l.index&&c.marker!==l);if(!!u.length)for(let c of s){let h=this.tmSnippet.getTextBefore(c,l);u.forEach(d=>{if(d.transform)r.push(d.range);else{let g=d.range.start;r.push(Ni.Range.create(_i(g,h),_i(g,h+c.toString())))}})}}),r.filter(l=>!Ct(l))}getSortedPlaceholders(e){let t=e?[e]:[],i=this._placeholders.filter(r=>r!==e&&!r.transform);return i.sort((r,o)=>r.primary!==o.primary?r.primary?-1:1:r.index==0||o.index==0?r.index==0?1:-1:r.index-o.index),t.push(...i),t}get hasPython(){return this.tmSnippet.pyBlocks.length>0}resetStartPosition(e){this.position=e,this.synchronize()}get start(){return Object.assign({},this.position)}get range(){return Ni.Range.create(this.position,_i(this.position,this._text))}get text(){return this._text}get finalCount(){return this._placeholders.filter(e=>e.index==0).length}get placeholders(){return this._placeholders.map(e=>e.marker)}get firstPlaceholder(){let e=0;for(let t of this._placeholders)t.index==0||t.transform||(e==0||t.indext.marker===e)}getPlaceholder(e){let t=this._placeholders.filter(r=>r.index==e&&!r.transform),i=t.find(r=>r.primary)||t[0];return i!=null?i:t[0]}getPrevPlaceholder(e){if(e<=1)return;let t=this._placeholders.filter(r=>r.index1;){e=e-1;let r=t.filter(o=>o.index==e);if(r.length){i=r.find(o=>o.primary)||r[0];break}}return i}getNextPlaceholder(e){let t=this._placeholders.filter(s=>!s.transform),i,r=t.map(s=>s.index),o=Math.max.apply(null,r);for(let s=e+1;s<=o+1;s++){let a=s==o+1?0:s,l=t.filter(u=>u.index==a);if(l.length){i=l.find(u=>u.primary)||l[0];break}}return i}getPlaceholderByRange(e){return this._placeholders.find(t=>Pi(e,t.range))}async insertSnippet(e,t,i,r){if(r){let{start:s,end:a}=e.range;this.nvim.setVar("coc_last_placeholder",{current_text:e.value,start:{line:s.line,col:s.character,character:s.character},end:{line:a.line,col:a.character,character:a.character}},!0)}let o=this.tmSnippet.insertSnippet(t,e.marker,i,r);return await this.resolve(r),this.synchronize(),o}getNewText(e,t){let{before:i,after:r}=e;if(!!t.startsWith(i)&&!(t.length{this.tmSnippet=l,this.synchronize()});let u=Ni.Range.create(o,_i(o,a));if(await this.tmSnippet.update(this.nvim,s,i),r.isCancellationRequested)return;this.synchronize();let c=this._placeholders.find(d=>d.marker==s),h=c?c.before:a;return{text:this._text,delta:Jb(t,Ni.TextEdit.replace(u,h))}}removeText(e,t){let i=this.tmSnippet.deleteText(e,t);return i&&this.synchronize(),i}synchronize(){let e=this.tmSnippet,{line:t,character:i}=this.position,r=jn.create("untitled:/1","snippet",0,e.toString()),{placeholders:o,variables:s,maxIndexNumber:a}=e,l=new Map,u=a+1;this._placeholders=[...o,...s].map(c=>{let h=e.offset(c),d=r.positionAt(h),g={line:t+d.line,character:d.line==0?i+d.character:d.character},f;if(c instanceof xo){let w=c.name;l.has(w)?f=l.get(w):(l.set(w,u),f=u,u=u+1)}else f=c.index;let p=c.toString(),b=_i(d,p);return{index:f,value:p,marker:c,transform:!!c.transform,range:Ni.Range.create(g,_i(g,p)),before:r.getText(Ni.Range.create(Ni.Position.create(0,0),d)),after:r.getText(Ni.Range.create(b,Ni.Position.create(r.lineCount,0))),primary:c instanceof nt&&c.primary===!0}}),this._text=this.tmSnippet.toString()}}});function np(n){return n<10?"0"+n:n.toString()}function qV(n){let e,t,i,r=n.split(",");for(let o of r){if(e&&t&&i)break;if(!o.includes(":"))continue;let[s,a]=o.split(":");s.includes("s")?e=a:s.includes("e")?t=a:!i&&s==""&&(i=a)}return{start:e,end:t,single:i}}function H0e(n){if(n.endsWith("%s"))return n.slice(0,-2).trim()}var rp,OQe,hD,YV=_(()=>{"use strict";rp=C(require("path"));Oe();we();OQe=q()("snippets-variable");hD=class{constructor(e,t){this.nvim=e;this.workspaceFolder=t;this._variableToValue={};let i=new Date,r=i.getFullYear().toString();Object.assign(this._variableToValue,{CURRENT_YEAR:r,CURRENT_YEAR_SHORT:r.slice(-2),CURRENT_MONTH:np(i.getMonth()+1),CURRENT_DATE:np(i.getDate()),CURRENT_HOUR:np(i.getHours()),CURRENT_MINUTE:np(i.getMinutes()),CURRENT_SECOND:np(i.getSeconds()),CURRENT_DAY_NAME:i.toLocaleString("en-US",{weekday:"long"}),CURRENT_DAY_NAME_SHORT:i.toLocaleString("en-US",{weekday:"short"}),CURRENT_MONTH_NAME:i.toLocaleString("en-US",{month:"long"}),CURRENT_MONTH_NAME_SHORT:i.toLocaleString("en-US",{month:"short"}),TM_FILENAME:null,TM_FILENAME_BASE:null,TM_DIRECTORY:null,TM_FILEPATH:null,YANK:null,TM_LINE_INDEX:null,TM_LINE_NUMBER:null,TM_CURRENT_LINE:null,TM_CURRENT_WORD:null,TM_SELECTED_TEXT:null,VISUAL:null,CLIPBOARD:null,RELATIVE_FILEPATH:null,RANDOM:null,RANDOM_HEX:null,UUID:null,BLOCK_COMMENT_START:null,BLOCK_COMMENT_END:null,LINE_COMMENT:null,WORKSPACE_NAME:null,WORKSPACE_FOLDER:null})}async resolveValue(e){let{nvim:t}=this;if(["TM_FILENAME","TM_FILENAME_BASE","TM_DIRECTORY","TM_FILEPATH"].includes(e)){let i=await t.eval('expand("%:p")');if(e==="TM_FILENAME")return rp.default.basename(i);if(e==="TM_FILENAME_BASE")return rp.default.basename(i,rp.default.extname(i));if(e==="TM_DIRECTORY")return rp.default.dirname(i);if(e==="TM_FILEPATH")return i}if(e==="YANK")return await t.call("getreg",['""']);if(e==="TM_LINE_INDEX")return(await t.call("line",["."])-1).toString();if(e==="TM_LINE_NUMBER")return(await t.call("line",["."])).toString();if(e==="TM_CURRENT_LINE")return await t.call("getline",["."]);if(e==="TM_CURRENT_WORD")return await t.eval("expand('')");if(e==="TM_SELECTED_TEXT"||e=="VISUAL")return await t.eval("get(g:,'coc_selected_text', v:null)");if(e==="CLIPBOARD")return await t.eval("@*");if(e==="RANDOM")return Math.random().toString().slice(-6);if(e==="RANDOM_HEX")return Math.random().toString(16).slice(-6);if(e==="UUID")return re();if(["RELATIVE_FILEPATH","WORKSPACE_NAME","WORKSPACE_FOLDER"].includes(e)){let i=await t.eval('expand("%:p")'),r=this.workspaceFolder.getWorkspaceFolder(O.file(i));if(e==="RELATIVE_FILEPATH")return this.workspaceFolder.getRelativePath(i);if(e==="WORKSPACE_NAME")return r.name;if(e==="WORKSPACE_FOLDER")return O.parse(r.uri).fsPath}if(e==="LINE_COMMENT"){let i=await t.eval("&commentstring"),r=H0e(i);if(r)return r;let o=await t.eval("&comments"),{single:s}=qV(o);return s!=null?s:""}if(["BLOCK_COMMENT_START","BLOCK_COMMENT_END"].includes(e)){let i=await t.eval("&comments"),{start:r,end:o}=qV(i);if(e==="BLOCK_COMMENT_START")return r!=null?r:"";if(e==="BLOCK_COMMENT_END")return o!=null?o:""}}async resolve(e){let t=e.name,i=this._variableToValue[t];if(i!=null)return i.toString();if(this._variableToValue.hasOwnProperty(t)){let r=await this.resolveValue(t);return!r&&e.children.length?e.toString():r==null?"":r.toString()}return e.children.length?e.toString():t}}});function q0e(n,e){return!!(n.hasChanged||E.pumvisible&&(e.line!=0||e.character!=0))}var Bi,hs,N_,dD,WV=_(()=>{"use strict";Bi=C(H());le();io();Jt();yt();Pe();ke();V();uD();M_();YV();hs=q()("snippets-session"),N_="snippets",dD=class{constructor(e,t,i=!1,r=!1){this.nvim=e;this.document=t;this.enableHighlight=i;this.preferComplete=r;this.mutex=new ei;this._applying=!1;this._isActive=!1;this._snippet=null;this._onCancelEvent=new Bi.Emitter;this.onCancel=this._onCancelEvent.event;this.disposable=t.onDocumentChange(async o=>{if(this._applying||!this._isActive)return;let s=o.contentChanges;s.length!==0&&await this.synchronize({version:o.textDocument.version,change:s[0]})})}async start(e,t,i=!0,r){var l;let{document:o}=this,s=this.getReplacePlaceholder(t),a=[];if(s){let u=this.snippet.range,c=o.textDocument.getText(u),h=NV(s.value,s.range,t);this.current=await this.snippet.insertSnippet(s,e,h,r);let d=O_({range:u,newText:this.snippet.text},c);a.push(d)}else{let u=new hD(this.nvim,y.workspaceFolderControl),c=new cD(e,t.start,this.nvim,u);if(await c.init(r),this._snippet=c,this.current=(l=c.firstPlaceholder)==null?void 0:l.marker,a.push(Bi.TextEdit.replace(t,c.text)),e.replace(/\$0$/,"").endsWith(` -`)){let h=o.getline(t.start.line),d=h.slice(t.end.character);if(d.length){let g=t.end.character,f=d.match(/^\s*/)[0].length,p=Bi.Range.create(t.end.line,g,t.end.line,g+f);a.push(Bi.TextEdit.replace(p,h.match(/^\s*/)[0]))}}}if(await this.applyEdits(a),this.textDocument=o.textDocument,this.activate(),i&&this.current){let u=this.snippet.getPlaceholderByMarker(this.current);await this.selectPlaceholder(u,!0)}return this._isActive}async applyEdits(e){this._applying=!0,await this.document.applyEdits(e),this._applying=!1}getReplacePlaceholder(e){if(!this.snippet)return;let t=this.findPlaceholder(e);if(!(!t||t.index==0))return t}activate(){this._isActive||(this._isActive=!0,this.nvim.call("coc#snippet#enable",[this.preferComplete?1:0],!0))}deactivate(){this.cancel(),this._isActive&&(this.disposable.dispose(),this._isActive=!1,this.current=null,this.nvim.call("coc#snippet#disable",[],!0),this.enableHighlight&&this.nvim.call("coc#highlight#clear_highlight",[this.bufnr,N_,0,-1],!0),this._onCancelEvent.fire(void 0),hs.debug(`session ${this.bufnr} cancelled`))}get isActive(){return this._isActive}get bufnr(){return this.document.bufnr}async nextPlaceholder(){await this.forceSynchronize();let e=this.placeholder;if(!e)return;let t=this.snippet.getNextPlaceholder(e.index);t&&await this.selectPlaceholder(t)}async previousPlaceholder(){await this.forceSynchronize();let e=this.placeholder;if(!e)return;let t=this.snippet.getPrevPlaceholder(e.index);t&&await this.selectPlaceholder(t)}async selectCurrentPlaceholder(e=!0){if(await this.forceSynchronize(),!this.snippet)return;let t=this.snippet.getPlaceholderByMarker(this.current);t&&await this.selectPlaceholder(t,e)}async selectPlaceholder(e,t=!0){let{nvim:i,document:r}=this;if(!r||!e)return;let{start:o,end:s}=e.range,a=s.character-o.character,l=Q(r.getline(o.line).slice(0,o.character))+1,u=this.current=e.marker;if(u instanceof nt&&u.choice&&u.choice.options.length){let c=u.choice.options.map(h=>h.value);await i.call("coc#snippet#show_choices",[o.line+1,l,a,c]),t&&i.call("coc#util#do_autocmd",["CocJumpPlaceholder"],!0)}else{let c=this.snippet.finalCount;await this.select(e,t),this.highlights(e),e.index==0&&(c==1?(hs.info("Jump to final placeholder, cancelling snippet session"),this.deactivate()):i.call("coc#snippet#disable",[],!0))}}highlights(e,t=!0){if(!this.enableHighlight)return;let i=this.document.buffer;this.nvim.pauseNotification(),i.clearNamespace(N_);let r=this.snippet.getRanges(e);r.length&&i.highlightRanges(N_,"CocSnippetVisual",r),this.nvim.resumeNotification(t,!0)}async select(e,t=!0){let{range:i,value:r}=e,{nvim:o}=this;r.length>0?await o.call("coc#snippet#select",[i.start,i.end,r]):await o.call("coc#snippet#move",[i.start]),t&&o.call("coc#util#do_autocmd",["CocJumpPlaceholder"],!0),o.redrawVim()}async checkPosition(){if(!this.isActive)return;let e=await k.getCursorPosition();this.snippet&&ut(e,this.snippet.range)!=0&&(hs.info("Cursor insert out of range, cancelling snippet session"),this.deactivate())}findPlaceholder(e){let{placeholder:t}=this;return t&&Pi(e,t.range)?t:this.snippet.getPlaceholderByRange(e)||null}async synchronize(e){this.cancel(),await this.mutex.use(()=>{let t=this.textDocument?this.textDocument.version:-1;return e&&(this.document.version!=e.version||e.version-t!==1)&&(e=void 0),this._synchronize(e?e.change:void 0)})}async _synchronize(e){let{document:t,textDocument:i}=this;if(!t.attached||!this._isActive)return;let r=Date.now(),o=t.textDocument;if(o.version==i.version||Fe(i.lines,o.lines))return;let{range:s,text:a}=this.snippet;e&&!Pi(e.range,s)&&(e=void 0);let l=MV(s.end,i,o);if(!l){hs.info("Content change after snippet, cancel snippet session"),this.deactivate();return}if(!OV(s.start,i,o)){let v=o.getText(Bi.Range.create(Bi.Position.create(0,0),l));if(v.endsWith(a)){let w=o.positionAt(v.length-a.length);this.snippet.resetStartPosition(w),this.textDocument=o,hs.info("Content change before snippet, reset snippet position");return}hs.info("Before and snippet body changed, cancel snippet session"),this.deactivate();return}let c=this.tokenSource=new Bi.CancellationTokenSource,h=await k.getCursorPosition();if(c.token.isCancellationRequested||t.hasChanged)return;let d,g,f=o.getText(Bi.Range.create(s.start,l)),p=this.placeholder;if(e){for(let v of this.snippet.getSortedPlaceholders(p))if(Pi(e.range,v.range)){d=v,g=this.snippet.getNewText(v,f);break}if(!d&&e.text.length==0&&!Ct(e.range)&&Y2(e.range)){let v=e.range.end.character-e.range.start.character,w=o.getText(Bi.Range.create(s.start,e.range.start)).length;if(this.snippet.removeText(w,v)){this.textDocument=o;return}}}else for(let v of this.snippet.getSortedPlaceholders(p))if(!(De(h,v.range.start)<0)&&(g=this.snippet.getNewText(v,f),g!=null&&AV(v.range.start,h,g))){d=v;break}if(!d&&f.endsWith(a)){let v=_i(s.start,f.slice(0,-a.length));this.snippet.resetStartPosition(v),this.textDocument=o,hs.info("Content change before snippet, reset snippet position");return}if(!d){hs.info("Unable to find changed placeholder, cancel snippet session"),this.deactivate();return}let b=await this.snippet.updatePlaceholder(d,h,g,c.token);if(!(b==null||c.token.isCancellationRequested)){if(q0e(t,b.delta)){c.cancel(),c.dispose();return}if(c.dispose(),this.current=d.marker,b.text!==f){let v=O_({range:Bi.Range.create(this.snippet.start,l),newText:b.text},f);await this.applyEdits([v]);let{delta:w}=b;(w.line!=0||w.character!=0)&&this.nvim.call("coc#cursor#move_to",[h.line+w.line,h.character+w.character],!0),this.highlights(d,!1),this.nvim.redrawVim()}else this.highlights(d);hs.debug("update cost:",Date.now()-r,b.delta),this.textDocument=this.document.textDocument}}async forceSynchronize(){this.cancel(),await this.document.patchChange(),(await this.mutex.acquire())()}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null)}get placeholder(){if(!(!this.snippet||!this.current))return this.snippet.getPlaceholderByMarker(this.current)}get snippet(){return this._snippet}static async resolveSnippet(e,t,i){let r=await k.getCursorPosition(),o=await e.line,s;i&&(s=Object.assign({range:Bi.Range.create(r,r),line:o},i));let a=new hD(e,y.workspaceFolderControl),l=new cD(t,r,e,a);return await l.init(s,!0),l.text}}});var qr,B_=_(()=>{"use strict";qr=class{constructor(e){this._tabstop=1;this.value=e||""}static isSnippetString(e){return e instanceof qr?!0:e?typeof e.value=="string":!1}static _escape(e){return e.replace(/\$|}|\\/g,"\\$&")}appendText(e){return this.value+=qr._escape(e),this}appendTabstop(e=this._tabstop++){return this.value+="$",this.value+=e,this}appendPlaceholder(e,t=this._tabstop++){if(typeof e=="function"){let i=new qr;i._tabstop=this._tabstop,e(i),this._tabstop=i._tabstop,e=i.value}else e=qr._escape(e);return this.value+="${",this.value+=t,this.value+=":",this.value+=e,this.value+="}",this}appendChoice(e,t=this._tabstop++){let i=e.map(r=>r.replace(/\$|}|\\|,/g,"\\$&")).join(",");return this.value+="${",this.value+=t,this.value+="|",this.value+=i,this.value+="|}",this}appendVariable(e,t){if(typeof t=="function"){let i=new qr;i._tabstop=this._tabstop,t(i),this._tabstop=i._tabstop,t=i.value}else typeof t=="string"&&(t=t.replace(/\$|}/g,"\\$&"));return this.value+="${",this.value+=e,t&&(this.value+=":",this.value+=t),this.value+="}",this}}});var tu,cKe,ZV,Ut,iu=_(()=>{"use strict";tu=C(H());le();Jt();yt();ke();V();WV();M_();B_();cKe=q()("snippets-manager"),ZV=class{constructor(){this.sessionMap=new Map;this.disposables=[];E.on("InsertCharPre",()=>{var e;(e=this.session)==null||e.cancel()},null,this.disposables),k.onDidChangeActiveTextEditor(e=>{if(!this.statusItem)return;this.getSession(e.document.bufnr)?this.statusItem.show():this.statusItem.hide()},null,this.disposables),E.on("InsertEnter",async e=>{let t=this.getSession(e);t&&await t.checkPosition()},null,this.disposables),y.onDidCloseTextDocument(e=>{let t=this.getSession(e.bufnr);t&&t.deactivate()},null,this.disposables),y.onDidChangeConfiguration(e=>{(e.affectsConfiguration("suggest")||e.affectsConfiguration("coc.preferences"))&&this.init()},null,this.disposables)}get nvim(){return y.nvim}init(){this.statusItem||(this.statusItem=k.createStatusBarItem(0));let e=y.getConfiguration("coc.preferences");this.statusItem.text=e.get("snippetStatusText","SNIP"),this.highlight=e.get("snippetHighlight",!1);let t=y.getConfiguration("suggest");this.preferComplete=t.get("preferCompleteThanJumpPlaceholder",!1)}async insertSnippet(e,t=!0,i,r,o){let{bufnr:s}=y,a=y.getAttachedDocument(s);if(i&&!Pi(i,tu.Range.create(0,0,a.lineCount+1,0)))throw new Error("Unable to insert snippet, invalid range.");let l;if(E.pumvisible&&this.nvim.call("coc#_cancel",[],!0),!i){let f=await k.getCursorPosition();i=tu.Range.create(f,f)}let u=a.getline(i.start.line),c=qr.isSnippetString(e)?e.value:e,h=await this.normalizeInsertText(a.uri,c,u,r),d=this.getSession(s);d&&d.cancel(),o!=null&&(l=Object.assign({range:Pr(i),line:u},o),!Ct(i)&&h.includes("`!p")&&(this.nvim.call("coc#cursor#move_to",[i.start.line,i.start.character],!0),await a.applyEdits([{range:i,newText:""}]),i.end=tu.Position.create(i.start.line,i.start.character))),d?(await d.forceSynchronize(),d=this.getSession(s)):await a.patchChange(!0),d||(d=new dD(this.nvim,a,this.highlight,this.preferComplete),d.onCancel(()=>{this.sessionMap.delete(s),this.statusItem.hide()}));let g=await d.start(h,i,t,l);return g?(this.statusItem.show(),this.sessionMap.set(s,d)):(this.statusItem.hide(),this.sessionMap.delete(s)),g}async selectCurrentPlaceholder(e=!0){let{session:t}=this;if(t)return await t.selectCurrentPlaceholder(e)}async nextPlaceholder(){let{session:e}=this;return e?await e.nextPlaceholder():(this.nvim.call("coc#snippet#disable",[],!0),this.statusItem.hide()),""}async previousPlaceholder(){let{session:e}=this;return e?await e.previousPlaceholder():(this.nvim.call("coc#snippet#disable",[],!0),this.statusItem.hide()),""}cancel(){let e=this.getSession(y.bufnr);if(e)return e.deactivate();this.nvim.call("coc#snippet#disable",[],!0),this.statusItem&&this.statusItem.hide()}get session(){return this.getSession(y.bufnr)}getSession(e){return this.sessionMap.get(e)}jumpable(){let{session:e}=this;return e?e.placeholder!=null&&e.placeholder.index!=0:!1}async editsInsideSnippet(e){let t=this.getSession(y.bufnr);if(!t||!t.snippet)return!1;await t.forceSynchronize();let i=t.snippet.range;return!!e.some(r=>Sc(r.range,i))}async resolveSnippet(e,t){if(t){let i=this.getSession(y.bufnr);t.noPython=i!=null&&i.snippet.hasPython}return await dD.resolveSnippet(this.nvim,e,t)}async normalizeInsertText(e,t,i,r){let o="";if(r===tu.InsertTextMode.asIs||!HV(t))o=t;else{let s=i.match(/^\s*/)[0],a=k.activeTextEditor?k.activeTextEditor.options:await y.getFormatOptions(e);o=BV(t,s,a)}return o}dispose(){this.cancel();for(let e of this.disposables)e.dispose()}},Ut=new ZV});var JV,op,nu,Co,gD=_(()=>{"use strict";we();JV=C(require("path"));(e=>{function n(t){return typeof t.label=="string"}e.is=n})(op||(op={}));nu=(i=>(i[i.None=0]="None",i[i.Collapsed=1]="Collapsed",i[i.Expanded=2]="Expanded",i))(nu||{}),Co=class{constructor(e,t=0){this.collapsibleState=t;O.isUri(e)?(this.resourceUri=e,this.label=JV.default.basename(e.path),this.id=e.toString()):this.label=e}}});var H_=_(()=>{"use strict";gD()});function Y0e(n){return Array.isArray(n)&&n.every(e=>typeof e=="string")}function W0e(n){return typeof n>"u"||Y0e(n)}var $V,sp,XV=_(()=>{"use strict";$V=C(H());sp=class{constructor(e){if(this._prevLine=0,this._prevChar=0,this._dataIsSortedAndDeltaEncoded=!0,this._data=[],this._dataLen=0,this._tokenTypeStrToInt=new Map,this._tokenModifierStrToInt=new Map,this._hasLegend=!1,e){this._hasLegend=!0;for(let t=0,i=e.tokenTypes.length;t"u"))return typeof o>"u"&&(o=0),this._pushEncoded(e,t,i,r,o);if($V.Range.is(e)&&typeof t=="string"&&W0e(i))return this._push(e,t,i);throw new Error("Illegal argument")}_push(e,t,i){if(!this._hasLegend)throw new Error("Legend must be provided in constructor");if(e.start.line!==e.end.line)throw new Error("`range` cannot span multiple lines");if(!this._tokenTypeStrToInt.has(t))throw new Error("`tokenType` is not in the provided legend");let r=e.start.line,o=e.start.character,s=e.end.character-e.start.character,a=this._tokenTypeStrToInt.get(t),l=0;if(i)for(let u of i){if(!this._tokenModifierStrToInt.has(u))throw new Error("`tokenModifier` is not in the provided legend");let c=this._tokenModifierStrToInt.get(u);l|=1<>>0}this._pushEncoded(r,o,s,a,l)}_pushEncoded(e,t,i,r,o){if(this._dataIsSortedAndDeltaEncoded&&(e0&&(s-=this._prevLine,s===0&&(a-=this._prevChar)),this._data[this._dataLen++]=s,this._data[this._dataLen++]=a,this._data[this._dataLen++]=i,this._data[this._dataLen++]=r,this._data[this._dataLen++]=o,this._prevLine=e,this._prevChar=t}static _sortAndDeltaEncode(e){let t=[],i=e.length/5|0;for(let a=0;a{let u=e[5*a],c=e[5*l];if(u===c){let h=e[5*a+1],d=e[5*l+1];return h-d}return u-c});let r=new Array(e.length),o=0,s=0;for(let a=0;a{"use strict";wi();le();Ce();lf();Zo();cw();YP();oa();kG();$f();Ul();V();ke();bo();sD();iu();B_();eu();bc();yo();io();we();var se=C(H());Fr();E_();z();H_();XV();UV.exports={Uri:O,NullLogger:zP,SettingMonitor:k_,LanguageClient:Jf,CancellationTokenSource:se.CancellationTokenSource,ProgressType:se.ProgressType,RequestType:se.RequestType,RequestType0:se.RequestType0,NotificationType:se.NotificationType,NotificationType0:se.NotificationType0,Highligher:Ri,Mru:oo,Emitter:se.Emitter,SnippetString:qr,BasicList:Xt,Mutex:ei,TreeItem:Co,SemanticTokensBuilder:sp,FloatFactory:ci,RelativePattern:bw,UniquenessLevel:se.UniquenessLevel,MonikerKind:se.MonikerKind,PatternType:wg,SourceType:Dg,MessageLevel:Eb,ConfigurationTarget:Pb,ServiceStat:xg,FileType:_b,State:xw,ClientState:Cw,CloseAction:e_,ErrorAction:VP,TransportKind:jw,MessageTransports:mh,RevealOutputChannelOn:Dw,MarkupKind:se.MarkupKind,DiagnosticTag:se.DiagnosticTag,DocumentHighlightKind:se.DocumentHighlightKind,SymbolKind:se.SymbolKind,SignatureHelpTriggerKind:se.SignatureHelpTriggerKind,FileChangeType:se.FileChangeType,CodeActionKind:se.CodeActionKind,Diagnostic:se.Diagnostic,DiagnosticSeverity:se.DiagnosticSeverity,CompletionItemKind:se.CompletionItemKind,InsertTextFormat:se.InsertTextFormat,Location:se.Location,LocationLink:se.LocationLink,CancellationToken:se.CancellationToken,Position:se.Position,Range:se.Range,TextEdit:se.TextEdit,Disposable:se.Disposable,Event:se.Event,workspace:y,window:k,CompletionTriggerKind:se.CompletionTriggerKind,snippetManager:Ut,events:E,services:Mi,commands:oe,sources:Lt,languages:A,diagnosticManager:Ft,extensions:ye,listManager:Di,TreeItemCollapsibleState:nu,fetch:fh,download:Nf,ansiparse:hg,disposeAll:Z,concurrent:ag,watchFile:lc,wait:bt,runCommand:Vr,isRunning:pH,executable:sg}});function J0e(n){return()=>{throw new Error(`process.${n}() is not allowed in extension sandbox`)}}function $0e(){let n=e=>e==="coc.nvim"?GV():this.require(e);return n.resolve=e=>So._resolveFilename(e,this),n.main=process.mainModule,n.extensions=So._extensions,n.cache=So._cache,n}function X0e(n){return function(e,t){let i=$0e.call(this),r=KV.default.dirname(t),o=e.replace(/^\#\!.*/,""),s=So.wrap(o),a=fD.runInContext(s,n,{filename:t}),l=[this.exports,i,this,t,r];return a.apply(this.exports,l)}}function U0e(n,e){let t=new So(n);t.paths=So._nodeModulePaths(n);let i=fD.createContext({module:t,Buffer,console:{debug:(...r)=>{e.debug.apply(e,r)},log:(...r)=>{e.info.apply(e,r)},error:(...r)=>{e.error.apply(e,r)},info:(...r)=>{e.info.apply(e,r)},warn:(...r)=>{e.warn.apply(e,r)}}});eJ(i,global),i.Reflect=Reflect,i.require=function(o){let s=So.prototype._compile;So.prototype._compile=X0e(i);let a=i.module.require(o);return So.prototype._compile=s,a},i.process=new process.constructor;for(let r of Object.keys(process))i.process[r]=process[r];return Z0e.forEach(r=>{i.process[r]=J0e(r)}),i.process.chdir=()=>{},i.process.umask=r=>{if(typeof r<"u")throw new Error("Cannot use process.umask() to change mask (read-only)");return process.umask()},i}function VV(n,e,t=!1){if(t||!QV.default.existsSync(e))return{activate:()=>{},deactivate:null};let i=U0e(e,zV(`extension:${n}`));delete So._cache[require.resolve(e)];let r=i.require(e),o=r&&r.activate||r;return typeof o!="function"?{activate:()=>{},deactivate:null}:{activate:o,deactivate:typeof r.deactivate=="function"?r.deactivate:null}}var QV,KV,fD,zV,GKe,So,Z0e,eee=_(()=>{"use strict";QV=C(require("fs")),KV=C(require("path")),fD=C(require("vm"));Vo();zV=q(),GKe=zV("util-factoroy"),So=require("module"),Z0e=["reallyExit","abort","umask","setuid","setgid","setgroups","_fatalException","exit","kill"]});var aee={};xs(aee,{ExtensionType:()=>see,Extensions:()=>q_,default:()=>ye});var tee,pt,iee,Ie,nee,pD,ree,oee,tn,see,q_,ye,bo=_(()=>{"use strict";tee=C(Ei()),pt=C(Rn()),iee=C(T0());Eg();Ie=C(require("path")),nee=C(nf()),pD=C(H());we();ree=C(rg());wi();wk();le();Nk();Zo();UJ();SG();TG();z();Go();CC();eee();Je();In();ke();V();oee=q(),tn=oee("extensions"),see=(r=>(r[r.Global=0]="Global",r[r.Local=1]="Local",r[r.SingleFile=2]="SingleFile",r[r.Internal=3]="Internal",r))(see||{}),q_=class{constructor(){this.extensions=new Map;this.disabled=new Set;this._onDidLoadExtension=new pD.Emitter;this._onDidActiveExtension=new pD.Emitter;this._onDidUnloadExtension=new pD.Emitter;this._additionalSchemes={};this.activated=!1;this.disposables=[];this.ready=!0;this.onDidLoadExtension=this._onDidLoadExtension.event;this.onDidActiveExtension=this._onDidActiveExtension.event;this.onDidUnloadExtension=this._onDidUnloadExtension.event;let e=global.__TEST__?Ie.default.join(__dirname,"__tests__"):process.env.COC_DATA_HOME,t=this.root=Ie.default.join(e,"extensions");if(this.checkRoot(t)){let r=Ie.default.join(t,"db.json");this.db=new qc(r)}}checkRoot(e){try{pt.default.existsSync(e)||pt.default.mkdirpSync(e);let t=pt.default.statSync(e);if(t.isFile())tn.info(`Trying to delete ${e}`),pt.default.unlinkSync(e),pt.default.mkdirpSync(e);else if(!t.isDirectory())return console.error(`Data home ${e} it not a valid directory`),!1;let i=Ie.default.join(e,"package.json");pt.default.existsSync(i)||pt.default.writeFileSync(i,'{"dependencies":{}}',"utf8")}catch(t){return console.error(`Unexpected error when check data home: ${t}`),!1}return!0}get outputChannel(){return this._outputChannel?this._outputChannel:(this._outputChannel=k.createOutputChannel("extensions"),this._outputChannel)}async init(){let e=this.db.fetch("extension")||{},t=Object.keys(e);for(let o of t)e[o].disabled==!0&&this.disabled.add(o);if(process.env.COC_NO_PLUGINS)return;let i=await this.globalExtensionStats(),r=await this.localExtensionStats(i.map(o=>o.id));i=i.concat(r),this.memos=new mw(Ie.default.resolve(this.root,"../memos.json")),i.map(o=>{let s=o.isLocal?1:0;try{this.createExtension(o.root,o.packageJSON,s)}catch(a){tn.error(`Error on create ${o.root}:`,a)}}),await this.loadFileExtensions(),oe.register({id:"extensions.forceUpdateAll",execute:async()=>{let o=await this.cleanExtensions();tn.info(`Force update extensions: ${o}`),await this.installExtensions(o)}},!1,"remove all global extensions and install them"),y.onDidRuntimePathChange(async o=>{for(let s of o)s&&this.checkDirectory(s)===!0&&await this.loadExtension(s)},null,this.disposables)}getExtensionsInfo(){let e=[];for(let[t,i]of this.extensions.entries()){let{directory:r,filepath:o}=i;r||(r=o),i.type,r&&e.push({name:t,filepath:o,directory:r.endsWith(Ie.default.sep)?r:r+Ie.default.sep})}return e}activateExtensions(){this.activated=!0;for(let o of this.extensions.values()){let{id:s,packageJSON:a}=o.extension;this.setupActiveEvents(s,a).logError()}let e=new ci(y.nvim);if(E.on("CursorMoved",(0,tee.debounce)(async o=>{if(this.installBuffer&&o==this.installBuffer.bufnr){let s=await y.nvim.call("line",["."]),a=this.installBuffer.getMessages(s-1),l=a&&a.length?[{content:a.join(` -`),filetype:"txt"}]:[];await e.show(l,{modes:["n"]})}},500)),global.__TEST__)return;this.checkExtensions();let t=y.getConfiguration("coc.preferences"),i=t.get("extensionUpdateCheck","never"),r=t.get("silentAutoupdate",!0);if(i!="never"){let o=new Date,s=new Date(o.getFullYear(),o.getMonth(),o.getDate()-(i=="daily"?0:7)),a=this.db.fetch("lastUpdate");if(a&&Number(a)>s.getTime())return;this.outputChannel.appendLine("Start auto update..."),this.updateExtensions(!1,r).logError()}}async updateExtensions(e,t=!1){if(!this.npm)return;let i=await this.getLockedList(),r=await this.globalExtensionStats();r=r.filter(l=>![...i,...this.disabled].includes(l.id)),this.db.push("lastUpdate",Date.now()),t&&k.showMessage("Updating extensions, checkout output:///extensions for details.","more");let o=this.installBuffer=new uf(!0,e,t?this.outputChannel:void 0);o.setExtensions(r.map(l=>l.id)),await o.show(y.nvim);let s=pw(this.npm,this.modulesFolder);await ag(r,l=>{let{id:u}=l;o.startProgress([u]);let c=l.exotic?l.uri:null,h=s(u);return h.on("message",(d,g)=>{o.addMessage(u,d,g)}),h.update(c).then(d=>{o.finishProgress(u,!0),d&&this.loadExtension(d).logError()},d=>{o.addMessage(u,d.message),o.finishProgress(u,!1)})},t?1:3)}checkExtensions(){let{globalExtensions:e}=y.env;if(e&&e.length){let t=this.filterGlobalExtensions(e);this.installExtensions(t)}}get installer(){return pw(this.npm,this.modulesFolder)}async installExtensions(e=[]){let{npm:t}=this;if(!t||!e.length)return;e=sa(e);let i=this.installBuffer=new uf;i.setExtensions(e),await i.show(y.nvim);let r=pw(this.npm,this.modulesFolder);await ag(e,s=>{i.startProgress([s]);let a=r(s);return a.on("message",(l,u)=>{i.addMessage(s,l,u)}),a.install().then(l=>{i.finishProgress(s,!0);let u=Ie.default.join(this.modulesFolder,l);this.loadExtension(u).logError(),s.match(/(.+)@([^/]+)$/)!=null&&this.lockExtension(l,!0)},l=>{i.addMessage(s,l.message),i.finishProgress(s,!1),tn.error(`Error on install ${s}`,l)})})}getMissingExtensions(){let e=this.loadJson()||{dependencies:{}},t=[];for(let i of Object.keys(e.dependencies)){let r=Ie.default.join(this.modulesFolder,i);if(!pt.default.existsSync(r)){let o=e.dependencies[i];o.startsWith("http")?t.push(o):t.push(i)}}return t}get npm(){let e=y.getConfiguration("npm").get("binPath","npm");e=y.expand(e);for(let t of[e,"yarnpkg","yarn","npm"])try{return ree.default.sync(t)}catch{continue}return k.showMessage("Can't find npm or yarn in your $PATH","error"),null}get all(){return Array.from(this.extensions.values()).map(e=>e.extension).filter(e=>!this.isDisabled(e.id))}getExtension(e){return this.extensions.get(e)}getExtensionState(e){if(this.isDisabled(e))return"disabled";let i=this.extensions.get(e);if(!i)return"unknown";let{extension:r}=i;return r.isActive?"activated":"loaded"}async getExtensionStates(){let e=await this.localExtensionStats([]),t=await this.globalExtensionStats();return e.concat(t.filter(i=>e.find(r=>r.id==i.id)==null))}async getLockedList(){let e=await this.db.fetch("extension");return e=e||{},Object.keys(e).filter(t=>e[t].locked===!0)}async lockExtension(e,t){let i=`extension.${e}.locked`,r=await this.db.fetch(i);t=t===void 0?!r:t,t?this.db.push(i,!0):this.db.delete(i)}async toggleExtension(e){let t=this.getExtensionState(e);if(t==null)return;t=="activated"&&await this.deactivate(e);let i=`extension.${e}.disabled`;if(this.db.push(i,t!="disabled"),t!="disabled")this.disabled.add(e),await this.unloadExtension(e);else{this.disabled.delete(e);let r=Ie.default.join(this.modulesFolder,e);pt.default.existsSync(r)&&await this.loadExtension(r)}await bt(200)}async reloadExtension(e){let t=this.extensions.get(e);if(!t){k.showMessage(`Extension ${e} not registered`,"error");return}if(t.type==3){k.showMessage(`Can't reload internal extension "${t.id}"`,"warning");return}t.type==2?await this.loadExtensionFile(t.filepath):t.directory?await this.loadExtension(t.directory):k.showMessage(`Can't reload extension ${t.id}`,"warning")}async cleanExtensions(){let e=this.modulesFolder;if(!pt.default.existsSync(e))return[];let t=this.globalExtensions,i=[];for(let r of t){let o=Ie.default.join(e,r),s=await pt.default.lstat(o);!s||s&&s.isSymbolicLink()||(await this.unloadExtension(r),await pt.default.remove(o),i.push(r))}return i}async uninstallExtension(e){try{if(!e.length)return;let[t,i]=sy(e,a=>this.globalExtensions.includes(a));i.length&&k.showMessage(`Extensions ${i} not global extensions, can't uninstall!`,"warning");let r=this.loadJson()||{dependencies:{}};for(let a of t){await this.unloadExtension(a),delete r.dependencies[a];let l=Ie.default.join(this.modulesFolder,a);pt.default.existsSync(l)&&await pt.default.remove(l)}let o={dependencies:{}};Object.keys(r.dependencies).sort().forEach(a=>{o.dependencies[a]=r.dependencies[a]});let s=Ie.default.join(this.root,"package.json");pt.default.writeFileSync(s,JSON.stringify(o,null,2),{encoding:"utf8"}),k.showMessage(`Removed: ${t.join(" ")}`)}catch(t){k.showMessage(`Uninstall failed: ${t}`,"error")}}isDisabled(e){return this.disabled.has(e)}has(e){return this.extensions.has(e)}isActivated(e){let t=this.extensions.get(e);return!!(t&&t.extension.isActive)}async loadExtension(e){if(Array.isArray(e)){for(let t of e)await this.loadExtension(t);return!0}try{let t=Ie.default.dirname(e),i=Ie.default.normalize(t)!=Ie.default.normalize(this.modulesFolder),r=Ie.default.join(e,"package.json"),o=JSON.parse(pt.default.readFileSync(r,"utf8")),{name:s}=o;return this.isDisabled(s)?!1:(await this.unloadExtension(s),this.createExtension(e,Object.freeze(o),i?1:0),!0)}catch(t){return k.showMessage(`Error on load extension from "${e}": ${t}`,"error"),tn.error(`Error on load extension from ${e}`,t),!1}}async loadFileExtensions(){if(!process.env.COC_VIMCONFIG)return;let e=Ie.default.join(process.env.COC_VIMCONFIG,"coc-extensions");if(!pt.default.existsSync(e))return;let t=await pt.default.readdir(e);t=t.filter(i=>i.endsWith(".js"));for(let i of t)await this.loadExtensionFile(Ie.default.join(e,i))}loadedExtensions(){return Array.from(this.extensions.keys())}async watchExtension(e){let t=this.extensions.get(e);if(!t){k.showMessage(`extension ${e} not found`,"error");return}if(e.startsWith("single-"))k.showMessage(`watching ${t.filepath}`),this.disposables.push(lc(t.filepath,async()=>{await this.loadExtensionFile(t.filepath),k.showMessage(`reloaded ${e}`)}));else{let i=y.getWatchmanPath();if(!i){k.showMessage("watchman not found","error");return}let r=await la.createClient(i,t.directory);if(!r){k.showMessage("Can't create watchman client, check output:///watchman");return}k.showMessage(`watching ${t.directory}`),this.disposables.push(r),r.subscribe("**/*.js",async()=>{await this.reloadExtension(e),k.showMessage(`reloaded ${e}`)}).then(o=>{this.disposables.push(o)},o=>{})}}async loadExtensionFile(e){let t=Ie.default.basename(e),i=Ie.default.basename(e,".js"),r="single-"+i;if(this.isDisabled(r))return;let o=Ie.default.dirname(e),s={name:r,main:t,engines:{coc:"^0.0.79"}},a=Ie.default.join(o,i+".json"),l=await Ht(a);if(l&&l.isFile()){let u=await xc(a,"utf8"),c=JSON.parse(u);if(c){let h=["activationEvents","contributes"];for(let d of h)c[d]&&(s[d]=c[d])}}await this.unloadExtension(r),this.createExtension(o,s,2)}async activate(e){if(this.isDisabled(e))throw new Error(`Extension ${e} is disabled!`);let t=this.extensions.get(e);if(!t)throw new Error(`Extension ${e} not registered!`);let{extension:i}=t;return i.isActive?!0:(await Promise.resolve(i.activate()),i.isActive?(this._onDidActiveExtension.fire(i),!0):!1)}async deactivate(e){let t=this.extensions.get(e);return t?(await Promise.resolve(t.deactivate()),!0):!1}async call(e,t,i){let r=this.extensions.get(e);if(!r)throw new Error(`extension ${e} not registered`);let{extension:o}=r;o.isActive||await this.activate(e);let{exports:s}=o;if(!s||!s.hasOwnProperty(t))throw new Error(`method ${t} not found on extension ${e}`);return await Promise.resolve(s[t].apply(null,i))}getExtensionApi(e){let t=this.extensions.get(e);if(!t)return null;let{extension:i}=t;return i.isActive?i.exports:null}registerExtension(e,t){let{id:i,packageJSON:r}=e;this.extensions.set(i,{id:i,type:3,extension:e,deactivate:t,isLocal:!0});let{contributes:o}=r;if(o){let{configuration:s}=o;if(s&&s.properties){let{properties:a}=s,l={};for(let u of Object.keys(a)){let c=a[u].default;c!=null&&(l[u]=c)}y.configurations.extendsDefaults(l)}}this._onDidLoadExtension.fire(e),this.setupActiveEvents(i,r).logError()}get globalExtensions(){let e=this.loadJson();return!e||!e.dependencies?[]:Object.keys(e.dependencies)}async globalExtensionStats(){let e=this.loadJson();if(!e||!e.dependencies)return[];let{modulesFolder:t}=this;return(await Promise.all(Object.keys(e.dependencies).map(r=>new Promise(async o=>{try{let s=e.dependencies[r],a=Ie.default.join(t,r),l=this.checkDirectory(a);if(l instanceof Error)return k.showMessage(`Unable to load global extension at ${a}: ${l.message}`,"error"),tn.error(`Error on load ${a}`,l),o(null);let u=await xc(Ie.default.join(a,"package.json"),"utf8");a=await pt.default.realpath(a);let c=JSON.parse(u),h=c&&c.version||"",d=c&&c.description||"",g=iee.default.isValid(s)?s:"";o({id:r,isLocal:!1,version:h,description:d,exotic:/^https?:/.test(s),uri:g.replace(/\.git(#master)?$/,""),root:a,state:this.getExtensionState(r),packageJSON:Object.freeze(c)})}catch(s){tn.error(s),o(null)}})))).filter(r=>r!=null)}async localExtensionStats(e){let i=(await y.nvim.eval('join(globpath(&runtimepath, "", 0, 1), ",")')).split(",");return(await Promise.all(i.map(o=>new Promise(async s=>{try{if(this.checkDirectory(o)!==!0)return s(null);let l=Ie.default.join(o,"package.json"),u=await xc(l,"utf8"),c=JSON.parse(u),h=this.extensions.get(c.name);if(h&&!h.isLocal)return tn.info(`Extension "${c.name}" in runtimepath already loaded.`),s(null);if(e.includes(c.name))return tn.info(`Skipped load vim plugin from "${o}", "${c.name}" already global extension.`),s(null);let d=c&&c.version||"",g=c&&c.description||"";s({id:c.name,isLocal:!0,version:d,description:g,exotic:!1,root:o,state:this.getExtensionState(c.name),packageJSON:Object.freeze(c)})}catch(a){tn.error(a),s(null)}})))).filter(o=>o!=null)}loadJson(){let{root:e}=this,t=Ie.default.join(e,"package.json");if(!pt.default.existsSync(t))return null;let i=[],r=pt.default.readFileSync(t,"utf8"),o=_c(r,i,{allowTrailingComma:!0});return i&&i.length>0&&(k.showMessage(`Error on parse ${t}`,"error"),y.nvim.call("coc#util#open_file",["edit",t],!0)),o}get schemes(){return this._additionalSchemes}addSchemeProperty(e,t){this._additionalSchemes[e]=t,y.configurations.extendsDefaults({[e]:t.default})}async setupActiveEvents(e,t){let{activationEvents:i}=t;if(!this.canActivate(e))return;if(!i||Array.isArray(i)&&i.includes("*")){await this.activate(e).catch(a=>{k.showMessage(`Error on activate extension ${e}: ${a.message}`),this.outputChannel.appendLine(`Error on activate extension ${e}. -${a.message} - ${a.stack}`)});return}let r=[],o=!1,s=()=>{if(!o)return o=!0,Z(r),new Promise(a=>{if(!this.canActivate(e))return this.outputChannel.appendLine(`Extension ${e} is disabled or not loaded.`),a();this.activate(e).then(()=>{a()},l=>{k.showMessage(`Error on activate extension ${e}: ${l.message}`),this.outputChannel.appendLine(`Error on activate extension ${e}:${l.message} - ${l.stack}`),a()})})};for(let a of i){let l=a.split(":"),u=l[0];if(u=="onLanguage"){if(y.languageIds.has(l[1])||y.filetypes.has(l[1])){await s();return}y.onDidOpenTextDocument(c=>{let h=y.getDocument(c.bufnr);(c.languageId==l[1]||h.filetype==l[1])&&s()},null,r)}else if(u=="onCommand")oe.onCommandList.push(l[1]),E.on("Command",async c=>{c==l[1]&&(await s(),await bt(500))},null,r);else if(u=="workspaceContains"){let c=async()=>{let d=y.workspaceFolders.map(g=>O.parse(g.uri).fsPath);for(let g of d)for(let f of l[1].split(/\s+/))if(await A2(g,f))return await s(),!0;return!1};if(y.onDidChangeWorkspaceFolders(c,null,r),await c())return}else if(u=="onFileSystem"){for(let c of y.documents)if(O.parse(c.uri).scheme==l[1]){await s();return}y.onDidOpenTextDocument(c=>{O.parse(c.uri).scheme==l[1]&&s()},null,r)}else k.showMessage(`Unsupported event ${a} of ${e}`,"error")}}createExtension(e,t,i){let r=t.name,o=!1,s,a=Ie.default.join(e,t.main||"index.js"),l,u=[],c,h={activate:()=>{if(s)return s;let g={subscriptions:u,extensionPath:e,globalState:this.memos.createMemento(`${r}|global`),workspaceState:this.memos.createMemento(`${r}|${y.rootPath}`),asAbsolutePath:f=>Ie.default.join(e,f),storagePath:Ie.default.join(this.root,`${r}-data`),logger:oee(r)};if(!l)try{let f=!(t.engines||{}).hasOwnProperty("coc");l=VV(r,a,f)}catch(f){tn.error(`Error on createExtension ${r} from ${a}`,f);return}return s=new Promise((f,p)=>{try{Promise.resolve(l.activate(g)).then(b=>{o=!0,c=b,f(b)},b=>{tn.error(`Error on active extension ${r}: ${b.message}`,b),p(b)})}catch(b){tn.error(`Error on active extension ${r}: ${b}`,b instanceof Error?b.stack:b),p(b)}}),s}};Object.defineProperties(h,{id:{get:()=>r,enumerable:!0},packageJSON:{get:()=>t,enumerable:!0},extensionPath:{get:()=>e,enumerable:!0},isActive:{get:()=>o,enumerable:!0},exports:{get:()=>{if(!o)throw new Error(`Invalid access to exports, extension "${r}" not activated`);return c},enumerable:!0}}),this.extensions.set(r,{id:r,type:i,isLocal:i==1,extension:h,directory:e,filepath:a,deactivate:()=>{if(!!o&&(s=void 0,c=void 0,o=!1,Z(u),u.splice(0,u.length),u=[],l&&l.deactivate))try{return Promise.resolve(l.deactivate()).catch(g=>{tn.error(`Error on ${r} deactivate: `,g)})}catch(g){tn.error(`Error on ${r} deactivate: `,g)}}});let{contributes:d}=t;if(d){let{configuration:g,rootPatterns:f,commands:p}=d;if(g&&g.properties){let{properties:b}=g,v={};for(let w of Object.keys(b)){let D=b[w].default;D!=null&&(v[w]=D)}y.configurations.extendsDefaults(v)}if(f&&f.length)for(let b of f)y.workspaceFolderControl.addRootPattern(b.filetype,b.patterns);if(p&&p.length)for(let b of p)oe.titles.set(b.command,b.title)}this._onDidLoadExtension.fire(h),this.activated&&this.setupActiveEvents(r,t).logError()}filterGlobalExtensions(e){let t=new Map;e.forEach(s=>{let a=this.getExtensionName(s);a&&t.set(a,s)});let i=this.loadJson(),r=[],o=[];if(i&&i.dependencies)for(let s of Object.keys(i.dependencies)){let a=i.dependencies[s];typeof a=="string"&&pt.default.existsSync(Ie.default.join(this.modulesFolder,s,"package.json"))&&(o.push(s),/^https?:/.test(a)&&r.push(a))}for(let s of t.keys()){if(this.disabled.has(s)||this.extensions.has(s)){t.delete(s);continue}(/^https?:/.test(s)&&r.some(a=>a.startsWith(s))||o.includes(s))&&t.delete(s)}return Array.from(t.values())}getExtensionName(e){return/^https?:/.test(e)||!e.includes("@")?e:e.replace(/@[\d.]+$/,"")}get modulesFolder(){return Ie.default.join(this.root,global.__TEST__?"":"node_modules")}canActivate(e){return!this.disabled.has(e)&&this.extensions.has(e)}async unloadExtension(e){this.extensions.get(e)&&(await this.deactivate(e),this.extensions.delete(e),this._onDidUnloadExtension.fire(e))}checkDirectory(e){try{let t=Ie.default.join(e,"package.json");if(!pt.default.existsSync(t))throw new Error("package.json not found");let i=JSON.parse(pt.default.readFileSync(t,"utf8")),{name:r,engines:o,main:s}=i;if(!r||!o)throw new Error("can't find name & engines in package.json");if(!o||!_t(o))throw new Error(`invalid engines in ${t}`);if(s&&!pt.default.existsSync(Ie.default.join(e,s)))throw new Error(`main file ${s} not found, you may need to build the project.`);let a=Object.keys(o);if(!a.includes("coc")&&!a.includes("vscode"))throw new Error("Engines in package.json doesn't have coc or vscode");if(a.includes("coc")){let l=o.coc.replace(/^\^/,">=");if(!nee.default.satisfies(y.version,l))throw new Error(`Please update coc.nvim, ${i.name} requires coc.nvim ${o.coc}`)}return!0}catch(t){return t}}dispose(){Z(this.disposables)}},ye=new q_});var lee,xze,G0e,mD,uee=_(()=>{"use strict";lee=C(H());we();le();Je();xze=q()("sources-keywords"),G0e=10*1024,mD=class{constructor(e){this.doc=e;this._words=new Set;this._gitIgnored=!1;this.parse();let t=O.parse(e.uri);t.scheme==="file"&&j2(t.fsPath).then(i=>{this._gitIgnored=i})}get bufnr(){return this.doc.bufnr}get gitIgnored(){return this._gitIgnored}get words(){return this._words}parse(){if(!this.doc.attached||E.completing)return;let{textDocument:e}=this.doc,{version:t,lineCount:i}=e;if(this.version===t||E.insertMode&&this.lineCount==i&&e.length>G0e)return;this.cancel();let r=this.tokenSource=new lee.CancellationTokenSource;this.doc.matchWords(r.token).then(o=>{o!=null&&(this._words=o,this.lineCount=i,this.version=t)})}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource=null)}onChange(e){e.contentChanges.length!=0&&this.parse()}dispose(){this.cancel(),this._words.clear()}}});var Fze,dr,Eh=_(()=>{"use strict";Fr();Pe();V();Fze=q()("sources-source"),dr=class{constructor(e){this._disabled=!1;this.nvim=y.nvim,this.name=e.name,this.filepath=e.filepath||"",this.sourceType=e.sourceType||0,this.isSnippet=!!e.isSnippet,this.defaults=e}get priority(){return this.getConfig("priority",1)}get triggerOnly(){let e=this.defaults.triggerOnly;return typeof e=="boolean"?e:!this.triggerCharacters&&!this.triggerPatterns?!1:Array.isArray(this.triggerPatterns)&&this.triggerPatterns.length!=0}get triggerCharacters(){return this.getConfig("triggerCharacters",null)}get optionalFns(){return this.defaults.optionalFns||[]}get triggerPatterns(){let e=this.getConfig("triggerPatterns",null);return!e||e.length==0?null:e.map(t=>typeof t=="string"?new RegExp(t+"$"):t)}get shortcut(){let e=this.getConfig("shortcut","");return e||this.name.slice(0,3)}get enable(){return this._disabled?!1:this.getConfig("enable",!0)}get filetypes(){return this.getConfig("filetypes",null)}get disableSyntaxes(){return this.getConfig("disableSyntaxes",[])}getConfig(e,t){let i=y.getConfiguration(`coc.source.${this.name}`);return t=this.defaults.hasOwnProperty(e)?this.defaults[e]:t,i.get(e,t)}toggle(){this._disabled=!this._disabled}get firstMatch(){return this.getConfig("firstMatch",!0)}get menu(){let{shortcut:e}=this;return e?`[${e}]`:""}fixStartcol(e,t){let{col:i,input:r,line:o,bufnr:s}=e,a=et(o,0,i),l=y.getDocument(s);if(!l)return i;let{chars:u}=l;for(let c=a.length-1;c>=0;c--){let h=a[c];if(!u.isKeywordChar(h)&&!t.includes(h))break;r=`${h}${r}`,i=i-1}return e.col=i,e.input=r,i}async shouldComplete(e){let{disableSyntaxes:t}=this;if(e.synname&&t&&t.length){let r=(e.synname||"").toLowerCase();if(t.findIndex(o=>r.includes(o.toLowerCase()))!==-1)return!1}let i=this.defaults.shouldComplete;return typeof i=="function"?await Promise.resolve(i.call(this,e)):!0}async refresh(){let e=this.defaults.refresh;typeof e=="function"&&await Promise.resolve(e.call(this))}async onCompleteDone(e,t){let i=this.defaults.onCompleteDone;typeof i=="function"&&await Promise.resolve(i.call(this,e,t))}async doComplete(e,t){let i=this.defaults.doComplete;return typeof i=="function"?await Promise.resolve(i.call(this,e,t)):null}}});function K0e(n,e){let t=e[0];if(t.textEdit==null)return;let i=Gt.InsertReplaceEdit.is(t.textEdit)?t.textEdit.replace:t.textEdit.range,{character:r}=i.start;for(let o=1;of)u=h.slice(f,c.start.character)+u;else{let p=h.slice(c.start.character,f);p.length&&u.startsWith(p)&&(u=u.slice(p.length))}if(f=Ui(h,g-1),c.end.character>f){let p=h.slice(f,c.end.character);u.endsWith(p)&&(u=u.slice(0,-p.length))}}}else s&&(u=s);if(o==Gt.InsertTextFormat.Snippet&&u&&u.includes("$")){let h=new Fa().text(u);l=h?cee(h,t):i}else l=cee(u,t)||i;return l||""}function cee(n,e,t=2){if(!n)return"";if(!e.length)return n;for(let i=t;i{"use strict";Gt=C(H());wi();iu();uD();ls();Pe();ke();V();Q0e=q()("source-language"),bD=class{constructor(e,t,i,r,o,s,a,l){this.name=e;this.shortcut=t;this.provider=i;this.documentSelector=r;this.triggerCharacters=o;this.allCommitCharacters=s;this.completeConfig=l;this._enabled=!0;this.completeItems=[];this.priority=typeof a=="number"?a:l.priority}get enable(){return this._enabled}toggle(){this._enabled=!this._enabled}shouldCommit(e,t){let i=this.completeItems[e.index];return i?[...this.allCommitCharacters,...i.commitCharacters||[]].includes(t):!1}async doComplete(e,t){let{triggerCharacter:i,input:r,bufnr:o}=e;this.filetype=e.filetype,this.completeItems=[];let s=this.getTriggerKind(e),a=this.getPosition(e),l={triggerKind:s,option:e};s==Gt.CompletionTriggerKind.TriggerCharacter&&(l.triggerCharacter=i);let u=y.getAttachedDocument(o),c=await Promise.resolve(this.provider.provideCompletionItems(u.textDocument,a,t,l));if(!c||t.isCancellationRequested)return null;let h=Array.isArray(c)?c:c.items;if(!h||h.length==0)return null;this.completeItems=h;let d=K0e(e.line,h),g=Object.assign({},e),f,p=typeof c.isIncomplete=="boolean"?c.isIncomplete:!1;d==null&&r.length>0&&this.triggerCharacters.includes(e.triggerCharacter)&&(h.every(v=>{var w;return((w=v.insertText)!=null?w:v.label).startsWith(e.input)})||(d=e.col+Q(e.input))),d!=null&&(f=d{let D=this.convertVimCompleteItem(v,this.shortcut,g,f);return D.index=w,D});return{startcol:d,isIncomplete:p,items:b}}async onCompleteResolve(e,t){let{index:i}=e,r=this.completeItems[i];if(!r||e.resolved)return;if(typeof this.provider.resolveCompletionItem=="function"){let s=await Promise.resolve(this.provider.resolveCompletionItem(r,t));if(t.isCancellationRequested||!s)return;Object.assign(r,s)}if(typeof e.documentation>"u"){let{documentation:s,detail:a}=r;if(!s&&!a)return;let l=[];if(a&&!e.detailShown&&a!=e.word&&(a=a.replace(/\n\s*/g," "),a.length)){let u=/^[\w-\s.,\t\n]+$/.test(a);l.push({filetype:u?"txt":this.filetype,content:a})}s&&(typeof s=="string"?l.push({filetype:"txt",content:s}):s.value&&l.push({filetype:s.kind=="markdown"?"markdown":"txt",content:s.value})),e.resolved=!0,e.documentation=l}}async onCompleteDone(e,t){let i=this.completeItems[e.index];if(!i)return;typeof e.line=="string"&&Object.assign(t,{line:e.line});let r=y.getAttachedDocument(t.bufnr);await r.patchChange(!0);let o=Array.isArray(i.additionalTextEdits)&&i.additionalTextEdits.length>0;o&&await Ut.editsInsideSnippet(i.additionalTextEdits)&&Ut.cancel();let s=r.version,a=await this.applyTextEdit(r,o,i,e.word,t);o&&(await r.applyEdits(i.additionalTextEdits,r.version!=s,!a),a&&await Ut.selectCurrentPlaceholder()),i.command&&(oe.has(i.command.command)?await oe.execute(i.command):Q0e.warn(`Command "${i.command.command}" not registered to coc.nvim`))}async applyTextEdit(e,t,i,r,o){var w,D;let{line:s,linenr:a,colnr:l,col:u}=o,c=await k.getCursorPosition();if(c.line!=a-1)return;let{textEdit:h}=i,d=e.getline(a-1),g=Ui(s,l-1);if(!h&&i.insertText&&(h={range:Gt.Range.create(c.line,Ui(s,u),c.line,g),newText:i.insertText}),!h)return!1;let f=h.newText,p=Gt.InsertReplaceEdit.is(h)?h.replace:h.range,b=eTe(s,d,p);b&&(g+=b),p.end.characterg&&(p.end.character+=c.character-g);let v=i.insertTextFormat===Gt.InsertTextFormat.Snippet;if(v&&this.completeConfig.snippetsSupport===!1&&(v=!1,f=r),v){let S=((w=i.data)==null?void 0:w.ultisnip)===!0?{}:(D=i.data)==null?void 0:D.ultisnip;return await Ut.insertSnippet(f,!t,p,i.insertTextMode,S||void 0)}return await e.applyEdits([Gt.TextEdit.replace(p,f)],!1,c),!1}getTriggerKind(e){let{triggerCharacters:t}=this,i=t.includes(e.triggerCharacter),r=Gt.CompletionTriggerKind.Invoked;return e.triggerForInComplete?r=Gt.CompletionTriggerKind.TriggerForIncompleteCompletions:i&&(r=Gt.CompletionTriggerKind.TriggerCharacter),r}convertVimCompleteItem(e,t,i,r){var f;let{detailMaxLength:o,invalidInsertCharacters:s,detailField:a,labels:l,defaultKindText:u}=this.completeConfig,c=e.additionalTextEdits!=null&&e.additionalTextEdits.length>0,h=e.insertTextFormat===Gt.InsertTextFormat.Snippet||c,d=e.label.trim(),g={word:V0e(e,i,s),abbr:d,menu:`[${t}]`,kind:z0e(e.kind,l,u),sortText:e.sortText||null,sourceScore:e.score||null,filterText:e.filterText||d,isSnippet:h,dup:e.data&&e.data.dup==0?0:1};if(r&&(g.filterText.startsWith(r)||e.textEdit&&mo(xn(r),e.textEdit.newText)&&(g.filterText=e.textEdit.newText.replace(/\r?\n/g,"")),!e.textEdit&&!g.word.startsWith(r)&&(g.word=`${r}${g.word}`)),e&&e.detail&&a!="preview"){let p=e.detail.replace(/\n\s*/g," ");Q(p){"use strict";ls();Pe();V();ke();Eh();Kze=q()("sources-source-vim"),yD=class extends dr{async callOptionalFunc(e,t){if(!this.optionalFns.includes(e))return null;let r=`coc#source#${this.name}#${e}`,o;try{o=await this.nvim.call(r,t)}catch(s){return k.showMessage(`Vim error from source ${this.name}: ${s}`,"error"),null}return o}async shouldComplete(e){return await super.shouldComplete(e)?this.optionalFns.includes("should_complete")?!!await this.callOptionalFunc("should_complete",[e]):!0:!1}async refresh(){await this.callOptionalFunc("refresh",[])}async onCompleteDone(e,t){!this.optionalFns.includes("on_complete")||await this.callOptionalFunc("on_complete",[e])}onEnter(e){if(!this.optionalFns.includes("on_enter"))return;let t=y.getDocument(e);if(!t)return;let{filetypes:i}=this;i&&!i.includes(t.filetype)||this.callOptionalFunc("on_enter",[{bufnr:e,uri:t.uri,languageId:t.filetype}]).logError()}async doComplete(e,t){let{col:i,input:r,line:o,colnr:s}=e,a=await this.callOptionalFunc("get_startcol",[e]);if(t.isCancellationRequested)return;if(a){if(a<0)return null;a=Number(a),(isNaN(a)||a<0)&&(a=i),a!==i&&(r=et(o,a,s-1),e=Object.assign({},e,{col:a,changed:i-a,input:r}))}let l=await this.nvim.callAsync("coc#util#do_complete",[this.name,e]);if(!l||l.length==0||t.isCancellationRequested)return null;if(this.firstMatch&&r.length){let c=r[0];l=l.filter(h=>{let d=h.filterText?h.filterText[0]:h.word[0];return Xf(c,d)})}l=l.map(c=>{if(typeof c=="string")return{word:c,menu:this.menu,isSnippet:this.isSnippet};let h=c.menu?c.menu+" ":"";return c.menu=`${h}${this.menu}`,c.isSnippet=this.isSnippet,delete c.user_data,c});let u={items:l};return a&&(u.startcol=a),u}}});var fee={};xs(fee,{default:()=>vD,regist:()=>tTe});function tTe(n,e){return n.set("around",new vD(e)),gee.Disposable.create(()=>{n.delete("around")})}var gee,n5e,vD,pee=_(()=>{"use strict";gee=C(H());z();ls();Eh();n5e=q()("sources-around"),vD=class extends dr{constructor(e){super({name:"around",filepath:__filename});this.keywords=e}async filterWords(e,t,i,r){let o=!1,{input:s}=t,a=t.word,l=s[0],u=s.length>1,c=t.input.length,h=l.charCodeAt(0),d=h>=97&&h<=122,g=u?xn(s):[],f=!0,p=!0,b=Date.now();for(let v of e){let w=v.length;if(w15){if(await zr(),i.isCancellationRequested)return;b=Date.now()}let D=d?v[0].toLowerCase():v[0];if(u){if(D.charCodeAt(0)===h&&mo(g,v)&&(r.push(v),r.length==100)){o=!0;break}}else if(D.charCodeAt(0)===h&&(r.push(v),r.length==100)){o=!0;break}}return o}async doComplete(e,t){let{bufnr:i,input:r}=e;if(r.length===0||(await zr(),t.isCancellationRequested))return null;let o=this.keywords.getItem(i),s=o==null?void 0:o.words;if(!s)return null;let a=[],l=await this.filterWords(s,e,t,a);return t.isCancellationRequested?null:{isIncomplete:l,items:a.map(u=>({word:u,menu:this.menu}))}}}});var bee={};xs(bee,{default:()=>wD,regist:()=>iTe});function iTe(n,e){return n.set("buffer",new wD(e)),mee.Disposable.create(()=>{n.delete("buffer")})}var mee,l5e,wD,yee=_(()=>{"use strict";mee=C(H());z();ls();Eh();l5e=q()("sources-buffer"),wD=class extends dr{constructor(e){super({name:"buffer",filepath:__filename});this.keywords=e}get ignoreGitignore(){return this.getConfig("ignoreGitignore",!0)}async getWords(e,t,i,r){let{ignoreGitignore:o}=this,s=!1,a=t.input[0],l=t.input.length,u=l>1,c=a.charCodeAt(0),h=c>=97&&c<=122,d=u?xn(t.input):[],g=Date.now();for(let f of this.keywords.items){if(r.size==100)break;if(!(f.bufnr===e||o&&f.gitIgnored))for(let p of f.words){if(Date.now()-g>15){if(await zr(),i.isCancellationRequested)return;g=Date.now()}if(p.length({word:a,menu:this.menu}))}}}});var xee={};xs(xee,{default:()=>xD,regist:()=>oTe});function oTe(n){return n.set("file",new xD),Dee.Disposable.create(()=>{n.delete("file")})}var DD,vee,Tn,wee,Dee,nTe,rTe,xD,Cee=_(()=>{"use strict";DD=C(require("fs")),vee=C(Vn()),Tn=C(require("path")),wee=C(require("util")),Dee=C(H());Eh();Je();Pe();ac();V();nTe=q()("sources-file"),rTe=/(?:\.{0,2}|~|\$HOME|([\w]+)|[a-zA-Z]:|)(\/|\\+)(?:[\u4E00-\u9FA5\u00A0-\u024F\w .@()-]+(\/|\\+))*(?:[\u4E00-\u9FA5\u00A0-\u024F\w .@()-])*$/,xD=class extends dr{constructor(){super({name:"file",filepath:__filename})}get triggerCharacters(){let e=this.getConfig("triggerCharacters",[]);return Xi?e:e.filter(t=>t!="\\")}resolveEnvVariables(e){let t=e;return t=t.replace(/%([^%]+)%/g,(i,r)=>process.env[r]),t=t.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/gi,(i,r,o)=>process.env[r||o]),t}getPathOption(e){let{line:t,colnr:i}=e,r=et(t,0,i-1);if(r=this.resolveEnvVariables(r),!r||r.endsWith("//"))return null;let o=r.match(rTe);if(o&&o.length){let s=y.expand(o[0]),a=o[0].match(/[^/\\]*$/)[0];return{pathstr:s,part:o[1],startcol:i-a.length-1,input:a}}return null}async getFileItem(e,t){let i=Tn.default.join(e,t),r=await Ht(i);if(r){let o=r.isDirectory()?t+"/":t;return{word:t,abbr:o}}return null}filterFiles(e){let t=this.getConfig("ignoreHidden",!0),i=this.getConfig("ignorePatterns",[]);return e.filter(r=>{if(r==null||t&&r.startsWith("."))return!1;for(let o of i)if((0,vee.default)(r,o,{dot:!0}))return!1;return!0})}async getItemsFromRoot(e,t){let i=[],r=/[\\/]$/.test(e)?e:Tn.default.dirname(e),o=Tn.default.isAbsolute(e)?r:Tn.default.join(t,r);try{let s=await Ht(o);if(s&&s.isDirectory()){let a=await wee.default.promisify(DD.default.readdir)(o);a=this.filterFiles(a);let l=await Promise.all(a.map(u=>this.getFileItem(o,u)));i=i.concat(l)}return i=i.filter(a=>a!=null),i}catch(s){return nTe.error("Error on list files:",s),i}}get trimSameExts(){return this.getConfig("trimSameExts",[])}async doComplete(e){let{col:t,filepath:i}=e,r=this.getPathOption(e);if(!r)return null;let{pathstr:o,part:s,startcol:a,input:l}=r;if(av.word[0]===b)),{items:f.map(v=>{let w=Tn.default.extname(v.word);return v.word=p&&w===h?v.word.replace(h,""):v.word,{word:`${u}${v.word}`,abbr:`${u}${v.abbr}`,menu:this.menu}})}}}});var Eee={};xs(Eee,{Sources:()=>Y_,default:()=>Lt});var Tee,CD,kee,rt,See,Y_,Lt,Ul=_(()=>{"use strict";Tee=C(require("fs")),CD=C(require("path")),kee=C(require("util")),rt=C(H());le();bo();Fr();z();Go();Je();Pe();uee();ke();V();Eh();hee();dee();See=q()("sources"),Y_=class{constructor(){this.sourceMap=new Map;this.disposables=[];this.remoteSourcePaths=[]}init(){this.loadCompleteConfig(),this.keywords=y.registerBufferSync(e=>new mD(e)),y.onDidChangeConfiguration(e=>{e.affectsConfiguration("suggest")&&this.loadCompleteConfig()},null,this.disposables),this.createNativeSources(),this.createRemoteSources(),E.on("InsertLeave",()=>{for(let e of this.keywords.items)e.parse()},this,this.disposables),E.on("BufEnter",this.onDocumentEnter,this,this.disposables),y.onDidRuntimePathChange(e=>{for(let t of e)t&&this.createVimSources(t)},null,this.disposables)}loadCompleteConfig(){let e=y.getConfiguration("suggest"),t=e.get("completionItemKindLabels",{}),i=new Map([[rt.CompletionItemKind.Text,t.text||"v"],[rt.CompletionItemKind.Method,t.method||"f"],[rt.CompletionItemKind.Function,t.function||"f"],[rt.CompletionItemKind.Constructor,typeof t.constructor=="function"?"f":t["constructor"]],[rt.CompletionItemKind.Field,t.field||"m"],[rt.CompletionItemKind.Variable,t.variable||"v"],[rt.CompletionItemKind.Class,t.class||"C"],[rt.CompletionItemKind.Interface,t.interface||"I"],[rt.CompletionItemKind.Module,t.module||"M"],[rt.CompletionItemKind.Property,t.property||"m"],[rt.CompletionItemKind.Unit,t.unit||"U"],[rt.CompletionItemKind.Value,t.value||"v"],[rt.CompletionItemKind.Enum,t.enum||"E"],[rt.CompletionItemKind.Keyword,t.keyword||"k"],[rt.CompletionItemKind.Snippet,t.snippet||"S"],[rt.CompletionItemKind.Color,t.color||"v"],[rt.CompletionItemKind.File,t.file||"F"],[rt.CompletionItemKind.Reference,t.reference||"r"],[rt.CompletionItemKind.Folder,t.folder||"F"],[rt.CompletionItemKind.EnumMember,t.enumMember||"m"],[rt.CompletionItemKind.Constant,t.constant||"v"],[rt.CompletionItemKind.Struct,t.struct||"S"],[rt.CompletionItemKind.Event,t.event||"E"],[rt.CompletionItemKind.Operator,t.operator||"O"],[rt.CompletionItemKind.TypeParameter,t.typeParameter||"T"]]),r=e.get("floatEnable",!0),o=e.get("detailField","preview");o=="preview"&&(!r||!y.floatSupported)&&(o="menu"),this.completeConfig=Object.assign(this.completeConfig||{},{labels:i,floatEnable:r,detailField:o,defaultKindText:t.default||"",priority:e.get("languageSourcePriority",99),snippetsSupport:e.get("snippetsSupport",!0),detailMaxLength:e.get("detailMaxLength",100),invalidInsertCharacters:e.get("invalidInsertCharacters",["(","<","{","[","\r",` -`])})}get nvim(){return y.nvim}createNativeSources(){this.disposables.push((pee(),Ha(fee)).regist(this.sourceMap,this.keywords)),this.disposables.push((yee(),Ha(bee)).regist(this.sourceMap,this.keywords)),this.disposables.push((Cee(),Ha(xee)).regist(this.sourceMap))}createLanguageSource(e,t,i,r,o,s,a){let l=new bD(e,t,r,i,o||[],a||[],s,this.completeConfig);return See.debug("created service source",e),this.sourceMap.set(e,l),{dispose:()=>{this.sourceMap.delete(e)}}}async createVimSourceExtension(e,t){let i=CD.default.basename(t,".vim");try{await e.command(`source ${t}`);let r=await e.call("coc#util#remote_fns",i);for(let c of["init","complete"])if(!r.includes(c))return k.showMessage(`${c} not found for source ${i}`,"error"),null;let o=await e.call(`coc#source#${i}#init`,[]),s={name:`coc-source-${i}`,engines:{coc:">= 0.0.1"},activationEvents:o.filetypes?o.filetypes.map(c=>`onLanguage:${c}`):["*"],contributes:{configuration:{properties:{[`coc.source.${i}.enable`]:{type:"boolean",default:!0},[`coc.source.${i}.firstMatch`]:{type:"boolean",default:!!o.firstMatch},[`coc.source.${i}.triggerCharacters`]:{type:"number",default:o.triggerCharacters||[]},[`coc.source.${i}.priority`]:{type:"number",default:o.priority||9},[`coc.source.${i}.shortcut`]:{type:"string",default:o.shortcut||i.slice(0,3).toUpperCase(),description:"Shortcut text shown in complete menu."},[`coc.source.${i}.disableSyntaxes`]:{type:"array",default:[],items:{type:"string"}},[`coc.source.${i}.filetypes`]:{type:"array",default:o.filetypes||null,description:"Enabled filetypes.",items:{type:"string"}}}}}},a=new yD({name:i,filepath:t,sourceType:1,optionalFns:r.filter(c=>!["init","complete"].includes(c))}),l=!1,u={id:s.name,packageJSON:s,exports:void 0,extensionPath:t,activate:()=>(l=!0,this.addSource(a),Promise.resolve())};Object.defineProperty(u,"isActive",{get:()=>l}),ye.registerExtension(u,()=>{l=!1,this.removeSource(a)})}catch(r){k.showMessage(`Error on create vim source ${i}: ${r}`,"error")}}createRemoteSources(){let{runtimepath:e}=y.env,t=e.split(",");for(let i of t)this.createVimSources(i).logError()}async createVimSources(e){if(this.remoteSourcePaths.includes(e))return;this.remoteSourcePaths.push(e);let t=CD.default.join(e,"autoload/coc/source"),i=await Ht(t);if(i&&i.isDirectory()){let r=await kee.default.promisify(Tee.default.readdir)(t);r=r.filter(s=>s.endsWith(".vim"));let o=r.map(s=>CD.default.join(t,s));if(o.length==0)return;await Promise.all(o.map(s=>this.createVimSourceExtension(this.nvim,s)))}}get names(){return Array.from(this.sourceMap.keys())}get sources(){return Array.from(this.sourceMap.values())}has(e){return this.names.findIndex(t=>t==e)!=-1}getSource(e){return e&&this.sourceMap.get(e)||null}shouldCommit(e,t){if(!e||!e.source)return!1;let i=this.getSource(e.source);return i&&i.sourceType==2&&typeof i.shouldCommit=="function"?i.shouldCommit(e,t):!1}getCompleteSources(e){let{filetype:t,disabled:i}=e,r=et(e.line,0,e.colnr-1),o=e.input==""&&!!e.triggerCharacter,s=tb(e.filepath,e.bufnr,"",y.env.isCygwin);return i=Array.isArray(i)?i:[],o?this.getTriggerSources(r,t,s,i):this.getNormalSources(e.filetype,s,i)}getNormalSources(e,t,i=[]){let r=e.split(".");return this.sources.filter(o=>{let{filetypes:s,triggerOnly:a,name:l,documentSelector:u,enable:c}=o;return!(i.includes(l)||!c||a||s&&!hk(s,r)||u&&r.every(h=>y.match(u,{uri:t,languageId:h})==0))})}checkTrigger(e,t,i){let{triggerCharacters:r,triggerPatterns:o}=e;return!!((r==null?void 0:r.length)>0&&r.includes(i)||(o==null?void 0:o.length)>0&&o.findIndex(s=>s.test(t))!==-1)}shouldTrigger(e,t,i){return this.getTriggerSources(e,t,i).length>0}getTriggerSources(e,t,i,r=[]){if(!e)return[];let o=e[e.length-1],s=t.split(".");return this.sources.filter(a=>{let{filetypes:l,enable:u,documentSelector:c,name:h}=a;return r.includes(h)||!u||l&&!hk(l,s)||c&&s.every(d=>y.match(c,{uri:i,languageId:d})==0)?!1:this.checkTrigger(a,e,o)})}addSource(e){let{name:t}=e;return this.names.includes(t)&&See.warn(`Recreate source ${t}`),this.sourceMap.set(t,e),rt.Disposable.create(()=>{this.sourceMap.delete(t)})}removeSource(e){let t=typeof e=="string"?e:e.name;this.sourceMap.delete(t)}async refresh(e){for(let t of this.sources)(!e||t.name==e)&&typeof t.refresh=="function"&&await Promise.resolve(t.refresh())}toggleSource(e){if(!e)return;let t=this.getSource(e);!t||typeof t.toggle=="function"&&t.toggle()}sourceStats(){let e=[],t=this.sources;for(let i of t)e.push({name:i.name,priority:i.priority,triggerCharacters:i.triggerCharacters||[],shortcut:i.shortcut||"",filetypes:i.filetypes||[],filepath:i.filepath||"",type:i.sourceType==0?"native":i.sourceType==1?"remote":"service",disabled:!i.enable});return e}onDocumentEnter(e){let{sources:t}=this;for(let i of t)i.enable&&typeof i.onEnter=="function"&&i.onEnter(e)}createSource(e){if(!e.name||!e.doComplete)throw new Error("name and doComplete required for createSource");let t=new dr(Object.assign({sourceType:2},e));return this.addSource(t)}dispose(){Z(this.disposables)}},Lt=new Y_});var To,B7e,Pee,A,Ce=_(()=>{"use strict";To=C(H());eu();zZ();tJ();nJ();oJ();sJ();lJ();cJ();dJ();fJ();mJ();yJ();wJ();xJ();SJ();kJ();PJ();RJ();FJ();jJ();OJ();NJ();HJ();YJ();ZJ();Jk();z();B7e=q()("languages"),Pee=class{constructor(){this._onDidSemanticTokensRefresh=new To.Emitter;this._onDidInlayHintRefresh=new To.Emitter;this.onDidSemanticTokensRefresh=this._onDidSemanticTokensRefresh.event;this.onDidInlayHintRefresh=this._onDidInlayHintRefresh.event;this.onTypeFormatManager=new ev;this.documentLinkManager=new $y;this.documentColorManager=new Zy;this.foldingRangeManager=new Uy;this.renameManager=new iv;this.formatManager=new Gy;this.codeActionManager=new By;this.workspaceSymbolsManager=new lv;this.formatRangeManager=new Qy;this.hoverManager=new Ky;this.signatureManager=new sv;this.documentSymbolManager=new Xy;this.documentHighlightManager=new Jy;this.definitionManager=new Wy;this.declarationManager=new qy;this.typeDefinitionManager=new av;this.referenceManager=new tv;this.implementationManager=new zy;this.codeLensManager=new Hy;this.selectionRangeManager=new nv;this.callHierarchyManager=new My;this.semanticTokensManager=new rv;this.semanticTokensRangeManager=new ov;this.linkedEditingManager=new Vy;this.inlayHintManager=new hv}hasFormatProvider(e){return!!(this.formatManager.hasProvider(e)||this.formatRangeManager.hasProvider(e))}registerOnTypeFormattingEditProvider(e,t,i){return this.onTypeFormatManager.register(e,t,i)}registerCompletionItemProvider(e,t,i,r,o=[],s,a){return i=typeof i=="string"?[{language:i}]:i,(Ul(),Ha(Eee)).default.createLanguageSource(e,t,i,r,o,s,a)}registerCodeActionProvider(e,t,i,r){return this.codeActionManager.register(e,t,i,r)}registerHoverProvider(e,t){return this.hoverManager.register(e,t)}registerSelectionRangeProvider(e,t){return this.selectionRangeManager.register(e,t)}registerSignatureHelpProvider(e,t,i){return this.signatureManager.register(e,t,i)}registerDocumentSymbolProvider(e,t,i){return this.documentSymbolManager.register(e,t,i)}registerFoldingRangeProvider(e,t){return this.foldingRangeManager.register(e,t)}registerDocumentHighlightProvider(e,t){return this.documentHighlightManager.register(e,t)}registerCodeLensProvider(e,t){return this.codeLensManager.register(e,t)}registerDocumentLinkProvider(e,t){return this.documentLinkManager.register(e,t)}registerDocumentColorProvider(e,t){return this.documentColorManager.register(e,t)}registerDefinitionProvider(e,t){return this.definitionManager.register(e,t)}registerDeclarationProvider(e,t){return this.declarationManager.register(e,t)}registerTypeDefinitionProvider(e,t){return this.typeDefinitionManager.register(e,t)}registerImplementationProvider(e,t){return this.implementationManager.register(e,t)}registerReferencesProvider(e,t){return this.referenceManager.register(e,t)}registerRenameProvider(e,t){return this.renameManager.register(e,t)}registerWorkspaceSymbolProvider(e){return arguments.length>1&&typeof arguments[1].provideWorkspaceSymbols=="function"&&(e=arguments[1]),this.workspaceSymbolsManager.register(e)}registerDocumentFormatProvider(e,t,i=0){return this.formatManager.register(e,t,i)}registerDocumentRangeFormatProvider(e,t,i=0){return this.formatRangeManager.register(e,t,i)}registerCallHierarchyProvider(e,t){return this.callHierarchyManager.register(e,t)}registerDocumentSemanticTokensProvider(e,t,i){let r=setTimeout(()=>{this._onDidSemanticTokensRefresh.fire(e)},500),o=this.semanticTokensManager.register(e,t,i,()=>{clearTimeout(r),this._onDidSemanticTokensRefresh.fire(e)});return To.Disposable.create(()=>{clearTimeout(r),o.dispose()})}registerDocumentRangeSemanticTokensProvider(e,t,i){return this._onDidSemanticTokensRefresh.fire(e),this.semanticTokensRangeManager.register(e,t,i)}registerInlayHintsProvider(e,t){let i=[];return i.push(this.inlayHintManager.register(e,t)),this._onDidInlayHintRefresh.fire(e),typeof t.onDidChangeInlayHints=="function"&&t.onDidChangeInlayHints(()=>{this._onDidInlayHintRefresh.fire(e)},null,i),To.Disposable.create(()=>{Z(i),this._onDidInlayHintRefresh.fire(e)})}registerLinkedEditingRangeProvider(e,t){return this.linkedEditingManager.register(e,t)}shouldTriggerSignatureHelp(e,t){return this.signatureManager.shouldTrigger(e,t)}async getHover(e,t,i){return await this.hoverManager.provideHover(e,t,i)}async getSignatureHelp(e,t,i,r){return await this.signatureManager.provideSignatureHelp(e,t,i,r)}async getDefinition(e,t,i){return this.definitionManager.hasProvider(e)?await this.definitionManager.provideDefinition(e,t,i):null}async getDefinitionLinks(e,t,i){return this.definitionManager.hasProvider(e)?await this.definitionManager.provideDefinitionLinks(e,t,i):null}async getDeclaration(e,t,i){return this.declarationManager.hasProvider(e)?await this.declarationManager.provideDeclaration(e,t,i):null}async getTypeDefinition(e,t,i){return this.typeDefinitionManager.hasProvider(e)?await this.typeDefinitionManager.provideTypeDefinition(e,t,i):null}async getImplementation(e,t,i){return this.implementationManager.hasProvider(e)?await this.implementationManager.provideReferences(e,t,i):null}async getReferences(e,t,i,r){return this.referenceManager.hasProvider(e)?await this.referenceManager.provideReferences(e,i,t,r):null}async getDocumentSymbol(e,t){return await this.documentSymbolManager.provideDocumentSymbols(e,t)}getDocumentSymbolMetadata(e){return this.documentSymbolManager.getMetaData(e)}async getSelectionRanges(e,t,i){return await this.selectionRangeManager.provideSelectionRanges(e,t,i)}async getWorkspaceSymbols(e,t){return e=e||"",await this.workspaceSymbolsManager.provideWorkspaceSymbols(e,t)}async resolveWorkspaceSymbol(e,t){return await this.workspaceSymbolsManager.resolveWorkspaceSymbol(e,t)}async prepareRename(e,t,i){return await this.renameManager.prepareRename(e,t,i)}async provideRenameEdits(e,t,i,r){return await this.renameManager.provideRenameEdits(e,t,i,r)}async provideDocumentFormattingEdits(e,t,i){if(!this.formatManager.hasProvider(e)){if(!this.formatRangeManager.hasProvider(e))return null;let o=e.positionAt(e.getText().length),s=To.Range.create(To.Position.create(0,0),o);return await this.provideDocumentRangeFormattingEdits(e,s,t,i)}return await this.formatManager.provideDocumentFormattingEdits(e,t,i)}async provideDocumentRangeFormattingEdits(e,t,i,r){return this.formatRangeManager.hasProvider(e)?await this.formatRangeManager.provideDocumentRangeFormattingEdits(e,t,i,r):null}async getCodeActions(e,t,i,r){return await this.codeActionManager.provideCodeActions(e,t,i,r)}async getDocumentHighLight(e,t,i){return await this.documentHighlightManager.provideDocumentHighlights(e,t,i)}async getDocumentLinks(e,t){return this.documentLinkManager.hasProvider(e)?await this.documentLinkManager.provideDocumentLinks(e,t)||[]:null}async resolveDocumentLink(e,t){return await this.documentLinkManager.resolveDocumentLink(e,t)}async provideDocumentColors(e,t){return await this.documentColorManager.provideDocumentColors(e,t)}async provideFoldingRanges(e,t,i){return this.foldingRangeManager.hasProvider(e)?await this.foldingRangeManager.provideFoldingRanges(e,t,i):null}async provideColorPresentations(e,t,i){return await this.documentColorManager.provideColorPresentations(e,t,i)}async getCodeLens(e,t){return await this.codeLensManager.provideCodeLenses(e,t)}async resolveCodeLens(e,t){return e.command!=null?e:await this.codeLensManager.resolveCodeLens(e,t)}async resolveCodeAction(e,t){return await this.codeActionManager.resolveCodeAction(e,t)}async provideDocumentOnTypeEdits(e,t,i,r){return this.onTypeFormatManager.onCharacterType(e,t,i,r)}canFormatOnType(e,t){return this.onTypeFormatManager.getProvider(t,e)!=null}async prepareCallHierarchy(e,t,i){return this.callHierarchyManager.prepareCallHierarchy(e,t,i)}async provideIncomingCalls(e,t,i){return this.callHierarchyManager.provideCallHierarchyIncomingCalls(e,t,i)}async provideOutgoingCalls(e,t,i){return this.callHierarchyManager.provideCallHierarchyOutgoingCalls(e,t,i)}getLegend(e,t){return t?this.semanticTokensRangeManager.getLegend(e):this.semanticTokensManager.getLegend(e)}hasSemanticTokensEdits(e){return this.semanticTokensManager.hasSemanticTokensEdits(e)}async provideDocumentSemanticTokens(e,t){return this.semanticTokensManager.provideDocumentSemanticTokens(e,t)}async provideDocumentSemanticTokensEdits(e,t,i){return this.semanticTokensManager.provideDocumentSemanticTokensEdits(e,t,i)}async provideDocumentRangeSemanticTokens(e,t,i){return this.semanticTokensRangeManager.provideDocumentRangeSemanticTokens(e,t,i)}async provideInlayHints(e,t,i){return this.inlayHintManager.provideInlayHints(e,t,i)}async resolveInlayHint(e,t){return this.inlayHintManager.resolveInlayHint(e,t)}hasLinkedEditing(e){return this.linkedEditingManager.hasProvider(e)}async provideLinkedEdits(e,t,i){return this.linkedEditingManager.provideLinkedEditingRanges(e,t,i)}createDiagnosticCollection(e){return Ft.create(e)}hasProvider(e,t){switch(e){case"formatOnType":return this.onTypeFormatManager.hasProvider(t);case"rename":return this.renameManager.hasProvider(t);case"onTypeEdit":return this.onTypeFormatManager.hasProvider(t);case"documentLink":return this.documentLinkManager.hasProvider(t);case"documentColor":return this.documentColorManager.hasProvider(t);case"foldingRange":return this.foldingRangeManager.hasProvider(t);case"format":return this.formatManager.hasProvider(t)||this.formatRangeManager.hasProvider(t);case"codeAction":return this.codeActionManager.hasProvider(t);case"workspaceSymbols":return this.workspaceSymbolsManager.hasProvider();case"formatRange":return this.formatRangeManager.hasProvider(t);case"hover":return this.hoverManager.hasProvider(t);case"signature":return this.signatureManager.hasProvider(t);case"documentSymbol":return this.documentSymbolManager.hasProvider(t);case"documentHighlight":return this.documentHighlightManager.hasProvider(t);case"definition":return this.definitionManager.hasProvider(t);case"declaration":return this.declarationManager.hasProvider(t);case"typeDefinition":return this.typeDefinitionManager.hasProvider(t);case"reference":return this.referenceManager.hasProvider(t);case"implementation":return this.implementationManager.hasProvider(t);case"codeLens":return this.codeLensManager.hasProvider(t);case"selectionRange":return this.selectionRangeManager.hasProvider(t);case"callHierarchy":return this.callHierarchyManager.hasProvider(t);case"semanticTokens":return this.semanticTokensManager.hasProvider(t);case"semanticTokensRange":return this.semanticTokensRangeManager.hasProvider(t);case"linkedEditing":return this.linkedEditingManager.hasProvider(t);case"inlayHint":return this.inlayHintManager.hasProvider(t);default:throw new Error(`Invalid provider name: ${e}`)}}},A=new Pee});var _ee,J7e,SD,Ree=_(()=>{"use strict";_ee=C(H());le();z();J7e=q()("model-dialog"),SD=class{constructor(e,t){this.nvim=e;this.config=t;this.disposables=[];this._onDidClose=new _ee.Emitter;this.onDidClose=this._onDidClose.event;E.on("BufWinLeave",i=>{i==this.bufnr&&(this.dispose(),t.callback&&t.callback(-1))},null,this.disposables),E.on("FloatBtnClick",(i,r)=>{if(i==this.bufnr){this.dispose();let o=t==null?void 0:t.buttons.filter(s=>s.disabled!=!0);t.callback&&t.callback(o[r].index)}},null,this.disposables)}get lines(){return[...this.config.content.split(/\r?\n/)]}async show(e){let{nvim:t}=this,{title:i,close:r,highlights:o,buttons:s}=this.config,a=this.config.borderhighlight||e.floatBorderHighlight,l=this.config.highlight||e.floatHighlight,u={maxwidth:e.maxWidth||80};i&&(u.title=i),(r||typeof r>"u")&&(u.close=1),e.maxHeight&&(u.maxHeight=e.maxHeight),e.maxWidth&&(u.maxWidth=e.maxWidth),l&&(u.highlight=l),o&&(u.highlights=o),a&&(u.borderhighlight=[a]),s&&(u.buttons=s.filter(h=>!h.disabled).map(h=>h.text)),e.rounded&&(u.rounded=1),Array.isArray(u.buttons)&&(u.getchar=1);let c=await t.call("coc#dialog#create_dialog",[this.lines,u]);if(!c)throw new Error("Unable to open dialog window.");this.bufnr=c[1],t.command("redraw",!0)}get winid(){return this.bufnr?this.nvim.call("bufwinid",[this.bufnr]):Promise.resolve(null)}dispose(){this._onDidClose.fire(),this.bufnr=void 0,Z(this.disposables),this.disposables=[]}}});var W_,K7e,ru,Z_=_(()=>{"use strict";W_=C(H());le();z();K7e=q()("model-input"),ru=class{constructor(e,t){this.nvim=e;this.disposables=[];this.accepted=!1;this._dimension=[0,0,0,0];this._onDidFinish=new W_.Emitter;this._onDidChange=new W_.Emitter;this.onDidFinish=this._onDidFinish.event;this.onDidChange=this._onDidChange.event;this._input=t,this.disposables.push(this._onDidFinish),this.disposables.push(this._onDidChange);let i;Object.defineProperty(this,"title",{set:s=>{i=s,this._winid&&e.call("coc#dialog#change_title",[this._winid,s],!0)},get:()=>i});let r=!1;Object.defineProperty(this,"loading",{set:s=>{r=s,this._winid&&e.call("coc#dialog#change_loading",[this._winid,s],!0)},get:()=>r});let o;Object.defineProperty(this,"borderhighlight",{set:s=>{o=s,this._winid&&e.call("coc#dialog#change_border_hl",[this._winid,s],!0)},get:()=>o}),E.on("BufWinLeave",s=>{s==this._bufnr&&(this._winid=void 0,this.dispose())},null,this.disposables),E.on("PromptInsert",(s,a)=>{a==this._bufnr&&(this._input=s,this.accepted=!0,this.dispose())},null,this.disposables),E.on("TextChangedI",(s,a)=>{s==this._bufnr&&(this._input=a.line,this._onDidChange.fire(a.line))},null,this.disposables)}get dimension(){let{_dimension:e}=this;return{width:e[0],height:e[1],row:e[2],col:e[3]}}get bufnr(){return this._bufnr}get winid(){return this._winid}get value(){return this._input}async show(e,t){var r;this.title=e,this.borderhighlight=(r=t.borderhighlight)!=null?r:"CocFloating",this.loading=!1;let i=await this.nvim.call("coc#dialog#create_prompt_win",[e,this._input,t]);if(!i)throw new Error("Unable to open input window");return this._bufnr=i[0],this._winid=i[1],this._dimension=i[2],!0}dispose(){this._onDidFinish.fire(this.accepted?this._input:null),this._winid&&this.nvim.call("coc#float#close",[this._winid],!0),this._winid=void 0,this._bufnr=void 0,Z(this.disposables)}}});var J_,Ia,TD=_(()=>{"use strict";J_=process.env.VIM_NODE_RPC=="1",Ia=class{constructor(e,t,i,r,o=0){this.nvim=e;this.winid=t;this.bufnr=i;this.linecount=r;this._currIndex=o}get currIndex(){return this._currIndex}get valid(){return this.nvim.call("coc#float#valid",[this.winid]).then(e=>!!e)}close(){this.nvim.call("coc#float#close",[this.winid],!0)}refreshScrollbar(){J_||this.nvim.call("coc#float#nvim_scrollbar",[this.winid],!0)}execute(e){this.nvim.call("coc#compat#execute",[this.winid,e],!0)}async scrollForward(){let{nvim:e,bufnr:t,winid:i}=this,o=await e.createBuffer(t).length,s;if(J_)s=await e.eval(`get(popup_getpos(${i}), 'lastline', 0)`);else{let a=await e.call("getwininfo",[i]);if(!a||!a.length)return;s=a[0].botline}s>=o||s==0||(e.pauseNotification(),this.setCursor(s-1),this.execute("silent! noa setl scrolloff=0"),this.execute(`normal! ${s}Gzt`),this.refreshScrollbar(),e.command("redraw",!0),e.resumeNotification(!1,!0))}async scrollBackward(){let{nvim:e,winid:t}=this,i;if(J_)i=await e.eval(`get(popup_getpos(${t}), 'firstline', 0)`);else{let r=await e.call("getwininfo",[t]);if(!r||!r.length)return;i=r[0].topline}i!=1&&(e.pauseNotification(),this.setCursor(i-1),this.execute(`normal! ${i}Gzb`),this.refreshScrollbar(),e.command("redraw",!0),e.resumeNotification(!1,!0))}setCursor(e,t=!1){let{nvim:i,bufnr:r,winid:o,linecount:s}=this;e<0?e=0:e>s-1&&(e=s-1),this._currIndex=e,i.call("coc#dialog#set_cursor",[o,r,e+1],!0),t&&(this.refreshScrollbar(),i.command("redraw",!0))}}});function ou(n){return n?typeof n.text=="string":!1}var Lee,sTe,kD,Fee=_(()=>{"use strict";Lee=C(H());le();z();Pe();TD();sTe=q()("model-menu");kD=class{constructor(e,t,i){this.nvim=e;this.config=t;this.currIndex=0;this.contentHeight=0;this.disposables=[];this.keyMappings=new Map;this.shortcutIndexes=new Set;this._disposed=!1;this._onDidClose=new Lee.Emitter;this.onDidClose=this._onDidClose.event;this.total=t.items.length,i&&i.onCancellationRequested(()=>{var r;this.win?(r=this.win)==null||r.close():(this._onDidClose.fire(-1),this.dispose())}),this.disposables.push(this._onDidClose),this.addKeymappings()}attachEvents(){E.on("InputChar",this.onInputChar.bind(this),null,this.disposables),E.on("BufWinLeave",e=>{e==this.bufnr&&(this._onDidClose.fire(-1),this.dispose())},null,this.disposables)}addKeymappings(){let{nvim:e}=this;this.addKeys(["",""],()=>{this._onDidClose.fire(-1),this.dispose()}),this.addKeys(["\r",""],()=>{this.selectCurrent()});let t=s=>{var a;!this.win||(e.pauseNotification(),this.setCursor(s+this.contentHeight),(a=this.win)==null||a.refreshScrollbar(),e.command("redraw",!0),e.resumeNotification(!1,!0))};this.addKeys("",async()=>{var s;await((s=this.win)==null?void 0:s.scrollForward())}),this.addKeys("",async()=>{var s;await((s=this.win)==null?void 0:s.scrollBackward())}),this.addKeys(["j","","",""],()=>{let s=this.currIndex==this.total-1?0:this.currIndex+1;t(s)}),this.addKeys(["k","","",""],()=>{let s=this.currIndex==0?this.total-1:this.currIndex-1;t(s)}),this.addKeys(["g"],()=>{t(0)}),this.addKeys(["G"],()=>{t(this.total-1)});let i,r,o=s=>{this.isDisabled(s)||(this._onDidClose.fire(s),this.dispose())};this.addKeys(["0","1","2","3","4","5","6","7","8","9"],s=>{i&&clearTimeout(i);let a=parseInt(s,10);if(!(isNaN(a)||a>this.total)&&!(r==null&&a==0)){if(r){let l=r*10+a;r=void 0,o(l-1);return}if(this.total<10||a*10>this.total){o(a-1);return}i=setTimeout(async()=>{o(a-1)},200),r=a}}),this.config.shortcuts&&this.addShortcuts(o)}addShortcuts(e){let{items:t}=this.config;t.map(r=>ou(r)?r.text:r).forEach((r,o)=>{if(r.length){let s=r[0];j0(s.charCodeAt(0))&&!this.keyMappings.has(s)&&(this.shortcutIndexes.add(o),this.addKeys(s,()=>{e(o)}))}})}isDisabled(e){let{items:t}=this.config,i=t[e];return!!(ou(i)&&i.disabled)}async show(e={}){let{nvim:t,shortcutIndexes:i}=this,{title:r,items:o,borderhighlight:s,position:a,content:l}=this.config,u={};r&&(u.title=r),a==="center"&&(u.relative="editor"),e.maxHeight&&(u.maxHeight=e.maxHeight),e.maxWidth&&(u.maxWidth=e.maxWidth),e.floatHighlight&&(u.highlight=e.floatHighlight),s?u.borderhighlight=[s]:e.floatBorderHighlight&&(u.borderhighlight=[e.floatBorderHighlight]),e.rounded&&(u.rounded=1),typeof l=="string"&&(u.content=l);let c=[],h=o.map((g,f)=>{let p=ou(g)?g.text:g,b=f<99?`${f+1}. `:"";return i.has(f)&&c.push({lnum:f,hlGroup:e.shortcutHighlight||"MoreMsg",colStart:Q(b),colEnd:Q(b)+1}),b+p.trim()});h.forEach((g,f)=>{let p=o[f];ou(p)&&p.disabled&&c.push({hlGroup:"CocDisabled",lnum:f,colStart:0,colEnd:Q(g)})}),c.length&&(u.highlights=c),e.confirmKey&&e.confirmKey!=""&&this.addKeys(e.confirmKey,()=>{this.selectCurrent()});let d=await t.call("coc#dialog#create_menu",[h,u]);if(!d)throw new Error("Unable to create menu window");t.command("redraw",!0),!this._disposed&&(this.win=new Ia(t,d[0],d[1],h.length+d[2],d[2]),this.bufnr=d[1],this.contentHeight=d[2],this.attachEvents(),t.call("coc#prompt#start_prompt",["menu"],!0))}selectCurrent(){if(this.isDisabled(this.currIndex)){let e=this.config.items[this.currIndex];e.disabled.reason&&this.nvim.outWriteLine(`Item disabled: ${e.disabled.reason}`);return}this._onDidClose.fire(this.currIndex),this.dispose()}get buffer(){return this.bufnr?this.nvim.createBuffer(this.bufnr):void 0}dispose(){var e;this._disposed=!0,Z(this.disposables),this.shortcutIndexes.clear(),this.keyMappings.clear(),this.nvim.call("coc#prompt#stop_prompt",["menu"],!0),(e=this.win)==null||e.close(),this.bufnr=void 0,this.win=void 0}async onInputChar(e,t){if(e!="menu"||!this.win)return;let i=this.keyMappings.get(t);i?await Promise.resolve(i(t)):sTe.warn(`Ignored key press: ${t}`)}setCursor(e){!this.win||(this.currIndex=e-this.contentHeight,this.win.setCursor(e))}addKeys(e,t){if(Array.isArray(e))for(let i of e)this.keyMappings.set(i,t);else this.keyMappings.set(e,t)}}});var c9e,su,$_=_(()=>{"use strict";le();z();c9e=q()("model-notification"),su=class{constructor(e,t,i=!0){this.nvim=e;this.config=t;this.disposables=[];this._disposed=!1;i&&(E.on("BufWinLeave",r=>{r==this.bufnr&&(this.dispose(),t.callback&&t.callback(-1))},null,this.disposables),E.on("FloatBtnClick",(r,o)=>{if(r==this.bufnr){this.dispose();let s=t==null?void 0:t.buttons.filter(a=>a.disabled!=!0);t.callback&&t.callback(s[o].index)}},null,this.disposables))}get lines(){return this.config.content?this.config.content.split(/\r?\n/):[]}async show(e){let{nvim:t}=this,{buttons:i,kind:r,title:o}=this.config,s=Object.assign({},e);if(s.kind=r!=null?r:"",o&&(s.title=o),e.broder&&(s.borderhighlight=r?`CocNotification${r[0].toUpperCase()}${r.slice(1)}`:e.highlight),Array.isArray(i)){let l=i.filter(u=>!u.disabled).map(u=>u.text);l.length&&(s.actions=l)}let a=await t.call("coc#notify#create",[this.lines,s]);if(!a)throw new Error("Unable to create notification window");this._winid=a[0],this.bufnr=a[1]}get winid(){return this._winid}dispose(){if(this._disposed)return;this._disposed=!0;let{winid:e}=this;e&&(this.nvim.call("coc#notify#close",[e],!0),this.nvim.redrawVim()),this.bufnr=void 0,this._winid=void 0,Z(this.disposables)}}});var Iee,aTe,lTe,ED,jee=_(()=>{"use strict";Iee=C(H());le();z();Pe();TD();aTe=q()("model-dialog"),lTe=process.env.VIM_NODE_RPC=="1",ED=class{constructor(e,t,i){this.nvim=e;this.config=t;this.picked=new Set;this.disposables=[];this.keyMappings=new Map;this._onDidClose=new Iee.Emitter;this.onDidClose=this._onDidClose.event;for(let r=0;r{var r;(r=this.win)==null||r.close()}),this.disposables.push(this._onDidClose),this.addKeymappings()}get currIndex(){return this.win?this.win.currIndex:0}attachEvents(){E.on("InputChar",this.onInputChar.bind(this),null,this.disposables),E.on("BufWinLeave",e=>{e==this.bufnr&&(this._onDidClose.fire(void 0),this.bufnr=void 0,this.win=void 0,this.dispose())},null,this.disposables),E.on("FloatBtnClick",(e,t)=>{if(e==this.bufnr){if(t==0){let i=Array.from(this.picked);this._onDidClose.fire(i.length?i:void 0)}else this._onDidClose.fire(void 0);this.dispose()}},null,this.disposables)}addKeymappings(){let{nvim:e}=this,t=i=>{this.picked.has(i)?this.picked.delete(i):this.picked.add(i)};this.addKeys("",async()=>{if(lTe||!this.win)return;let[i,r,o]=await e.eval("[v:mouse_winid,v:mouse_lnum,v:mouse_col]");if(global.hasOwnProperty("__TEST__")){let s=await e.getVar("mouse_position");i=s[0],r=s[1],o=s[2]}e.pauseNotification(),i==this.win.winid&&(o<=3?(t(r-1),this.changeLine(r-1)):this.setCursor(r-1)),e.call("win_gotoid",[i],!0),e.call("cursor",[r,o],!0),e.call("coc#float#nvim_float_click",[],!0),e.command("redraw",!0),await e.resumeNotification()}),this.addKeys(["",""],()=>{this._onDidClose.fire(void 0),this.dispose()}),this.addKeys("",()=>{if(this.picked.size==0)this._onDidClose.fire(void 0);else{let i=Array.from(this.picked);this._onDidClose.fire(i)}this.dispose()}),this.addKeys(["j","","",""],()=>{this.win.setCursor(this.currIndex+1,!0)}),this.addKeys(["k","","",""],()=>{this.win.setCursor(this.currIndex-1,!0)}),this.addKeys(["g"],()=>{this.win.setCursor(0,!0)}),this.addKeys(["G"],()=>{this.win.setCursor(this.total-1,!0)}),this.addKeys(" ",async()=>{let i=this.currIndex;t(i),e.pauseNotification(),this.changeLine(i),this.setCursor(this.currIndex+1),e.command("redraw",!0),await e.resumeNotification()}),this.addKeys("",async()=>{var i;await((i=this.win)==null?void 0:i.scrollForward())}),this.addKeys("",async()=>{var i;await((i=this.win)==null?void 0:i.scrollBackward())})}async show(e={}){let{nvim:t}=this,{title:i,items:r}=this.config,o={close:1,cursorline:1};if(e.maxHeight&&(o.maxHeight=e.maxHeight),e.maxWidth&&(o.maxWidth=e.maxWidth),i&&(o.title=i),e.floatHighlight&&(o.highlight=e.floatHighlight),e.floatBorderHighlight&&(o.borderhighlight=[e.floatBorderHighlight]),e.pickerButtons){let u=e.pickerButtonShortcut;o.buttons=["Submit"+(u?" ":""),"Cancel"+(u?" ":"")]}e.rounded&&(o.rounded=1),e.confirmKey&&e.confirmKey!=""&&this.addKeys(e.confirmKey,()=>{this._onDidClose.fire(void 0),this.dispose()});let s=[],a=[];for(let u=0;u{"use strict";$_();PD=C(H());le();uTe=q()("model-progress"),_D=class extends su{constructor(e,t){super(e,{kind:"progress",title:t.title,buttons:t.cancellable?[{index:1,text:"Cancel"}]:void 0},!1);this.option=t;this._onDidFinish=new PD.Emitter;this.onDidFinish=this._onDidFinish.event;this.disposables.push(this._onDidFinish),E.on("BufWinLeave",i=>{i==this.bufnr&&(this.tokenSource&&this.tokenSource.cancel(),this._onDidFinish.fire(void 0),this.dispose())},null,this.disposables)}async show(e){let{task:t}=this.option,i=this.tokenSource=new PD.CancellationTokenSource;this.disposables.push(i);let r=0;this.config.buttons||!e.disabled?await super.show(e):uTe.warn('progress window disabled by "notification.disabledProgressSources"'),t({report:o=>{if(!this.winid)return;let{nvim:s}=this;o.increment&&(r+=o.increment,s.call("coc#window#set_var",[this.winid,"percent",`${r}%`],!0)),o.message&&s.call("coc#window#set_var",[this.winid,"message",o.message.replace(/\r?\n/g," ")],!0)}},i.token).then(o=>{this._disposed||(this._onDidFinish.fire(o),this.dispose())},o=>{this.nvim.echoError(o),!this._disposed&&(this._onDidFinish.fire(void 0),this.dispose())})}}});var Mee=m((k9e,X_)=>{var ja={};typeof X_>"u"?window.eastasianwidth=ja:X_.exports=ja;ja.eastAsianWidth=function(n){var e=n.charCodeAt(0),t=n.length==2?n.charCodeAt(1):0,i=e;return 55296<=e&&e<=56319&&56320<=t&&t<=57343&&(e&=1023,t&=1023,i=e<<10|t,i+=65536),i==12288||65281<=i&&i<=65376||65504<=i&&i<=65510?"F":i==8361||65377<=i&&i<=65470||65474<=i&&i<=65479||65482<=i&&i<=65487||65490<=i&&i<=65495||65498<=i&&i<=65500||65512<=i&&i<=65518?"H":4352<=i&&i<=4447||4515<=i&&i<=4519||4602<=i&&i<=4607||9001<=i&&i<=9002||11904<=i&&i<=11929||11931<=i&&i<=12019||12032<=i&&i<=12245||12272<=i&&i<=12283||12289<=i&&i<=12350||12353<=i&&i<=12438||12441<=i&&i<=12543||12549<=i&&i<=12589||12593<=i&&i<=12686||12688<=i&&i<=12730||12736<=i&&i<=12771||12784<=i&&i<=12830||12832<=i&&i<=12871||12880<=i&&i<=13054||13056<=i&&i<=19903||19968<=i&&i<=42124||42128<=i&&i<=42182||43360<=i&&i<=43388||44032<=i&&i<=55203||55216<=i&&i<=55238||55243<=i&&i<=55291||63744<=i&&i<=64255||65040<=i&&i<=65049||65072<=i&&i<=65106||65108<=i&&i<=65126||65128<=i&&i<=65131||110592<=i&&i<=110593||127488<=i&&i<=127490||127504<=i&&i<=127546||127552<=i&&i<=127560||127568<=i&&i<=127569||131072<=i&&i<=194367||177984<=i&&i<=196605||196608<=i&&i<=262141?"W":32<=i&&i<=126||162<=i&&i<=163||165<=i&&i<=166||i==172||i==175||10214<=i&&i<=10221||10629<=i&&i<=10630?"Na":i==161||i==164||167<=i&&i<=168||i==170||173<=i&&i<=174||176<=i&&i<=180||182<=i&&i<=186||188<=i&&i<=191||i==198||i==208||215<=i&&i<=216||222<=i&&i<=225||i==230||232<=i&&i<=234||236<=i&&i<=237||i==240||242<=i&&i<=243||247<=i&&i<=250||i==252||i==254||i==257||i==273||i==275||i==283||294<=i&&i<=295||i==299||305<=i&&i<=307||i==312||319<=i&&i<=322||i==324||328<=i&&i<=331||i==333||338<=i&&i<=339||358<=i&&i<=359||i==363||i==462||i==464||i==466||i==468||i==470||i==472||i==474||i==476||i==593||i==609||i==708||i==711||713<=i&&i<=715||i==717||i==720||728<=i&&i<=731||i==733||i==735||768<=i&&i<=879||913<=i&&i<=929||931<=i&&i<=937||945<=i&&i<=961||963<=i&&i<=969||i==1025||1040<=i&&i<=1103||i==1105||i==8208||8211<=i&&i<=8214||8216<=i&&i<=8217||8220<=i&&i<=8221||8224<=i&&i<=8226||8228<=i&&i<=8231||i==8240||8242<=i&&i<=8243||i==8245||i==8251||i==8254||i==8308||i==8319||8321<=i&&i<=8324||i==8364||i==8451||i==8453||i==8457||i==8467||i==8470||8481<=i&&i<=8482||i==8486||i==8491||8531<=i&&i<=8532||8539<=i&&i<=8542||8544<=i&&i<=8555||8560<=i&&i<=8569||i==8585||8592<=i&&i<=8601||8632<=i&&i<=8633||i==8658||i==8660||i==8679||i==8704||8706<=i&&i<=8707||8711<=i&&i<=8712||i==8715||i==8719||i==8721||i==8725||i==8730||8733<=i&&i<=8736||i==8739||i==8741||8743<=i&&i<=8748||i==8750||8756<=i&&i<=8759||8764<=i&&i<=8765||i==8776||i==8780||i==8786||8800<=i&&i<=8801||8804<=i&&i<=8807||8810<=i&&i<=8811||8814<=i&&i<=8815||8834<=i&&i<=8835||8838<=i&&i<=8839||i==8853||i==8857||i==8869||i==8895||i==8978||9312<=i&&i<=9449||9451<=i&&i<=9547||9552<=i&&i<=9587||9600<=i&&i<=9615||9618<=i&&i<=9621||9632<=i&&i<=9633||9635<=i&&i<=9641||9650<=i&&i<=9651||9654<=i&&i<=9655||9660<=i&&i<=9661||9664<=i&&i<=9665||9670<=i&&i<=9672||i==9675||9678<=i&&i<=9681||9698<=i&&i<=9701||i==9711||9733<=i&&i<=9734||i==9737||9742<=i&&i<=9743||9748<=i&&i<=9749||i==9756||i==9758||i==9792||i==9794||9824<=i&&i<=9825||9827<=i&&i<=9829||9831<=i&&i<=9834||9836<=i&&i<=9837||i==9839||9886<=i&&i<=9887||9918<=i&&i<=9919||9924<=i&&i<=9933||9935<=i&&i<=9953||i==9955||9960<=i&&i<=9983||i==10045||i==10071||10102<=i&&i<=10111||11093<=i&&i<=11097||12872<=i&&i<=12879||57344<=i&&i<=63743||65024<=i&&i<=65039||i==65533||127232<=i&&i<=127242||127248<=i&&i<=127277||127280<=i&&i<=127337||127344<=i&&i<=127386||917760<=i&&i<=917999||983040<=i&&i<=1048573||1048576<=i&&i<=1114109?"A":"N"};ja.characterLength=function(n){var e=this.eastAsianWidth(n);return e=="F"||e=="W"||e=="A"?2:1};function Oee(n){return n.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g)||[]}ja.length=function(n){for(var e=Oee(n),t=0,i=0;i=e-(l==2?1:0))if(r+l<=t)i+=a;else break;r+=l}return i}});var Bee=m((E9e,Nee)=>{"use strict";Nee.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g}});var qee=m((P9e,Hee)=>{var cTe=dg(),hTe=Mee(),dTe=Bee();Hee.exports=function(e,t={}){if(typeof e!="string"||e.length===0||(t=ge({ambiguousIsNarrow:!0},t),e=cTe(e),e.length===0))return 0;e=e.replace(dTe()," ");let i=t.ambiguousIsNarrow?1:2,r=0;for(let o of e){let s=o.codePointAt(0);if(s<=31||s>=127&&s<=159||s>=768&&s<=879)continue;switch(hTe.eastAsianWidth(o)){case"F":case"W":r+=2;break;case"A":r+=i;break;default:r+=1}}return r}});var Yee,RD,M9e,ap,Wee=_(()=>{"use strict";Yee=C(qee()),RD=C(H());le();z();Uf();Pe();Z_();TD();M9e=q()("model-quickpick"),ap=class{constructor(e,t){this.nvim=e;this.config=t;this.disposables=[];this._changed=!1;this._onDidFinish=new RD.Emitter;this._onDidChangeSelection=new RD.Emitter;this._onDidChangeValue=new RD.Emitter;this.onDidFinish=this._onDidFinish.event;this.onDidChangeSelection=this._onDidChangeSelection.event;this.onDidChangeValue=this._onDidChangeValue.event;var r;let i=(r=t.items)!=null?r:[];Object.defineProperty(this,"items",{set:o=>{this._changed=!0,i=o,this.filterItems("")},get:()=>i}),Object.defineProperty(this,"activeItems",{set:o=>{this._changed=!0,this.filteredItems=o,this.showFilteredItems()},get:()=>this.filteredItems}),Object.defineProperty(this,"title",{set:o=>{this.input&&(this.input.title=o)},get:()=>this.input?this.input.title:t.title}),Object.defineProperty(this,"loading",{set:o=>{this.input&&(this.input.loading=o)},get:()=>this.input?this.input.loading:!1})}get value(){var e;return this.input?this.input.value:(e=this.config.value)!=null?e:""}get currIndex(){return this.win?this.win.currIndex:0}get buffer(){return this.bufnr?this.nvim.createBuffer(this.bufnr):void 0}setCursor(e){var t;(t=this.win)==null||t.setCursor(e,!0)}attachEvents(e){E.on("BufWinLeave",t=>{t==this.bufnr&&this.dispose()},null,this.disposables),E.on("PromptKeyPress",async(t,i)=>{var r,o;t==e&&(i=="C-f"?await((r=this.win)==null?void 0:r.scrollForward()):i=="C-b"?await((o=this.win)==null?void 0:o.scrollBackward()):["C-j","C-n","down"].includes(i)?this.setCursor(this.currIndex+1):["C-k","C-p","up"].includes(i)?this.setCursor(this.currIndex-1):this.config.canSelectMany&&i=="C-@"&&this.toggePicked(this.currIndex))},null,this.disposables)}async show(e={}){let{nvim:t,items:i}=this,{title:r,canSelectMany:o,value:s}=this.config,a=[],l=[],u=[];for(let b=0;b{if(this._onDidChangeValue.fire(b),this._changed){this._changed=!1;return}this.filterItems(b)},this),c.onDidFinish(this.onFinish,this);let h=Math.max(40,Math.min(80,a.reduce((b,v)=>Math.max(b,(0,Yee.default)(v)),0)));await c.show(r!=null?r:"",{position:"center",marginTop:10,border:[1,1,0,1],list:!0,minWidth:h,maxWidth:e.maxWidth||80,rounded:!!e.rounded,highlight:e.floatHighlight,borderhighlight:e.floatBorderHighlight}),this.selectedItems=u;let d={lines:a,rounded:!!e.rounded};d.highlights=l,e.floatHighlight&&(d.highlight=e.floatHighlight),e.floatBorderHighlight&&(d.borderhighlight=e.floatBorderHighlight);let g=this.config.maxHeight||e.maxHeight;g&&(d.maxHeight=g);let f=await t.call("coc#dialog#create_list",[c.winid,c.dimension,d]);if(!f)throw new Error("Unable to open list window.");this.filteredItems=i,this.win=new Ia(t,f[0],f[1],a.length),this.win.refreshScrollbar(),this.bufnr=f[1];let p=o||u.length==0?0:i.indexOf(u[0]);this.setCursor(p),this.attachEvents(c.bufnr)}filterItems(e){let{items:t,win:i,selectedItems:r}=this;if(!i)return;let{canSelectMany:o}=this.config,s=[],a=[],l=0,u=[];for(let c of t){let h=this.toFilterText(c);if(e.length>0&&!Sh(e,h))continue;let d=r.includes(c),g=o?`[${d?"x":" "}] ${c.label}`:c.label;if(c.description){let p=Q(g);g=g+` ${c.description}`,a.push({hlGroup:"Comment",lnum:l,colStart:p,colEnd:Q(g)})}Vl(e,h).forEach(p=>{let b=Ze(h,p);a.push({hlGroup:"CocSearch",colStart:b,colEnd:b+1,lnum:l})}),u.push(c),s.push(g),l+=1}this.filteredItems=u,this.win.linecount=s.length,this.nvim.call("coc#dialog#update_list",[this.win.winid,this.win.bufnr,s,a],!0),this.setCursor(0)}showFilteredItems(){let{win:e,input:t,filteredItems:i}=this;if(!e)return;let{canSelectMany:r}=this.config,o=[],s=[],a=0,l=[];for(let u of i){let c=this.toFilterText(u),h=r?`[${u.picked?"x":" "}] ${u.label}`:u.label;if(u.picked&&l.push(u),u.description){let g=Q(h);h=h+` ${u.description}`,s.push({hlGroup:"Comment",lnum:a,colStart:g,colEnd:Q(h)})}Vl(t.value,c).forEach(g=>{let f=Ze(c,g);s.push({hlGroup:"CocSearch",colStart:f,colEnd:f+1,lnum:a})}),o.push(h),a+=1}this.selectedItems=l,this.win.linecount=o.length,this.nvim.call("coc#dialog#update_list",[this.win.winid,this.win.bufnr,o,s],!0),this.setCursor(r||l.length==0?0:i.indexOf(l[0]))}onFinish(e){if(e==null){this._onDidChangeSelection.fire([]),this._onDidFinish.fire(null);return}let t=this.getSelectedItems();this.config.canSelectMany||this._onDidChangeSelection.fire(t),this._onDidFinish.fire(t)}getSelectedItems(){let{win:e}=this,{canSelectMany:t}=this.config;if(t)return this.selectedItems;let i=this.filteredItems[e.currIndex];return i==null?[]:[i]}toggePicked(e){let{nvim:t,filteredItems:i,selectedItems:r}=this,o=i[e];if(!o)return;let s=r.indexOf(o);s!=-1?r.splice(s,1):r.push(o);let a=s==-1?"x":" ";t.pauseNotification(),this.win.execute(`normal! ^1lr${a}`),this.win.setCursor(this.win.currIndex+1),t.resumeNotification(!0,!0),this._onDidChangeSelection.fire(r)}toFilterText(e){let{label:t,description:i}=e,{canSelectMany:r}=this.config,o=`${r?" ":""}${t.replace(/\r?\n/,"")}`;return this.matchOnDescription?o+" "+(i!=null?i:""):o}dispose(){var e,t;this.bufnr=void 0,(e=this.input)==null||e.dispose(),(t=this.win)==null||t.close(),this._onDidFinish.dispose(),this._onDidChangeSelection.dispose(),Z(this.disposables)}}});var LD,Ph,FD,Zee=_(()=>{"use strict";le();LD=C(H());z();Ph="filter",FD=class{constructor(e,t){this.nvim=e;this._activated=!1;this.history=[];this.disposables=[];this._onDidUpdate=new LD.Emitter;this._onDidExit=new LD.Emitter;this._onDidKeyPress=new LD.Emitter;this.onDidKeyPress=this._onDidKeyPress.event;this.onDidUpdate=this._onDidUpdate.event;this.onDidExit=this._onDidExit.event;this.text="",E.on("InputChar",(i,r)=>{if(!(i!==Ph||!this._activated)){if(!t.includes(r)){if(r.length==1){this.text=this.text+r,this._onDidUpdate.fire(this.text);return}if(r==""||r==""){this.text=this.text.slice(0,-1),this._onDidUpdate.fire(this.text);return}if(r==""){this.text="",this._onDidUpdate.fire(this.text);return}if(r==""){let o=this.history.indexOf(this.text),s=this.history[o+1]||this.history[0];s&&(this.text=s,this._onDidUpdate.fire(this.text));return}if(r==""){let o=this.history.indexOf(this.text),s=this.history[o-1]||this.history[this.history.length-1];s&&(this.text=s,this._onDidUpdate.fire(this.text))}if(r==""||r==""){this.deactivate();return}}this._onDidKeyPress.fire(r)}},null,this.disposables)}active(){this._activated||(this._activated=!0,this.text="",this.nvim.call("coc#prompt#start_prompt",[Ph],!0))}deactivate(e){if(!this._activated)return;this.nvim.call("coc#prompt#stop_prompt",[Ph],!0),this._activated=!1;let{text:t}=this;this.text="",this._onDidExit.fire(e),t&&!this.history.includes(t)&&this.history.push(t)}get activated(){return this._activated}dispose(){this.deactivate(),this.history=[],this._onDidKeyPress.dispose(),this._onDidUpdate.dispose(),this._onDidExit.dispose(),Z(this.disposables)}}});var $ee={};xs($ee,{default:()=>au});var Hi,Jee,U_,G_,Q_,au,ID=_(()=>{"use strict";Hi=C(H());wi();le();Zo();z();Uf();io();Jt();Pe();ke();V();Zee();gD();Jee=q()("BasicTreeView"),U_="tree",G_=3e3,Q_=1,au=class{constructor(e,t){this.viewId=e;this.opts=t;this._selection=[];this._onDispose=new Hi.Emitter;this._onDidRefrash=new Hi.Emitter;this._onDidExpandElement=new Hi.Emitter;this._onDidCollapseElement=new Hi.Emitter;this._onDidChangeSelection=new Hi.Emitter;this._onDidChangeVisibility=new Hi.Emitter;this.onDidRefrash=this._onDidRefrash.event;this.onDispose=this._onDispose.event;this.onDidExpandElement=this._onDidExpandElement.event;this.onDidCollapseElement=this._onDidCollapseElement.event;this.onDidChangeSelection=this._onDidChangeSelection.event;this.onDidChangeVisibility=this._onDidChangeVisibility.event;this.retryTimers=0;this.renderedItems=[];this.nodesMap=new Map;this.mutex=new ei;this.disposables=[];this.lineState={titleCount:0,messageCount:0};this.loadConfiguration(),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),t.enableFilter&&(this.filter=new FD(this.nvim,[this.keys.selectNext,this.keys.selectPrevious,this.keys.invoke])),this.tooltipFactory=new ci(y.nvim),this.provider=t.treeDataProvider,this.leafIndent=t.disableLeafIndent!==!0,this.winfixwidth=t.winfixwidth!==!1,this.autoWidth=t.autoWidth===!0;let i;Object.defineProperty(this,"message",{set:a=>{i=a?a.replace(/\r?\n/g," "):void 0,this.updateHeadLines()},get:()=>i});let r=e.replace(/\r?\n/g," ");Object.defineProperty(this,"title",{set:a=>{r=a?a.replace(/\r?\n/g," "):void 0,this.updateHeadLines()},get:()=>r});let o;Object.defineProperty(this,"description",{set:a=>{o=a?a.replace(/\r?\n/g," "):void 0,this.updateHeadLines()},get:()=>o});let s;Object.defineProperty(this,"filterText",{set:a=>{let{titleCount:l,messageCount:u}=this.lineState,c=l+u;if(a!=null){let h=[{lnum:c,colStart:Q(a),colEnd:Q(a)+1,hlGroup:"Cursor"}];this.renderedItems=[],this.updateUI([a+" "],h,c,-1,!0),this.doFilter(a)}else s!=null&&this.updateUI([],[],c,c+1);s=a},get:()=>s}),this.provider.onDidChangeTreeData&&this.provider.onDidChangeTreeData(this.onDataChange,this,this.disposables),E.on("BufUnload",a=>{if(a!=this.bufnr)return;let l=this.winid!=null;this.winid=void 0,this.bufnr=void 0,l&&this._onDidChangeVisibility.fire({visible:!1}),this.dispose()},null,this.disposables),E.on("WinClosed",a=>{this.winid==a&&(this.winid=void 0,this._onDidChangeVisibility.fire({visible:!1}))},null,this.disposables),E.on("BufWinLeave",(a,l)=>{a==this.bufnr&&l==this.winid&&(this.winid=void 0,this._onDidChangeVisibility.fire({visible:!1}))},null,this.disposables),k.onDidTabClose(a=>{this._targetTabId===a&&this.dispose()},null,this.disposables),E.on("CursorHold",async a=>{a==this.bufnr&&await this.onHover()},null,this.disposables),E.on(["CursorMoved","BufEnter"],()=>{this.cancelResolve()},null,this.disposables),E.on("WinEnter",a=>{var d;if(a!=this.windowId||!((d=this.filter)!=null&&d.activated))return;let l=this.nvim.createBuffer(this.bufnr),u=this.startLnum-1,c=this.filterText?this.filterText.length:0,h=Hi.Range.create(u,c,u,c+1);l.highlightRanges(U_,"Cursor",[h]),this.nvim.call("coc#prompt#start_prompt",[Ph],!0),this.redraw()},null,this.disposables),E.on("WinLeave",a=>{var u;if(a!=this.windowId||!((u=this.filter)!=null&&u.activated))return;let l=this.nvim.createBuffer(this.bufnr);this.nvim.call("coc#prompt#stop_prompt",[Ph],!0),l.clearNamespace(U_,this.startLnum-1,this.startLnum)},null,this.disposables),this.disposables.push(this._onDidChangeVisibility,this._onDidChangeSelection,this._onDidCollapseElement,this._onDidExpandElement),this.filter&&(this.filter.onDidExit(a=>{this.nodesMap.clear(),this.filterText=void 0,this.itemsToFilter=void 0,a&&typeof this.provider.getParent=="function"?(this.renderedItems=[],this.reveal(a,{focus:!0})):(this.clearSelection(),this.render())}),this.filter.onDidUpdate(a=>{this.filterText=a}),this.filter.onDidKeyPress(async a=>{var c,h;let l=this.renderedItems;if(!(l!=null&&l.length))return;let u=this.selection[0];if(a==""||a==this.keys.selectPrevious){let d=l.findIndex(p=>p.node==u),g=d==-1||d==0?l.length-1:d-1,f=(c=l[g])==null?void 0:c.node;f&&this.selectItem(f,!0)}if(a==""||a==this.keys.selectNext){let d=l.findIndex(p=>p.node==u),g=d==-1||d==l.length-1?0:d+1,f=(h=l[g])==null?void 0:h.node;f&&this.selectItem(f,!0)}if(a==""||a==this.keys.invoke){if(!u)return;await this.invokeCommand(u),this.filter.deactivate(u)}}))}get windowId(){return this.winid}get targetTabnr(){return k.getTabNumber(this._targetTabId)}get targetWinId(){return this._targetWinId}get targetBufnr(){return this._targetBufnr}get startLnum(){let e=this.filterText==null?0:1;return this.lineState.messageCount+this.lineState.titleCount+e}get nvim(){return y.nvim}loadConfiguration(e){if(!e||e.affectsConfiguration("tree")){let t=y.getConfiguration("tree");this.config={openedIcon:t.get("openedIcon"," "),closedIcon:t.get("closedIcon"," ")},this.keys={close:t.get("key.close"),invoke:t.get("key.invoke"),toggle:t.get("key.toggle"),actions:t.get("key.actions"),collapseAll:t.get("key.collapseAll"),toggleSelection:t.get("key.toggleSelection"),activeFilter:t.get("key.activeFilter"),selectNext:t.get("key.selectNext"),selectPrevious:t.get("key.selectPrevious")},e&&this.render()}}async doFilter(e){let t=[],i=0,r=await this.mutex.acquire();try{if(!this.itemsToFilter){let l=[],u=async h=>{for(let d of h){l.push(d);let g=await Promise.resolve(this.provider.getChildren(d));g!=null&&g.length&&await u(g)}},c=await Promise.resolve(this.provider.getChildren());await u(c),this.itemsToFilter=l}for(let l of this.itemsToFilter){let u=await this.getTreeItem(l),c=op.is(u.label)?u.label.label:u.label;if(!e||Sh(e,c)){let h=e?Vl(e,c):[];u.collapsibleState=0,u.label={label:c,highlights:e?i4(h):[]};let{line:d,highlights:g}=this.getRenderedLine(u,i,0);t.push({level:0,node:l,line:d,index:i,score:e?Ch(e,c):0,highlights:g}),i+=1}}t.sort((l,u)=>l.score!=u.score?u.score-l.score:l.index-u.index);let o=this.startLnum,s=[],a=this.renderedItems=t.map((l,u)=>(s.push(...l.highlights.map(c=>(c.lnum=o+u,c))),delete l.index,delete l.score,delete l.highlights,l));this.updateUI(a.map(l=>l.line),s,o,-1,!0),a.length?this.selectItem(a[0].node,!0):this.clearSelection(),this.redraw(),r()}catch(o){r(),Jee.error("Error on tree filter:",o)}}async onHover(){let{nvim:e}=this,t=await e.call("line",["."]),i=this.getElementByLnum(t-1);if(!i)return;let r=this.nodesMap.get(i);if(!r)return;let o=r.item;if(!r.resolved&&(o=await this.resolveItem(i,o),!o)||!o.tooltip||!this.bufnr)return;let a={filetype:Hi.MarkupContent.is(o.tooltip)&&o.tooltip.kind==Hi.MarkupKind.Markdown?"markdown":"txt",content:Hi.MarkupContent.is(o.tooltip)?o.tooltip.value:o.tooltip};await this.tooltipFactory.show([a],{modes:["n"]})}async onClick(e){let{nvim:t}=this,[i,r]=await t.eval("[getline('.'),col('.')]"),o=et(i,0,r-1),s=i[o.length];if(!s)return;let{openedIcon:a,closedIcon:l}=this.config;/^\s*$/.test(o)&&[a,l].includes(s)?await this.toggleExpand(e):await this.invokeCommand(e)}async invokeCommand(e){let t=this.nodesMap.get(e);if(!t)return;this.selectItem(e);let i=t.item;if(!(!i.command&&(i=await this.resolveItem(e,i),!i))){if(!i.command)throw new Error("Failed to resolve command from TreeItem.");await oe.execute(i.command)}}async invokeActions(e){if(this.selectItem(e),typeof this.provider.resolveActions!="function"){await k.showWarningMessage("No actions");return}let t=this.nodesMap.get(e),i=await Promise.resolve(this.provider.resolveActions(t.item,e));if(!i||i.length==0){await k.showWarningMessage("No actions available");return}let r=i.map(s=>s.title),o=await k.showMenuPicker(r,"Choose action");o!=-1&&await Promise.resolve(i[o].handler(e))}async onDataChange(e){var i;if((i=this.filter)!=null&&i.activated){this.itemsToFilter=void 0,await this.doFilter(this.filterText);return}if(this.clearSelection(),!e){await this.render();return}let t=await this.mutex.acquire();try{let r=this.renderedItems,o=r.findIndex(s=>s.node===e);if(o!=-1&&this.bufnr){let a=r[o].level,l=0;for(let d=o;da)&&(l+=1)}let u=[],c=[],h=o+this.startLnum;await this.appendTreeNode(e,a,h,u,c),r.splice(o,l,...u),this.updateUI(u.map(d=>d.line),c,h,h+l)}t()}catch(r){let o=`Error on tree refresh: ${r}`;Jee.error(o,r),this.nvim.errWriteLine("[coc.nvim] "+o),t()}}async resolveItem(e,t){if(typeof this.provider.resolveTreeItem=="function"){let i=this.resolveTokenSource=new Hi.CancellationTokenSource,r=i.token;if(t=await Promise.resolve(this.provider.resolveTreeItem(t,e,r)),i.dispose(),this.resolveTokenSource=void 0,r.isCancellationRequested)return}return this.nodesMap.set(e,{item:t,resolved:!0}),t}get visible(){return this.bufnr?this.winid!=null:!1}get valid(){return typeof this.bufnr=="number"}get selection(){return this._selection.slice()}async checkLines(){if(!this.bufnr)return;let t=await this.nvim.createBuffer(this.bufnr).lines,{titleCount:i,messageCount:r}=this.lineState;t=t.slice(i+r);let o=this.renderedItems.map(s=>s.line);return Fe(t,o)}async toggleExpand(e){let t=this.nodesMap.get(e);if(!t)return;let i=t.item,r=this.getItemLnum(e),o=r-this.startLnum,s=this.renderedItems[o];if(!s||i.collapsibleState==0){if(typeof this.provider.getParent=="function"){let c=await Promise.resolve(this.provider.getParent(e));c&&(await this.toggleExpand(c),this.focusItem(c))}return}let a=0;if(i.collapsibleState==2){let c=s.level;for(let h=o+1;hc.line),u,r,r+a+1),this.refreshSigns(),i.collapsibleState==1?this._onDidCollapseElement.fire({element:e}):this._onDidExpandElement.fire({element:e})}toggleSelection(e){let t=this._selection.findIndex(i=>i===e);t!==-1?this.unselectItem(t):this.selectItem(e)}clearSelection(){if(!this.bufnr)return;this._selection=[],this.nvim.createBuffer(this.bufnr).unplaceSign({group:"CocTree"}),this._onDidChangeSelection.fire({selection:[]})}selectItem(e,t,i){let{nvim:r}=this;if(!this.bufnr||!y.env.sign)return;let o=this.getItemLnum(e);if(o==null)return;let s=r.createBuffer(this.bufnr),a=this._selection.includes(e);!this.opts.canSelectMany||t?this._selection=[e]:a||this._selection.push(e),r.pauseNotification(),(!this.opts.canSelectMany||t)&&s.unplaceSign({group:"CocTree"}),r.call("coc#compat#execute",[this.winid,`normal! ${o+1}G`],!0),s.placeSign({id:G_+o,lnum:o+1,name:"CocTreeSelected",group:"CocTree"}),i||this.redraw(),r.resumeNotification(!1,!0),a||this._onDidChangeSelection.fire({selection:this._selection})}unselectItem(e){let t=this._selection[e],i=this.getItemLnum(t);if(i==null||!this.bufnr||!y.env.sign)return;this._selection.splice(e,1),this.nvim.createBuffer(this.bufnr).unplaceSign({group:"CocTree",id:G_+i}),this._onDidChangeSelection.fire({selection:this._selection})}focusItem(e){if(!this.winid)return;let t=this.getItemLnum(e);t!=null&&this.nvim.call("coc#compat#execute",[this.winid,`exe ${t+1}`],!0)}getElementByLnum(e){let t=this.renderedItems[e-this.startLnum];return t?t.node:void 0}getItemLnum(e){let t=this.renderedItems.findIndex(i=>i.node===e);if(t!=-1)return this.startLnum+t}async getTreeItem(e){let t,i=!1,r=this.nodesMap.get(e);r!=null&&(t=r.item,i=r.resolved);let o=await Promise.resolve(this.provider.getTreeItem(e));if(o.id&&!t){for(let s of this.nodesMap.values())if(s.item.id===o.id){i=s.resolved,t=s.item;break}}return t&&t.collapsibleState!=0&&o.collapsibleState!=0&&(o.collapsibleState=t.collapsibleState),this.nodesMap.set(e,{item:o,resolved:i}),o}getRenderedLine(e,t,i){let{openedIcon:r,closedIcon:o}=this.config,s=[],{label:a,deprecated:l,description:u}=e,c=" ".repeat(i),h=(g,f)=>{let p=Q(c);s.push({lnum:t,hlGroup:f,colStart:p,colEnd:p+Q(g)})};switch(e.collapsibleState){case 2:{h(r,"CocTreeOpenClose"),c+=r+" ";break}case 1:{h(o,"CocTreeOpenClose"),c+=o+" ";break}default:c+=this.leafIndent?" ":""}if(e.icon){let{text:g,hlGroup:f}=e.icon;h(g,f),c+=g+" "}if(op.is(a)&&Array.isArray(a.highlights)){let g=Q(c);for(let f of a.highlights)s.push({lnum:t,hlGroup:"CocSearch",colStart:g+f[0],colEnd:g+f[1]})}let d=typeof a=="string"?a:a.label;return l&&h(d,"CocDeprecatedHighlight"),c+=d,u&&u.indexOf(` -`)==-1&&(c+=" ",h(u,"CocTreeDescription"),c+=u),{line:c,highlights:s}}async appendTreeNode(e,t,i,r,o){let s=1,a=await this.getTreeItem(e),l=this.getRenderedLine(a,i,t);if(o.push(...l.highlights),r.push({level:t,line:l.line,node:e}),a.collapsibleState==2){let u=t+1,c=await Promise.resolve(this.provider.getChildren(e))||[];for(let h of c){let d=await this.appendTreeNode(h,u,i+s,r,o);s=s+d}}return s}updateUI(e,t,i=0,r=-1,o=!1){if(!this.bufnr)return;let{nvim:s,winid:a}=this,l=s.createBuffer(this.bufnr);if(s.pauseNotification(),l.setOption("modifiable",!0,!0),l.setLines(e,{start:i,end:r,strictIndexing:!1},!0),this.autoWidth&&this.nvim.call("coc#window#adjust_width",[a],!0),t.length){let u=r==-1?-1:i+e.length;s.call("coc#highlight#update_highlights",[this.bufnr,U_,t,i,u],!0)}l.setOption("modifiable",!1,!0),o||this.redraw(),s.resumeNotification(!1,!0)}async reveal(e,t={}){var l;if((l=this.filter)!=null&&l.activated)return;let i=this.getItemLnum(e)!=null,{select:r,focus:o,expand:s}=t,a=e;if(typeof this.provider.getParent!="function")throw new Error("missing getParent function from provider for reveal.");if(!i)for(;a;){let u=await Promise.resolve(this.provider.getParent(a));if(u){let c=await this.getTreeItem(u);c.collapsibleState=2,a=u}else break}if(s){let u=await this.getTreeItem(e);if(u.collapsibleState==0)return;if(u.collapsibleState=2,typeof s=="number"&&s>1){let c=Math.min(s,2),h=await Promise.resolve(this.provider.getChildren(e));for(;(h==null?void 0:h.length)>0;){let d=[];for(let g of h){let f=await this.getTreeItem(g);if(f.collapsibleState!=0&&(f.collapsibleState=2,c>1)){let p=await Promise.resolve(this.provider.getChildren(g));d.push(...p)}}h=d,c=c-1}}}(!i||s)&&await this.render(),r!==!1&&this.selectItem(e),o&&this.focusItem(e)}updateHeadLines(e=!1){let{titleCount:t,messageCount:i}=this.lineState,r=e?-1:t+i,o=[],s=[];try{if(this.message&&(s.push({hlGroup:"MoreMsg",colStart:0,colEnd:Q(this.message),lnum:0}),o.push(this.message),o.push("")),this.title){if(s.push({hlGroup:"CocTreeTitle",colStart:0,colEnd:Q(this.title),lnum:o.length}),this.description){let a=Q(this.title)+1;s.push({hlGroup:"Comment",colStart:a,colEnd:a+Q(this.description),lnum:o.length})}o.push(this.title+(this.description?" "+this.description:""))}this.lineState.messageCount=this.message?2:0,this.lineState.titleCount=this.title?1:0,this.updateUI(o,s,0,r),e||this.refreshSigns()}catch(a){this.nvim.echoError(a)}}refreshSigns(){let{selection:e,nvim:t,bufnr:i}=this;if(!e.length||!i||!y.env.sign)return;let r=t.createBuffer(i);t.pauseNotification(),r.unplaceSign({group:"CocTree"});for(let o of e){let s=this.getItemLnum(o);s!=null&&r.placeSign({id:G_+s,lnum:s+1,name:"CocTreeSelected",group:"CocTree"})}t.resumeNotification(!1,!0)}async render(){if(!this.bufnr)return;let e=await this.mutex.acquire();try{let t=[],i=[],{startLnum:r}=this,o=await Promise.resolve(this.provider.getChildren()),s=0,a=r,l=[];if(!(o!=null&&o.length))this.message="No results";else{this.message=="No results"&&(this.message="");for(let c of o)a+=await this.appendTreeNode(c,s,a,l,i)}t.push(...l.map(c=>c.line)),this.renderedItems=l;let u=this.startLnum-r;u&&i.forEach(c=>c.lnum=c.lnum+u),this.updateUI(t,i,this.startLnum,-1),this._onDidRefrash.fire(),this.retryTimers=0,e()}catch(t){this.renderedItems=[],this.nodesMap.clear(),this.lineState={titleCount:0,messageCount:1},e();let i=`${t}`.replace(/\r?\n/g," ");if(this.updateUI([i],[{hlGroup:"WarningMsg",colStart:0,colEnd:Q(i),lnum:0}]),this.retryTimers==5)return;this.timer=setTimeout(()=>{this.retryTimers=this.retryTimers+1,this.render()},500)}}async show(e="belowright 30vs"){if(this._creating)return!1;this._creating=!0;let{nvim:t}=this,i=this.winid,[r,o,s,a]=await t.eval(`[bufnr("%"),win_getid(),tabpagenr(),bufloaded(${this.bufnr||-1})]`);this._targetBufnr=r,this._targetWinId=o,this._targetTabId=k.getTabId(s),a||(this.bufnr=void 0);let l=await t.call("coc#window#find",["cocViewId",this.viewId]);if(this.bufnr&&l!==-1&&await t.call("winbufnr",[l])==this.bufnr){this._creating=!1;return}if(t.pauseNotification(),this.bufnr)l!=-1?(t.call("win_gotoid",[l],!0),t.command(`b ${this.bufnr}`,!0)):t.command(`silent keepalt ${e} ${this.bufname}`,!0);else{let h=Q_;Q_=Q_+1,l!=-1?(t.call("win_gotoid",[l],!0),t.command(`silent edit +setl\\ buftype=nofile CocTree${h}`,!0)):t.command(`silent keepalt ${e} +setl\\ buftype=nofile CocTree${h}`,!0)}t.command(`setl bufhidden=${this.opts.bufhidden||"wipe"} nolist nonumber norelativenumber foldcolumn=0`,!0),t.command(`setl signcolumn=${this.opts.canSelectMany?"yes":"no"}${this.winfixwidth?" winfixwidth":""}`,!0),t.command("setl nocursorline nobuflisted wrap undolevels=-1 filetype=coctree nomodifiable noswapfile",!0),t.command(`let w:cocViewId = "${this.viewId.replace(/"/g,'\\"')}"`,!0),t.call("bufname",["%"],!0),t.call("bufnr",["%"],!0),t.call("win_getid",[],!0);let u=await t.resumeNotification();this.bufnr||this.registerKeymaps();let c=u[0];return this.bufname=c[c.length-3],this.bufnr=c[c.length-2],this.winid=c[c.length-1],i||this._onDidChangeVisibility.fire({visible:!0}),i&&i!==this.winid&&t.call("coc#window#close",[i],!0),this._creating=!1,this.updateHeadLines(!0),this.render(),!0}registerLocalKeymap(e,t,i,r=!1){this.disposables.push(y.registerLocalKeymap(e,t,async()=>{let o=await this.nvim.call("line",["."]),s=this.getElementByLnum(o-1);await Promise.resolve(i(s))},r))}registerKeymaps(){let{toggleSelection:e,actions:t,close:i,invoke:r,toggle:o,collapseAll:s,activeFilter:a}=this.keys,{nvim:l}=this,u=(c,h,d)=>{this.registerLocalKeymap(c,h,async g=>{g&&!this.nodesMap.has(g)||await Promise.resolve(d(g))},!0)};this.disposables.push(y.registerLocalKeymap("n","",()=>{l.call("win_gotoid",[this._targetWinId],!0)},!0)),u("n","",async c=>{c&&await this.onClick(c)}),this.filter&&a&&u("n",a,async()=>{this.nvim.command(`exe ${this.startLnum}`,!0),this.filter.active(),this.filterText=""}),e&&u("n",e,async c=>{c&&this.toggleSelection(c)}),r&&u("n",r,async c=>{c&&await this.invokeCommand(c)}),t&&u("n",t,async c=>{c&&await this.invokeActions(c)}),o&&u("n",o,async c=>{c&&await this.toggleExpand(c)}),s&&u("n",s,async()=>{for(let c of this.nodesMap.values()){let h=c.item;h.collapsibleState==2&&(h.collapsibleState=1)}await this.render()}),i&&u("n",i,async()=>{this.hide()})}hide(){let{winid:e}=this;!e||(this.nvim.call("coc#window#close",[e],!0),this.redraw(),this.winid=void 0,this._onDidChangeVisibility.fire({visible:!1}))}redraw(){var e;(y.isVim||((e=this.filter)==null?void 0:e.activated))&&this.nvim.command("redraw",!0)}cancelResolve(){this.resolveTokenSource&&(this.resolveTokenSource.cancel(),this.resolveTokenSource=void 0)}dispose(){var t;if(!this.provider)return;this.timer&&clearTimeout(this.timer),this.cancelResolve();let{bufnr:e}=this;this.winid&&this._onDidChangeVisibility.fire({visible:!1}),e&&this.nvim.command(`silent! bwipeout! ${e}`,!0),this.winid=void 0,this.bufnr=void 0,(t=this.filter)==null||t.dispose(),this._selection=[],this.itemsToFilter=[],this.tooltipFactory.dispose(),this.renderedItems=[],this.nodesMap.clear(),this.provider=void 0,this._onDispose.fire(),this._onDispose.dispose(),Z(this.disposables)}}});function Xee(){return fTe++}function K_(n){return[n.hlGroup,n.lnum,n.colStart,n.colEnd,n.combine?1:0,n.start_incl?1:0,n.end_incl?1:0]}function mTe(n,e){let t=[n.hlGroup,n.lnum,n.colStart,n.colEnd];return Fe(t,e.slice(0,4))}var z_,_h,jD,iet,gTe,fTe,pTe,Uee,k,ke=_(()=>{"use strict";z_=C(require("fs")),_h=C(require("path")),jD=C(H());we();wb();$2();Tb();le();Ce();Ree();oa();Z_();Fee();$_();jee();Aee();Wee();Xk();Fr();z();Je();io();Jt();ac();V();iet=q()("window"),gTe=_h.default.dirname(__dirname),fTe=3e3,pTe=["formatOnType","rename","onTypeEdit","documentLink","documentColor","foldingRange","format","codeAction","formatRange","hover","signature","documentSymbol","documentHighlight","definition","declaration","typeDefinition","reference","implementation","codeLens","selectionRange","callHierarchy","semanticTokens","semanticTokensRange","linkedEditing"];Uee=class{constructor(){this.mutex=new ei;this.tabIds=[];this.terminalManager=new xb;this._onDidTabClose=new jD.Emitter;this.onDidTabClose=this._onDidTabClose.event}init(e){for(let t=1;t<=e.tabCount;t++)this.tabIds.push(Xee());E.on("TabNew",t=>{this.tabIds.splice(t-1,0,Xee())}),E.on("TabClosed",t=>{let i=this.tabIds[t-1];this.tabIds.splice(t-1,1),i&&this._onDidTabClose.fire(i)})}getTabNumber(e){if(!!this.tabIds.includes(e))return this.tabIds.indexOf(e)+1}getTabId(e){return this.tabIds[e-1]}get nvim(){return y.nvim}dispose(){var e;this.terminalManager.dispose(),(e=this.statusLine)==null||e.dispose()}get activeTextEditor(){return y.editors.activeTextEditor}get visibleTextEditors(){return y.editors.visibleTextEditors}get onDidChangeActiveTextEditor(){return y.editors.onDidChangeActiveTextEditor}get onDidChangeVisibleTextEditors(){return y.editors.onDidChangeVisibleTextEditors}get terminals(){return this.terminalManager.terminals}get onDidOpenTerminal(){return this.terminalManager.onDidOpenTerminal}get onDidCloseTerminal(){return this.terminalManager.onDidCloseTerminal}async createTerminal(e){return await this.terminalManager.createTerminal(this.nvim,e)}showMessage(e,t="more"){let{messageLevel:i}=this,r="Error",o=2;switch(t){case"more":o=0,r="MoreMsg";break;case"warning":o=1,r="WarningMsg";break}o>=i&&Q2(this.nvim,e,r)}async runTerminalCommand(e,t,i=!1){return t=t||y.cwd,await this.nvim.callAsync("coc#ui#run_terminal",{cmd:e,cwd:t,keepfocus:i?1:0})}async openTerminal(e,t={}){return await this.nvim.call("coc#ui#open_terminal",ge({cmd:e},t))}async showQuickpick(e,t="Choose by number"){return await this.showMenuPicker(e,{title:t,position:"center"})}async showQuickPick(e,t,i=jD.CancellationToken.None){this.checkDialog("showQuickPick"),t=t||{};let r=await Promise.resolve(e),o=r.some(s=>typeof s=="string");if(!i.isCancellationRequested)return await this.mutex.use(()=>new Promise((s,a)=>{var u;if(i.isCancellationRequested)return s(void 0);let l=new ap(this.nvim,{items:r.map(c=>typeof c=="string"?{label:c}:c),title:(u=t.title)!=null?u:"",canSelectMany:t.canPickMany});l.matchOnDescription=t.matchOnDescription,l.onDidFinish(c=>{if(c==null)return s(void 0);let h=o?c.map(d=>d.label):c;if(t.canPickMany)return s(h);s(h[0])}),l.show(this.dialogPreference).catch(a)}))}async createQuickPick(e){return this.checkDialog("createQuickPick"),await this.mutex.use(async()=>{let t=new ap(this.nvim,e);return await t.show(this.dialogPreference),t})}async showMenuPicker(e,t,i){return y.env.dialog?await this.mutex.use(async()=>{if(i&&i.isCancellationRequested)return-1;t=t||{},typeof t=="string"&&(t={title:t});let r=new kD(this.nvim,ge({items:e},t),i),o=new Promise(s=>{r.onDidClose(a=>{s(a)})});return await r.show(this.dialogPreference),await o}):await this.mutex.use(async()=>{var c,h;let o=(typeof t=="string"?t:(h=t.title)!=null?h:((c=t.content)!=null?c:"")+"Choose by number")+":",s=[],a=1;for(let d of e)ou(d)&&d.disabled||(s.push(`${a}. ${ou(d)?d.text:d}`),a++);let l=await this.nvim.callAsync("coc#ui#quickpick",[o,s.map(d=>d.trim())]),u=parseInt(l,10);return isNaN(u)||u<=0||u>e.length?-1:u-1})}async openLocalConfig(){let e=await this.nvim.call("expand",["%:p"]),t=await this.nvim.eval("&filetype");if(!e||!_h.default.isAbsolute(e))throw new Error("current buffer doesn't have valid file path.");let i=y.getWorkspaceFolder(O.file(e).toString());if(!i){let l=y.getConfiguration("coc.preferences").get("rootPatterns",[]);throw y.getConfiguration("workspace").get("ignoredFiletypes",[]).includes(t)?new Error("Can't resolve workspace folder for current file, current filetype exclude for workspace folder resolve."):new Error(`Can't resolve workspace folder for current file, consider create one of ${l.join(", ")} in your project root.`)}let r=O.parse(i.uri).fsPath,o=_h.default.join(r,".vim");if(!z_.default.existsSync(o)){if(!await this.showPrompt(`Would you like to create folder'${r}/.vim'?`))return;z_.default.mkdirSync(o)}let s=_h.default.join(o,Er);await this.nvim.call("coc#util#open_file",["edit",s])}async showPrompt(e){return await this.mutex.use(()=>Sb(this.nvim,e))}async showDialog(e){return this.checkDialog("showDialog"),await this.mutex.use(async()=>{let t=new SD(this.nvim,e);return await t.show(this.dialogPreference),t})}async requestInput(e,t,i){let{nvim:r}=this,o=y.getConfiguration("coc.preferences");return y.env.dialog&&o.get("promptInput",!0)&&!Xi?await this.mutex.use(async()=>{let s=new ru(r,t!=null?t:"");return await s.show(e,Object.assign(this.inputPreference,i!=null?i:{})),await new Promise(a=>{s.onDidFinish(l=>{a(l)})})}):await this.mutex.use(async()=>{let s=await y.callAsync("input",[e+": ",t||""]);return r.command("normal! :",!0),s})}async createInputBox(e,t,i){this.checkDialog("createInputBox");let r=new ru(this.nvim,t!=null?t:"");return await r.show(e,Object.assign(this.inputPreference,i)),r}createStatusBarItem(e=0,t={}){if(!y.env){let i=()=>{};return{text:"",show:i,dispose:i,hide:i,priority:0,isProgress:!1}}return this.statusLine||(this.statusLine=new dv(this.nvim)),this.statusLine.createStatusBarItem(e,t.progress||!1)}createOutputChannel(e){return $o.create(e,this.nvim)}showOutputChannel(e,t){let r=y.getConfiguration("workspace").get("openOutputCommand","vs");$o.show(e,r,t)}async echoLines(e,t=!1){let{nvim:i}=this,r=y.env.cmdheight;e.length>r&&t&&(e=e.slice(0,r));let o=y.env.columns-12;if(e=e.map(s=>(s=s.replace(/\n/g," "),t&&(s=s.slice(0,o)),s)),t&&e.length==r){let s=e[e.length-1];e[r-1]=`${s.length==o?s.slice(0,-4):s} ...`}await i.call("coc#ui#echo_lines",[e])}getCursorPosition(){return Cb(this.nvim)}async moveTo(e){await X2(this.nvim,e,y.env.isVim)}getSelectedRange(e){return K2(this.nvim,e)}async selectRange(e){await z2(this.nvim,e,this.nvim.isVim)}getOffset(){return U2(this.nvim)}getCursorScreenPosition(){return G2(this.nvim)}async showPickerDialog(e,t,i){return this.checkDialog("showPickerDialog"),await this.mutex.use(async()=>{if(i&&i.isCancellationRequested)return;let r=typeof e[0]=="string",o=new ED(this.nvim,{title:t,items:r?e.map(u=>({label:u})):e},i),s=new Promise(u=>{o.onDidClose(c=>{u(c)})});await o.show(this.dialogPreference);let a=await s;return a==null?void 0:e.filter((u,c)=>a.includes(c))})}async showInformationMessage(e,...t){let i=Error().stack;return await this._showMessage("Info",e,t,i)}async showWarningMessage(e,...t){let i=Error().stack;return await this._showMessage("Warning",e,t,i)}async showErrorMessage(e,...t){let i=Error().stack;return await this._showMessage("Error",e,t,i)}async showMessagePicker(e,t,i,r){let o=r.map(a=>typeof a=="string"?a:a.title),s=await this.showMenuPicker(o,{content:t,title:e.replace(/\r?\n/," "),borderhighlight:i});return r[s]}async _showMessage(e,t,i,r){if(!this.enableMessageDialog)return await this.showConfirm(t,i,e);if(this.preferMenuPicker&&i.length>0)return await this.showMessagePicker("Choose action",t,`Coc${e}Float`,i);let o=typeof i[0]=="string"?i:i.map(a=>a.title),s=await this.createNotification(e.toLowerCase(),t,o,r);return s==-1?void 0:i[s]}async showNotification(e){this.checkDialog("showNotification");let t=Error().stack;await new su(this.nvim,e).show(this.getNotificationPreference(t))}async showConfirm(e,t,i){if(!t||t.length==0){let a=i=="Info"?"more":i=="Error"?"error":"warning";this.showMessage(e,a);return}let o=(typeof t[0]=="string"?t.slice():t.map(a=>a.title)).map((a,l)=>`${l+1}${a}`),s=await this.nvim.callAsync("coc#util#with_callback",["confirm",[e,o.join(` -`),0,i]]);return t[s-1]}async withProgress(e,t){this.checkDialog("withProgress");let i=Error().stack,r=new _D(this.nvim,{task:t,title:e.title,cancellable:e.cancellable}),s=y.getConfiguration("notification").get("minProgressWidth",30),a=new Promise(l=>{r.onDidFinish(l)});return await r.show(Object.assign(this.getNotificationPreference(i,e.source),{minWidth:s})),await a}createTreeView(e,t){let i=(ID(),Ha($ee)).default;return new i(e,t)}async diffHighlights(e,t,i,r,o){let s=[e,t];Array.isArray(r)&&s.push(r[0],r[1]);let a=await this.nvim.call("coc#highlight#get_highlights",s);if(!a||(o==null?void 0:o.isCancellationRequested))return null;i.sort((b,v)=>b.lnum-v.lnum);let l=[],u=y.has("nvim-0.5.1")||y.isVim,c=[],h=[],d=0,g=i.length-1,f=0,p=new Map;if(a.forEach(b=>{f=Math.max(f,b[1]);let v=p.get(b[1]);v?v.push(b):p.set(b[1],[b])}),a.length>0){let b=Array.isArray(r)?r[0]:0;for(let v=b;v<=f;v++){let w=p.get(v)||[],D=[];for(let S=d;S<=g;S++){let F=i[S];if(F.lnum==v)d=S+1,D.push(F);else{d=S;break}}D.length==0?w.length&&(u?c.push(...w.map(S=>S[4])):l.push(v)):w.length==0?h.push(...D.map(S=>K_(S))):(D.length!=w.length||!D.every((S,F)=>mTe(S,w[F])))&&(u?c.push(...w.map(S=>S[4])):l.push(v),h.push(...D.map(S=>K_(S))))}}for(let b=d;b<=g;b++)h.push(K_(i[b]));return{remove:l,add:h,removeMarkers:c}}async applyDiffHighlights(e,t,i,r,o=!1){let{nvim:s}=this,{remove:a,add:l,removeMarkers:u}=r;a.length===0&&l.length===0&&u.length===0||(s.pauseNotification(),u.length&&s.call("coc#highlight#del_markers",[e,t,u],!0),a.length&&s.call("coc#highlight#clear",[e,t,a],!0),l.length&&s.call("coc#highlight#set",[e,t,l,i],!0),o?s.resumeNotification(!0,!0):await s.resumeNotification(!0))}async bufferCheck(){let e=await y.document,t;if(e.attached||(e.enabled?e.buftype!==""&&e.buftype!=="acwrite"?t=`Document not attached with buftype '${e.buftype}'`:t="Document not attached, file size exceed coc.preferences.maxFileSize":t="Document not attached, b:coc_enabled is 0"),t){await this.showDialog({title:"Buffer check result",content:t,highlight:"WarningMsg"});return}let i=new Ri;i.addLine("Provider state","Title"),i.addLine("");for(let r of pTe){let o=A.hasProvider(r,e.textDocument);i.addTexts([{text:"-",hlGroup:"Comment"},{text:" "},o?{text:"\u2713",hlGroup:"CocListFgGreen"}:{text:"\u2717",hlGroup:"CocListFgRed"},{text:" "},{text:r,hlGroup:o?"Normal":"CocFadeOut"}])}await this.showDialog({title:"Buffer check result",content:i.content,highlights:i.highlights})}createNotification(e,t,i,r){return new Promise((o,s)=>{let a={kind:e,content:t,buttons:i.map((u,c)=>({text:u,index:c})),callback:u=>{o(u)}};new su(this.nvim,a).show(this.getNotificationPreference(r)).catch(s)})}parseSource(e,t=2){let i=e.split(/\r?\n/).slice(t)[0];if(!i)return;i=i.replace(/^\s*at\s*/,"");let r;if(i.endsWith(")")){let a=i.match(/(\((.*?):\d+:\d+\))$/);a&&(r=a[2])}else{let a=i.match(/(.*?):\d+:\d+$/);a&&(r=a[1])}if(!r)return;let o=(bo(),Ha(aee)).default.getExtensionsInfo(),s=o.find(a=>ii(a.filepath,r));if(s)return s.name.startsWith("single")?_h.default.basename(s.filepath):s.name;if(s=o.find(a=>Ae(a.directory,r)),s)return s.name;if(Ae(gTe,r))return"coc.nvim"}get dialogPreference(){let e=y.getConfiguration("dialog");return{rounded:e.get("rounded",!0),maxWidth:e.get("maxWidth"),maxHeight:e.get("maxHeight"),floatHighlight:e.get("floatHighlight"),floatBorderHighlight:e.get("floatBorderHighlight"),pickerButtons:e.get("pickerButtons"),pickerButtonShortcut:e.get("pickerButtonShortcut"),confirmKey:e.get("confirmKey"),shortcutHighlight:e.get("shortcutHighlight")}}get inputPreference(){let e=y.getConfiguration("dialog");return{rounded:e.get("rounded",!0),maxWidth:e.get("maxWidth"),highlight:e.get("floatHighlight"),borderhighlight:e.get("floatBorderHighlight")}}getNotificationPreference(e,t){t||(t=this.parseSource(e));let i=y.getConfiguration("notification"),r=i.get("disabledProgressSources",[]),o=Array.isArray(r)&&(r.includes("*")||r.includes(t));return{broder:i.get("border",!0),focusable:i.get("focusable",!0),marginRight:i.get("marginRight",10),timeout:i.get("timeout",10),maxWidth:i.get("maxWidth"),maxHeight:i.get("maxHeight"),highlight:i.get("highlightGroup"),winblend:i.get("winblend"),disabled:o,source:t}}checkDialog(e){if(!y.env.dialog)throw new Error(`API window.${e} requires vim >= 8.2.0750 or neovim >= 0.4.0, please upgrade your vim`)}get enableMessageDialog(){return y.env.dialog?y.getConfiguration("coc.preferences").get("enableMessageDialog",!1):!1}get preferMenuPicker(){return y.env.dialog?y.getConfiguration("notification").get("preferMenuPicker",!1):!1}get messageLevel(){switch(y.getConfiguration("coc.preferences").get("messageLevel","more")){case"error":return 2;case"warning":return 1;default:return 0}}},k=new Uee});function Rh(n){switch(n){case kt.DiagnosticSeverity.Warning:return"Warning";case kt.DiagnosticSeverity.Information:return"Information";case kt.DiagnosticSeverity.Hint:return"Hint";default:return"Error"}}function Gee(n){switch(n){case kt.DiagnosticSeverity.Warning:return"W";case kt.DiagnosticSeverity.Information:return"I";case kt.DiagnosticSeverity.Hint:return"I";default:return"E"}}function lu(n){if(n!=null)switch(n){case"hint":return kt.DiagnosticSeverity.Hint;case"information":return kt.DiagnosticSeverity.Information;case"warning":return kt.DiagnosticSeverity.Warning;case"error":return kt.DiagnosticSeverity.Error;default:return kt.DiagnosticSeverity.Hint}}function V_(n){switch(n){case kt.DiagnosticSeverity.Error:return"CocError";case kt.DiagnosticSeverity.Warning:return"CocWarning";case kt.DiagnosticSeverity.Information:return"CocInfo";case kt.DiagnosticSeverity.Hint:return"CocHint";default:return"CocError"}}function Qee(n,e,t){var l,u;let{start:i,end:r}=e.range,o=e.source||"coc.nvim",s=e.message.split(` -`)[0],a=Rh(e.severity).slice(0,1).toUpperCase();return{bufnr:n,lnum:i.line+1,end_lnum:r.line+1,col:Array.isArray(t)?Ze((l=t[i.line])!=null?l:"",i.character)+1:i.character+1,end_col:Array.isArray(t)?Ze((u=t[r.line])!=null?u:"",r.character)+1:r.character+1,text:`[${o}${e.code?" "+e.code:""}] ${s} [${a}]`,type:a}}function AD(n,e){if((n.severity||1)!=(e.severity||1))return(n.severity||1)-(e.severity||1);let t=De(n.range.start,e.range.start);return t!=0?t:n.source>e.source?1:-1}function Kee(n){let e=n.tags||[];if(e.includes(kt.DiagnosticTag.Deprecated))return"CocDeprecatedHighlight";if(e.includes(kt.DiagnosticTag.Unnecessary))return"CocUnusedHighlight";switch(n.severity){case kt.DiagnosticSeverity.Warning:return"CocWarningHighlight";case kt.DiagnosticSeverity.Information:return"CocInfoHighlight";case kt.DiagnosticSeverity.Hint:return"CocHintHighlight";default:return"CocErrorHighlight"}}function zee(n,e){let t=[],{range:i}=e;for(let r of n){let o=r.range;if(!Sc(i,o)){if(De(o.start,i.end)>0){let s=$b(o.start,e),a=$b(o.end,e);s.line>=0&&s.character>=0&&a.line>=0&&a.character>=0&&(r.range=kt.Range.create(s,a))}t.push(r)}}return t}var kt,eR=_(()=>{"use strict";kt=C(H());yt();Pe();jr()});var rte,Lh,yet,Vee,ete,tte,ite,nte,tR,ote=_(()=>{"use strict";rte=C(Ei()),Lh=C(H());le();yt();V();eR();yet=q()("diagnostic-buffer"),Vee="CocDiagnostic",ete="diagnostic",tte=["CocErrorHighlight","CocWarningHighlight","CocInfoHighlight","CocHintHighlight","CocDeprecatedHighlight","CocUnusedHighlight"],ite=global.__TEST__?10:500,nte=global.__TEST__?"MockAleResults":"ale#other_source#ShowResults",tR=class{constructor(e,t,i,r){this.nvim=e;this.doc=t;this.config=i;this.onRefresh=r;this.diagnosticsMap=new Map;this._disposed=!1;this._dirty=!1;this._changeTs=0;this.refreshHighlights=(0,rte.debounce)(this._refresh.bind(this),ite)}get dirty(){return this._dirty}get bufnr(){return this.doc.bufnr}get uri(){return this.doc.uri}onChange(e){let t=e.contentChanges;if(t.length>0){this._changeTs=Date.now();let i=Lh.TextEdit.replace(t[0].range,t[0].text);for(let[r,o]of this.diagnosticsMap.entries())if(o.length){let s=zee(o,i);this.diagnosticsMap.set(r,s)}}this.refreshHighlights()}onTextChange(){this._dirty=!0,this.refreshHighlights.clear()}get displayByAle(){return this.config.displayByAle}clearHighlight(e){this.buffer.clearNamespace(ete+e)}clearSigns(e){this.buffer.unplaceSign({group:Vee+e})}get diagnostics(){let e=[];for(let t of this.diagnosticsMap.values())e.push(...t);return e}get buffer(){return this.nvim.createBuffer(this.bufnr)}refreshAle(e,t){let i=t.map(r=>{let o=r.range;return{text:r.message,code:r.code,lnum:o.start.line+1,col:o.start.character+1,end_lnum:o.end.line+1,end_col:o.end.character,type:Gee(r.severity)}});this.nvim.call(nte,[this.bufnr,"coc"+e,i],!0)}async update(e,t){let{diagnosticsMap:i}=this,r=i.get(e)||[];if(!this._dirty&&t.length==0&&r.length==0)return;if(i.set(e,t),this._dirty||Date.now()-this._changeTs{this.diagnosticsMap.delete(s)}),this.onRefresh(this.diagnostics)}}updateLocationList(e,t){if(!this.config.locationlistUpdate||e==-1||t!=="Diagnostics of coc")return;let i=this.toLocationListItems(this.diagnostics);this.nvim.call("setloclist",[e,[],"r",{title:"Diagnostics of coc",items:i}],!0)}toLocationListItems(e){let{locationlistLevel:t}=this.config,i=[],r=this.doc.textDocument.lines;e.sort(AD);for(let o of e)t&&o.severity&&o.severity>t||i.push(Qee(this.bufnr,o,r));return i}addSigns(e,t){let{enableSign:i,signLevel:r}=this.config;if(!i)return;let o=Vee+e,s=[],a=new Map;for(let l of t){let{range:u,severity:c}=l;if(!c||r&&c>r)continue;let h=u.start.line,d=a.get(h)||[];if(d.includes(c))continue;d.push(c),a.set(h,d);let g=this.config.signPriority+4-c;s.push({name:V_(c),lnum:h+1,priority:g})}this.nvim.call("coc#ui#update_signs",[this.bufnr,o,s],!0)}setDiagnosticInfo(){let e=[0,0,0,0],t={error:0,warning:0,information:0,hint:0,lnums:e};for(let r of this.diagnosticsMap.values())for(let o of r){let s=o.range.start.line+1;switch(o.severity){case Lh.DiagnosticSeverity.Warning:t.warning=t.warning+1,e[1]=e[1]?Math.min(e[1],s):s;break;case Lh.DiagnosticSeverity.Information:t.information=t.information+1,e[2]=e[2]?Math.min(e[2],s):s;break;case Lh.DiagnosticSeverity.Hint:t.hint=t.hint+1,e[3]=e[3]?Math.min(e[3],s):s;break;default:e[0]=e[0]?Math.min(e[0],s):s,t.error=t.error+1}}this.nvim.createBuffer(this.bufnr).setVar("coc_diagnostic_info",t,!0),this.nvim.call("coc#util#do_autocmd",["CocDiagnosticChange"],!0)}showVirtualText(e,t){let{config:i}=this,{virtualText:r,virtualTextLevel:o}=i;if(!r)return;let{virtualTextSrcId:s,virtualTextPrefix:a,virtualTextCurrentLineOnly:l}=this.config,{diagnostics:u,buffer:c}=this;if(l){if(t&&this.bufnr!=t)return;u=u.filter(h=>{let{start:d,end:g}=h.range;return d.line<=e-1&&g.line>=e-1})}u.sort(AD),c.clearNamespace(s);for(let h=u.length-1;h>=0;h--){let d=u[h];if(o&&d.severity&&d.severity>o)continue;let{line:g}=d.range.start,f=V_(d.severity)+"VirtualText",p=d.message.split(/\n/).map(b=>b.trim()).filter(b=>b.length>0).slice(0,this.config.virtualTextLines).join(this.config.virtualTextLineSeparator);if(y.has("nvim-0.5.1")){let b={virt_text:[[a+p,f]]};i.virtualTextAlignRight||typeof i.virtualTextWinCol=="number"&&(b.virt_text_win_col=i.virtualTextWinCol),c.setExtMark(s,g,0,b)}else c.setVirtualText(s,g,[[a+p,f]],{})}}updateHighlights(e,t){if(!t.length)this.clearHighlight(e);else{let i=this.getHighlightItems(t),r=this.config.highlightPriority;this.buffer.updateHighlights(ete+e,i,{priority:r})}}async _refresh(){if(!this._dirty)return;let e=await this.getDiagnosticInfo();!e||e.winid==-1||this.diagnosticsMap.size==0||this.refresh(this.diagnosticsMap,e)}getHighlightItems(e){let t=y.getDocument(this.uri);if(!t)return[];let i=[];for(let r of e.slice(0,this.config.highlighLimit)){let o=Kee(r);t.addHighlights(i,o,r.range)}return i.sort((r,o)=>r.lnum!=o.lnum?r.lnum-o.lnum:r.colStart!=o.colStart?r.colStart-o.colStart:tte.indexOf(o.hlGroup)-tte.indexOf(r.hlGroup)),i}clear(){let{nvim:e}=this,t=Array.from(this.diagnosticsMap.keys());if(this.refreshHighlights.clear(),this.diagnosticsMap.clear(),this.displayByAle)for(let i of t)this.nvim.call(nte,[this.bufnr,i,[]],!0);else{e.pauseNotification(),this.buffer.deleteVar("coc_diagnostic_info");for(let i of t)this.clearHighlight(i),this.clearSigns(i);this.config.virtualText&&this.buffer.clearNamespace(this.config.virtualTextSrcId),e.resumeNotification(!0,!0)}}getDiagnosticsAt(e,t){let i=[];for(let r of this.diagnosticsMap.values())t?i.push(...r.filter(o=>q2(e.line,o.range))):i.push(...r.filter(o=>ut(e,o.range)==0));return i.sort(AD),i}async isEnabled(){return this._disposed?!1:await this.nvim.createBuffer(this.bufnr).getVar("coc_diagnostic_disable")!=1}dispose(){this.clear(),this._disposed=!0,this.refreshHighlights.clear()}}});var ds,Tet,bTe,OD,ste=_(()=>{"use strict";ds=C(H());we();V();Tet=q()("diagnostic-collection"),bTe=[ds.DiagnosticTag.Deprecated,ds.DiagnosticTag.Unnecessary],OD=class{constructor(e,t){this.name=e;this.onDispose=t;this.diagnosticsMap=new Map;this._onDidDiagnosticsChange=new ds.Emitter;this.onDidDiagnosticsChange=this._onDidDiagnosticsChange.event}set(e,t){let i=new Map;if(Array.isArray(e))for(let r of e){let[o,s]=r,a=y.getDocument(o);o=a?a.uri:o,s==null?s=[]:s=(i.get(o)||[]).concat(s),i.set(o,s)}else{let r=y.getDocument(e),o=r?r.uri:e;i.set(o,t||[])}for(let r of i){let[o,s]=r;o=O.parse(o).toString(),s.forEach(a=>{a.range=a.range||ds.Range.create(0,0,0,0),a.message=a.message||"",a.source=a.source||this.name,Array.isArray(a.tags)&&a.tags.some(l=>bTe.includes(l))&&(a.severity=ds.DiagnosticSeverity.Hint)}),this.diagnosticsMap.set(o,s),this._onDidDiagnosticsChange.fire(o)}}delete(e){this.diagnosticsMap.delete(e),this._onDidDiagnosticsChange.fire(e)}clear(){let e=Array.from(this.diagnosticsMap.keys());e=e.filter(t=>this.diagnosticsMap.get(t).length>0),this.diagnosticsMap.clear();for(let t of e)this._onDidDiagnosticsChange.fire(t)}forEach(e,t){for(let i of this.diagnosticsMap.keys()){let r=this.diagnosticsMap.get(i);e.call(t,i,r,this)}}entries(){return this.diagnosticsMap.entries()}get(e){let t=this.diagnosticsMap.get(e);return t==null?[]:t.slice()}has(e){return this.diagnosticsMap.has(e)}dispose(){this.clear(),this.onDispose&&this.onDispose(),this._onDidDiagnosticsChange.dispose()}}});var ate,qt,yTe,lte,Ft,eu=_(()=>{"use strict";ate=C(Ei()),qt=C(H());we();le();Zo();z();Je();yt();Pe();ke();V();ote();ste();eR();yTe=q()("diagnostic-manager"),lte=class{constructor(){this.enabled=!0;this._onDidRefresh=new qt.Emitter;this.onDidRefresh=this._onDidRefresh.event;this.collections=[];this.disposables=[]}init(){this.setConfiguration(),y.isNvim&&this.nvim.createNamespace("coc-diagnostic-virtualText").then(r=>{this.config.virtualTextSrcId=r}).logError(),y.onDidChangeConfiguration(this.setConfiguration,this,this.disposables),this.floatFactory=new ci(this.nvim),this.buffers=y.registerBufferSync(r=>{if(!this.enabled)return;let o=new tR(this.nvim,r,this.config,a=>{this._onDidRefresh.fire({diagnostics:a,uri:o.uri,bufnr:o.bufnr}),o.bufnr===y.bufnr&&this.config.messageTarget==="float"&&this.getCurrentDiagnostics().then(l=>this.showFloat(l))}),s=this.getDiagnostics(r.uri);return Object.keys(s).length>0&&o.reset(s),o}),y.onDidCloseTextDocument(r=>{for(let o of this.collections)o.delete(r.uri)},null,this.disposables);let e;E.on("CursorMoved",r=>{this.config.enableMessage=="always"&&(e&&clearTimeout(e),e=setTimeout(async()=>{let o=this.buffers.getItem(r);!o||o.dirty||await this.echoMessage(!0)},this.config.messageDelay))},null,this.disposables);let t=(0,ate.default)(async(r,o)=>{if(!this.config.virtualTextCurrentLineOnly||E.insertMode&&!this.config.refreshOnInsertMode)return;let s=this.buffers.getItem(r);s&&await s.isEnabled()&&s.showVirtualText(o[0])},global.__TEST__?10:100);this.disposables.push(qt.Disposable.create(()=>{t.clear()})),E.on("CursorMoved",t,null,this.disposables),E.on("InsertLeave",async()=>{if(!(this.config.refreshOnInsertMode||!this.autoRefresh))for(let r of this.buffers.items)r.dirty&&r.refreshHighlights()},null,this.disposables),E.on("BufWinEnter",r=>{let o=this.buffers.getItem(r);o&&o.dirty&&o.refreshHighlights()},null,this.disposables),this.clearTimers=()=>{e&&clearTimeout(e),e=void 0,t.clear()},E.on("InsertEnter",this.clearTimers,this,this.disposables);let i=y.configurations.errorItems;this.setConfigurationErrors(i),y.configurations.onError(r=>{this.setConfigurationErrors(r)},null,this.disposables)}defineSigns(){let{nvim:e}=this,{enableHighlightLineNumber:t,enableSign:i}=this.config;if(!!i){e.pauseNotification();for(let r of["Error","Warning","Info","Hint"]){let o=this.config[r.toLowerCase()+"Sign"],s=`sign define Coc${r} linehl=Coc${r}Line`;o&&(s+=` texthl=Coc${r}Sign text=${o}`),t&&(s+=` numhl=Coc${r}Sign`),e.command(s,!0)}e.resumeNotification(!1,!0)}}async setLocationlist(e){if(!this.enabled)throw new Error("Diagnostic not enabled.");let t=this.buffers.getItem(e);if(!t)throw new Error(`buffer ${e} not attached.`);let i=[];for(let a of Object.values(this.getDiagnostics(t.uri)))i.push(...a);let r=t.toLocationListItems(i),o=await this.nvim.call("getloclist",[0,{title:1}]),s=o.title&&o.title.indexOf("Diagnostics of coc")!=-1?"r":" ";await this.nvim.call("setloclist",[0,[],s,{title:"Diagnostics of coc",items:r}])}setConfigurationErrors(e){let t=this.create("config");if(e!=null&&e.length){let i=O.parse(e[0].location.uri).fsPath;k.showErrorMessage(`Error detected for config file ${i}, please check diagnostics list.`);let r=new Map;for(let o of e){let{uri:s}=o.location,a=r.get(s)||[];a.push(qt.Diagnostic.create(o.location.range,o.message,qt.DiagnosticSeverity.Error)),r.set(s,a)}t.set(Array.from(r))}else t.clear()}create(e){let t=this.getCollectionByName(e);return t||(t=new OD(e,()=>{let i=this.collections.findIndex(r=>r==t);i!==-1&&this.collections.splice(i,1)}),this.collections.push(t),t.onDidDiagnosticsChange(i=>{let r=this.buffers.getItem(i);!this.autoRefresh||!r||r.update(e,this.getDiagnosticsByCollection(i,t))}),t)}getSortedRanges(e,t){let i=this.getCollections(e),r=[],o=t?lu(t):0;for(let s of i){let a=s.get(e);if(o)a=a.filter(u=>u.severity==o);else{let u=this.config.level;u&&u!(c.severity&&c.severity>u)))}let l=a.map(u=>u.range);r.push(...l)}return r.sort((s,a)=>s.start.line!=a.start.line?s.start.line-a.start.line:s.start.character-a.start.character),r}getDiagnostics(e){let t={},i=this.getCollections(e);for(let r of i)!r||(t[r.name]=this.getDiagnosticsByCollection(e,r));return t}getDiagnosticsByCollection(e,t){let{level:i,showUnused:r,showDeprecated:o}=this.config,s=t.get(e)||[];return s.length&&(s=s.filter(a=>{var l,u;return!(i&&a.severity&&a.severity>i||!r&&((l=a.tags)==null?void 0:l.includes(qt.DiagnosticTag.Unnecessary))||!o&&((u=a.tags)==null?void 0:u.includes(qt.DiagnosticTag.Deprecated)))}),s.sort((a,l)=>De(a.range.start,l.range.start))),s}getDiagnosticsInRange(e,t){let i=this.getCollections(e.uri),r=[];for(let o of i){let s=o.get(e.uri);if(!!s)for(let a of s)Dl(a.range,t)&&r.push(a)}return r}async preview(){let e=await this.getCurrentDiagnostics();if(e.length==0){this.nvim.command("pclose",!0);return}let t=[];for(let i of e){let{source:r,code:o,severity:s,message:a}=i,l=Rh(s)[0];t.push(`[${r}${o?" "+o:""}] [${l}]`),t.push(...a.split(/\r?\n/)),t.push("")}this.nvim.call("coc#ui#preview_info",[t,"txt"],!0)}async jumpPrevious(e){let t=await this.nvim.buffer,i=this.buffers.getItem(t.id);if(!i)return;let r=await k.getCursorPosition(),o=this.getSortedRanges(i.uri,e),s;for(let a=o.length-1;a>=0;a--){let l=o[a].end;if(De(l,r)<0){s=o[a].start;break}else a==0&&await this.nvim.getOption("wrapscan")&&(s=o[o.length-1].start)}if(s){if(await k.moveTo(s),this.config.enableMessage=="never")return;await this.echoMessage(!1)}}async jumpNext(e){let t=await this.nvim.buffer,i=this.buffers.getItem(t.id);if(!i)return;let r=await k.getCursorPosition(),o=this.getSortedRanges(i.uri,e),s;for(let a=0;a<=o.length-1;a++){let l=o[a].start;if(De(l,r)>0){s=o[a].start;break}else a==o.length-1&&await this.nvim.getOption("wrapscan")&&(s=o[0].start)}if(s){if(await k.moveTo(s),this.config.enableMessage=="never")return;await this.echoMessage(!1)}}async getDiagnosticList(){var i,r;let e=[],{level:t}=this.config;for(let o of this.collections)for(let[s,a]of o.entries()){if(a.length==0)continue;let l=O.parse(s),u=y.getDocument(s),c=u&&u.attached?u.textDocument.lines:void 0;if(!c&&l.scheme==="file")try{let h=a.reduce((d,g)=>Math.max(g.range.end.line,d),0);c=await ia(l.fsPath,0,h)}catch{}for(let h of a){if(h.severity&&h.severity>t)continue;let{start:d,end:g}=h.range,f={file:l.fsPath,lnum:d.line+1,end_lnum:g.line+1,col:Array.isArray(c)?Ze((i=c[d.line])!=null?i:"",d.character)+1:d.character+1,end_col:Array.isArray(c)?Ze((r=c[g.line])!=null?r:"",g.character)+1:g.character+1,code:h.code,source:h.source||o.name,message:h.message,severity:Rh(h.severity),level:h.severity||0,location:qt.Location.create(s,h.range)};e.push(f)}}return e.sort((o,s)=>o.level!==s.level?o.level-s.level:o.file!==s.file?o.file>s.file?1:-1:o.lnum!=s.lnum?o.lnum-s.lnum:o.col-s.col),e}getDiagnosticsAt(e,t,i=!1,r=!1){let o=this.buffers.getItem(e);if(!o)return[];let s=qt.Position.create(t[0],t[1]),a=o.getDiagnosticsAt(s,this.config.checkCurrentLine);return this.config.checkCurrentLine||a.length||i&&(s=qt.Position.create(t[0],t[1]+1),a=o.getDiagnosticsAt(s,!1),a.length)||r&&t[1]==0&&(s=qt.Position.create(t[0]+1,0),a=o.getDiagnosticsAt(s,!1)),a}async getCurrentDiagnostics(){let[e,t,i,r]=await this.nvim.eval(`[bufnr("%"),coc#cursor#position(),col('.')==col('$')-1,line('.')==line('$')]`);return this.getDiagnosticsAt(e,t,i==1,r==1)}async echoMessage(e=!1){let t=this.config;if(!this.enabled||t.displayByAle)return;let i=t.messageTarget=="float",r=await this.getCurrentDiagnostics();if(t.messageLevel&&(r=r.filter(o=>o.severity&&o.severity<=t.messageLevel)),i)await this.showFloat(r);else{if(e&&E.insertMode)return;let o=[];r.forEach(s=>{let{source:a,code:l,severity:u,message:c}=s,h=Rh(u)[0],d=l?" "+l:"",g=t.format.replace("%source",a).replace("%code",d).replace("%severity",h).split("%message").join(c);o.push(g)}),o.length&&(await this.nvim.command('echo ""'),await k.echoLines(o,e))}}async showFloat(e){if(this.config.messageTarget!=="float")return;let{config:t}=this;if(e.length==0){this.floatFactory.close();return}if(E.insertMode)return;let i="",r=[];if(Object.keys(t.filetypeMap).length>0){let s=y.getDocument(y.bufnr),a=s?s.filetype:"",l=t.filetypeMap.default||"";i=t.filetypeMap[a]||(l=="bufferType"?a:l)}e.forEach(s=>{var p;let{source:a,code:l,severity:u,message:c}=s,h=Rh(u)[0],d=l?" "+l:"",g=t.format.replace("%source",a).replace("%code",d).replace("%severity",h).split("%message").join(c),f="Error";if(i==="")switch(u){case qt.DiagnosticSeverity.Hint:f="Hint";break;case qt.DiagnosticSeverity.Warning:f="Warning";break;case qt.DiagnosticSeverity.Information:f="Info";break}else f=i;r.push({filetype:f,content:g}),(p=s.codeDescription)!=null&&p.href&&r.push({filetype:"txt",content:s.codeDescription.href})});let o=this.floatFactory.applyFloatConfig({modes:["n"],maxWidth:80},this.config.floatConfig);yTe.debug("floatConfig:",o),await this.floatFactory.show(r,o)}async jumpRelated(){let t=(await this.getCurrentDiagnostics()).find(r=>r.relatedInformation!=null),i=t?t.relatedInformation.map(r=>r.location):[];i.length==1?await y.jumpTo(i[0].uri,i[0].range.start):i.length>1?await y.showLocations(i):k.showWarningMessage("No related information found.")}reset(){this.clearTimers&&this.clearTimers(),this.buffers.reset();for(let e of this.collections)e.dispose();this.collections=[]}dispose(){var e;this.clearTimers&&this.clearTimers(),this.buffers.dispose();for(let t of this.collections)t.dispose();(e=this.floatFactory)==null||e.close(),this.collections=[],Z(this.disposables)}get nvim(){return y.nvim}setConfiguration(e){if(e&&!e.affectsConfiguration("diagnostic"))return;let t=y.getConfiguration("diagnostic"),i=t.get("messageTarget","float");i=="float"&&!y.env.floating&&!y.env.textprop&&(i="echo");let r=t.get("enableHighlightLineNumber",!0);y.isNvim||(r=!1),this.config=Object.assign(this.config||{},{floatConfig:t.get("floatConfig",{}),messageTarget:i,enableHighlightLineNumber:r,highlighLimit:t.get("highlighLimit",1e3),highlightPriority:t.get("highlightPriority"),autoRefresh:t.get("autoRefresh",!0),checkCurrentLine:t.get("checkCurrentLine",!1),enableSign:y.env.sign&&t.get("enableSign",!0),locationlistUpdate:t.get("locationlistUpdate",!0),enableMessage:t.get("enableMessage","always"),messageDelay:t.get("messageDelay",200),virtualText:t.get("virtualText",!1)&&this.nvim.hasFunction("nvim_buf_set_virtual_text"),virtualTextAlignRight:y.has("nvim-0.5.1")&&t.get("virtualTextAlignRight",!1),virtualTextWinCol:y.has("nvim-0.5.1")?t.get("virtualTextWinCol",null):null,virtualTextCurrentLineOnly:t.get("virtualTextCurrentLineOnly",!0),virtualTextPrefix:t.get("virtualTextPrefix"," "),virtualTextLineSeparator:t.get("virtualTextLineSeparator"," \\ "),virtualTextLines:t.get("virtualTextLines",3),displayByAle:t.get("displayByAle",!1),level:lu(t.get("level","hint")),locationlistLevel:lu(t.get("locationlistLevel")),signLevel:lu(t.get("signLevel")),virtualTextLevel:lu(t.get("virtualTextLevel")),messageLevel:lu(t.get("messageLevel")),signPriority:t.get("signPriority",10),errorSign:t.get("errorSign",">>"),warningSign:t.get("warningSign",">>"),infoSign:t.get("infoSign",">>"),hintSign:t.get("hintSign",">>"),refreshOnInsertMode:t.get("refreshOnInsertMode",!1),filetypeMap:t.get("filetypeMap",{}),showUnused:t.get("showUnused",!0),showDeprecated:t.get("showDeprecated",!0),format:t.get("format","[%source%code] [%severity] %message")}),this.enabled=t.get("enable",!0),this.defineSigns()}getCollectionByName(e){return this.collections.find(t=>t.name==e)}getCollections(e){return this.collections.filter(t=>t.has(e))}toggleDiagnostic(e){let t=e==null?this.enabled:e==0;this.enabled=!t;for(let i of this.buffers.items)this.enabled?this.refreshBuffer(i.uri):i.clear()}async toggleDiagnosticBuffer(e,t){if(!this.enabled)return;e=e||y.bufnr;let i=this.buffers.getItem(e);if(i){let r=t==null?await i.isEnabled():t==0;await this.nvim.call("setbufvar",[e,"coc_diagnostic_disable",r?1:0]),r?i.clear():this.refreshBuffer(e)}}get autoRefresh(){return this.enabled&&this.config.autoRefresh}async refreshBuffer(e,t){let i=this.buffers.getItem(e);return i?(await i.reset(this.getDiagnostics(i.uri),t),!0):!1}refresh(e){let t;if(!e)t=this.buffers.items;else{let i=this.buffers.getItem(e);t=i?[i]:[]}for(let i of t)this.refreshBuffer(i.uri,!0)}},Ft=new lte});var Aa,ttt,ute,cte,oe,wi=_(()=>{"use strict";Aa=C(H());we();eu();iu();z();ke();V();le();ttt=q()("commands"),ute=class{constructor(e,t,i,r=!1){this.id=e;this.impl=t;this.thisArg=i;this.internal=r}execute(...e){let{impl:t,thisArg:i}=this;return t.apply(i,e||[])}dispose(){this.thisArg=null,this.impl=null}},cte=class{constructor(){this.commands=new Map;this.titles=new Map;this.onCommandList=[]}init(e,t){this.mru=y.createMru("commands"),this.register({id:"vscode.open",execute:async i=>{e.call("coc#ui#open_url",i.toString(),!0)}},!0),this.register({id:"workbench.action.reloadWindow",execute:async()=>{e.command("CocRestart",!0)}},!0),this.register({id:"editor.action.insertSnippet",execute:async(i,r)=>{let o=r===!0?{}:r;return await Ut.insertSnippet(i.newText,!0,i.range,Aa.InsertTextMode.adjustIndentation,o||void 0)}},!0),this.register({id:"editor.action.doCodeAction",execute:async i=>{await t.cocAction("doCodeAction",i)}},!0),this.register({id:"editor.action.triggerSuggest",execute:async()=>{let i=y.getDocument(y.bufnr);i&&await i.synchronize(),e.call("coc#start",[],!0)}},!0),this.register({id:"editor.action.triggerParameterHints",execute:async()=>{let i=y.getDocument(y.bufnr);i&&await i.synchronize(),await t.cocAction("showSignatureHelp")}},!0),this.register({id:"editor.action.addRanges",execute:async i=>{await t.cocAction("addRanges",i)}},!0),this.register({id:"editor.action.restart",execute:async()=>{await bt(30),e.command("CocRestart",!0)}},!0),this.register({id:"editor.action.showReferences",execute:async(i,r,o)=>{await y.showLocations(o)}},!0),this.register({id:"editor.action.rename",execute:async(i,r)=>{await y.jumpTo(i,r),await t.cocAction("rename")}},!0),this.register({id:"editor.action.format",execute:async()=>{await t.cocAction("format")}},!0),this.register({id:"workspace.refactor",execute:async i=>{let r=i.filter(o=>Aa.Location.is(o));await t.getHandler().refactor.fromLocations(r)}},!0),this.register({id:"workspace.clearWatchman",execute:async()=>{(await k.runTerminalCommand("watchman watch-del-all")).success&&k.showMessage("Cleared watchman watching directories.")}},!1,"run watch-del-all for watchman to free up memory."),this.register({id:"workspace.workspaceFolders",execute:async()=>{let r=y.workspaceFolders.map(o=>O.parse(o.uri).fsPath);await k.echoLines(r)}},!1,"show opened workspaceFolders."),this.register({id:"workspace.renameCurrentFile",execute:async()=>{await y.renameCurrent()}},!1,"change current filename to a new name and reload it."),this.register({id:"extensions.toggleAutoUpdate",execute:async()=>{let i=y.getConfiguration("coc.preferences");i.get("extensionUpdateCheck","daily")=="never"?(i.update("extensionUpdateCheck","daily",!0),k.showMessage("Extension auto update enabled.","more")):(i.update("extensionUpdateCheck","never",!0),k.showMessage("Extension auto update disabled.","more"))}},!1,"toggle auto update of extensions."),this.register({id:"workspace.diagnosticRelated",execute:()=>Ft.jumpRelated()},!1,"jump to related locations of current diagnostic."),this.register({id:"workspace.showOutput",execute:async i=>{if(i)k.showOutputChannel(i);else{let r=y.channelNames;if(r.length==0)return;if(r.length==1)k.showOutputChannel(r[0]);else{let o=await k.showQuickpick(r);if(o==-1)return;let s=r[o];k.showOutputChannel(s)}}}},!1,"open output buffer to show output from languageservers or extensions."),this.register({id:"document.showIncomingCalls",execute:async()=>{await t.cocAction("showIncomingCalls")}},!1,"show incoming calls in tree view."),this.register({id:"document.showOutgoingCalls",execute:async()=>{await t.cocAction("showOutgoingCalls")}},!1,"show outgoing calls in tree view."),this.register({id:"document.echoFiletype",execute:async()=>{let i=await e.call("bufnr","%"),r=y.getDocument(i);!r||await k.echoLines([r.filetype])}},!1,"echo the mapped filetype of the current buffer"),this.register({id:"document.renameCurrentWord",execute:async()=>{let i=await e.call("bufnr","%"),r=y.getDocument(i);if(!r)return;let o=await t.cocAction("getWordEdit");if(!o){k.showMessage("Invalid position","warning");return}let s=[],{changes:a,documentChanges:l}=o;if(a){let u=a[r.uri];u&&(s=u.map(c=>c.range))}else if(l)for(let u of l)Aa.TextDocumentEdit.is(u)&&u.textDocument.uri==r.uri&&(s=u.edits.map(c=>c.range));s.length&&await t.cocAction("addRanges",s)}},!1,"rename word under cursor in current buffer by use multiple cursors."),this.register({id:"document.jumpToNextSymbol",execute:async()=>{let i=await y.document;if(!i)return;let r=await t.cocAction("symbolRanges");if(!r)return;let{textDocument:o}=i,s=await k.getOffset();r.sort((a,l)=>a.start.line!=l.start.line?a.start.line-l.start.line:a.start.character-l.start.character);for(let a=0;a<=r.length-1;a++)if(o.offsetAt(r[a].start)>s){await k.moveTo(r[a].start);return}await k.moveTo(r[0].start)}},!1,"Jump to next symbol highlight position."),this.register({id:"workspace.undo",execute:async()=>{await y.files.undoWorkspaceEdit()}},!1,"Undo previous workspace edit"),this.register({id:"workspace.redo",execute:async()=>{await y.files.redoWorkspaceEdit()}},!1,"Redo previous workspace edit"),this.register({id:"workspace.inspectEdit",execute:async()=>{await y.files.inspectEdit()}},!1,"Inspect previous workspace edit in new tab"),this.register({id:"workspace.openLocation",execute:async(i,r,o)=>{i&&await e.call("win_gotoid",[i]),await y.jumpTo(r.uri,r.range.start,o)}},!0),this.register({id:"document.jumpToPrevSymbol",execute:async()=>{let i=await y.document;if(!i)return;let r=await t.cocAction("symbolRanges");if(!r)return;let{textDocument:o}=i,s=await k.getOffset();r.sort((a,l)=>a.start.line!=l.start.line?a.start.line-l.start.line:a.start.character-l.start.character);for(let a=r.length-1;a>=0;a--)if(o.offsetAt(r[a].end){await t.cocAction("bufferCheck")}},!1,"Check providers for current buffer.")}get commandList(){let e=[];for(let t of this.commands.values())t.internal||e.push(t);return e}dispose(){for(let e of this.commands.values())e.dispose();this.commands.clear()}execute(e){var t;return this.executeCommand(e.command,...(t=e.arguments)!=null?t:[])}register(e,t=!1,i){for(let r of Array.isArray(e.id)?e.id:[e.id])this.registerCommand(r,e.execute,e,t),i&&this.titles.set(r,i);return e}has(e){return this.commands.has(e)}unregister(e){let t=this.commands.get(e);!t||(t.dispose(),this.commands.delete(e))}registerCommand(e,t,i,r=!1){return e.startsWith("_")&&(r=!0),this.commands.set(e,new ute(e,t,i,r)),Aa.Disposable.create(()=>{this.commands.delete(e)})}executeCommand(e,...t){let i=this.commands.get(e);if(!i)throw new Error(`Command: ${e} not found`);return Promise.resolve(i.execute.apply(i,t))}async fireCommand(e,...t){await E.fire("Command",[e]);let i=Date.now(),r=await this.executeCommand(e,...t);return t.length==0&&await this.addRecent(e,E.lastChangeTs>i),r}async addRecent(e,t){await this.mru.add(e),t&&await y.nvim.command('silent! call repeat#set("\\(coc-command-repeat)", -1)')}async repeatCommand(){let t=(await this.mru.load())[0];t&&(await this.executeCommand(t),await y.nvim.command('silent! call repeat#set("\\(coc-command-repeat)", -1)'))}},oe=new cte});CC();var Xte=C(WM()),Ute=C(aC());le();var $te=require("events"),fR=C(H());wi();var rR=C(H());we();le();Ul();z();In();Jt();Pe();V();var Oa=C(H());z();ls();Pe();Go();ls();Pe();function iR(n,e,t=1){return n===e?1/t:e+32===n?.5/t:0}function hte(n,e){if(e.length==0||n.length=r)return;let o=t[0],s=t.slice(1);if(!X6(o)){let d=nW(n,o,e);if(d==-1)return;let g=d==0?5:1,f=Fh(n,d+1,s,[...i,d]);return f===void 0?void 0:[g+f[0],f[1]]}let a=i.length==0,l=iR(o,n[e],a?.2:1);if(l>0){let d=Fh(n,e+1,s,[...i,e]);return d===void 0?void 0:[l+d[0],d[1]]}let u=new Map,c=vH(n,e+1);if(c!=null){let d=iR(o,c[1],a?.5:1);if(d>0){let g=[...i,c[0]];d===.5&&(d=.75);let f=Fh(n,c[0]+1,s,g);f!==void 0&&u.set(d+f[0],f[1])}}for(let d=e+1;d0){let f=Fh(n,d+1,s,[...i,d]);f!==void 0&&u.set(g+f[0],f[1]);break}}if(u.size==0){if(i.length>0){let d=i[i.length-1];if(d>0&&n[d]!==o&&n[d-1]===o){let g=i.slice();g.splice(i.length-1,0,d-1);let f=Fh(n,d+1,s,g);return f===void 0?void 0:[.5+f[0],f[1]]}}return}let h=Math.max(...u.keys());return[h,u.get(h)]}var vTe=process.env.VIM_NODE_RPC=="1",nR=q()("completion-complete"),MD=class{constructor(e,t,i,r,o,s){this.option=e;this.document=t;this.config=i;this.sources=r;this.mruLoader=o;this.nvim=s;this.results=new Map;this._input="";this._completing=!1;this.localBonus=new Map;this.filtered=new Set;this.names=[];this._onDidRefresh=new Oa.Emitter;this.onDidRefresh=this._onDidRefresh.event;this.tokenSource=new Oa.CancellationTokenSource,r.sort((a,l)=>l.priority-a.priority),this.names=r.map(a=>a.name)}fireRefresh(e){this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>{this.allFiltered||this._onDidRefresh.fire()},e)}get allFiltered(){let{filtered:e,results:t}=this;if(e.size===0)return!1;for(let i of t.keys())if(!e.has(i))return!1;return!0}get isCompleting(){return this._completing}get input(){return this._input}get isEmpty(){let e=!0;for(let t of this.results.values())if(t.items.length>0){e=!1;break}return e}getIncompleteSources(){let e=[];for(let[t,i]of this.results.entries())i.isIncomplete&&e.push(t);return e}async doComplete(){let e=this.tokenSource.token,t=await Promise.all([this.nvim.call("coc#util#synname",[]),this.document.patchChange()]);if(this.option.synname=t[0],e.isCancellationRequested)return!0;let{triggerCompletionWait:i,localityBonus:r}=this.config;if(await bt(Math.min(i!=null?i:0,50)),e.isCancellationRequested)return!0;let{colnr:o,linenr:s,col:a}=this.option;if(r){let l=s-1;this.localBonus=this.document.getLocalifyBonus(Oa.Position.create(l,a-1),Oa.Position.create(l,o))}return await this.completeSources(this.sources),e.isCancellationRequested}async completeSources(e){let{fixInsertedWord:t,timeout:i}=this.config,{results:r,tokenSource:o}=this,s=this.option.col,a=r.size>0,l=t?this.getFollowPart():"",u=e.map(p=>p.name),c=u.length;this._completing=!0;let h=o.token,d,g=new Promise(p=>{d=setTimeout(()=>{o.token.isCancellationRequested||(u=u.filter(b=>!f.includes(b)),o.cancel(),nR.warn(`Complete timeout after ${i}ms`,u),this.nvim.setVar("coc_timeout_sources",u,!0)),p()},typeof i=="number"?i:500)}),f=[];await Promise.race([g,Promise.all(e.map(p=>this.completeSource(p,h,l).then(()=>{if(f.push(p.name),h.isCancellationRequested||a)return;let b=this.option.col!==s;b&&this.cancel(),b||f.length===c?this.fireRefresh(0):r.has(p.name)&&this.fireRefresh(16)})))]),clearTimeout(d),this._completing=!1}async completeSource(e,t,i){var a;let r=Object.assign({},this.option),{snippetIndicator:o}=this.config,{name:s}=e;try{if(typeof e.shouldComplete=="function"&&(!await Promise.resolve(e.shouldComplete(r))||t.isCancellationRequested))return;let l=(a=e.priority)!=null?a:0,u=Date.now();await new Promise((c,h)=>{Promise.resolve(e.doComplete(r,t)).then(d=>{let g=d?d.items.length:0;if(t.isCancellationRequested){c(void 0);return}if(nR.debug(`Source "${s}" finished with ${g} items ${Date.now()-u}ms`),g>0){d.priority=l;let f=i.length>0;d.items.forEach((p,b)=>{var D,S,F;let v=(D=p.word)!=null?D:"",w=(S=p.abbr)!=null?S:v;p.word=v,p.source=s,p.priority=l,p.filterText=(F=p.filterText)!=null?F:v,f&&v!=i&&v.endsWith(i)&&(p.word=v.slice(0,-i.length)),p.isSnippet===!0&&!w.endsWith(o)&&(p.abbr=`${w}${o}`),p.localBonus=this.localBonus.get(p.filterText)||0,p.user_data=`${s}:${b}`}),this.setResult(s,d)}else this.results.delete(s);c()},d=>{h(d)})})}catch(l){this.nvim.echoError(l),nR.error("Complete error:",e.name,l)}}async completeInComplete(e,t){let{document:i}=this;this.cancel(),this.tokenSource=new Oa.CancellationTokenSource;let r=this.tokenSource.token;if(await i.patchChange(!0),r.isCancellationRequested)return;let{input:o,colnr:s,linenr:a}=this.option,l=e[e.length-1];Object.assign(this.option,{input:e,line:i.getline(a-1),colnr:s+(e.length-o.length),triggerCharacter:!l||hc(l)?void 0:l,triggerForInComplete:!0});let u=this.sources.filter(c=>t.includes(c.name));if(await this.completeSources(u),!r.isCancellationRequested)return this.filterItems(e)}filterItems(e){let{results:t,names:i}=this;if(this._input=e,t.size==0)return[];let r=e.length,o=r==0,{maxItemCount:s,selection:a,enablePreselect:l,defaultSortMethod:u,removeDuplicateItems:c}=this.config,h=[],d=xn(e),g=new Set,f=-1,p=a!=="none";for(let v of i){let w=t.get(v);if(!w)continue;let D=v==="snippets",S=w.items;for(let F=0;F{let D=v.sortText,S=w.sortText;if(v.score!==w.score)return w.score-v.score;if(v.priority!==w.priority)return w.priority-v.priority;if(v.localBonus!==w.localBonus)return w.localBonus-v.localBonus;if(v.source===w.source&&D!==S)return D{let{results:v}=this;for(let w of b){let D=v.get(w);D&&(D.items=h.filter(S=>S.source===w))}}),f!==-1){let v=h.findIndex(w=>w.recentScore===f);if(l&&!vTe)h[v].preselect=!0;else{let w=h.splice(v,1);h.unshift(w[0])}}return this.limitCompleteItems(h.slice(0,s))}async filterResults(e){if(this.filtered=new Set(this.results.keys()),e!==this.option.input){let t=this.getIncompleteSources();if(t.length)return await this.completeInComplete(e,t)}return this.filterItems(e)}limitCompleteItems(e){let{highPrioritySourceLimit:t,lowPrioritySourceLimit:i}=this.config;if(!t&&!i)return e;let r=new Map;return e.filter(o=>{let{priority:s,source:a}=o,l=s<90,u=r.get(a)||0;return i&&l&&u==i||t&&!l&&u==t?!1:(r.set(a,u+1),!0)})}setResult(e,t){let{results:i}=this,{line:r,colnr:o,col:s}=this.option;if(typeof t.startcol=="number"&&t.startcol!=s){let{startcol:a}=t;this.option.col=a,this.option.input=et(r,a,o-1),i.clear(),i.set(e,t)}else i.set(e,t)}cancel(){let{tokenSource:e,timer:t}=this;t&&clearTimeout(t),e.cancel(),this._completing=!1}resolveCompletionItem(e){if(typeof e.user_data!="string")return null;try{let t=e.user_data.split(":",2),i=this.results.get(t[0]);return i?i.items.find(r=>r.user_data==e.user_data):null}catch{return null}}getFollowPart(){let{colnr:e,line:t}=this.option,i=Ui(t,e-1);return i==t.length?"":t.slice(i-t.length).match(/^\S?[\w-]*/)[0]}dispose(){this.cancel(),this._onDidRefresh.dispose(),this.sources=[],this.filtered.clear(),this.results.clear()}};le();X0();var mtt=q()("floating"),ND=class{constructor(e,t){this.nvim=e;this.isVim=t;this.winid=0;this.bufnr=0}async show(e,t,i){let{nvim:r}=this;e=e.filter(c=>c.content.trim().length>0);let{lines:o,codes:s,highlights:a}=lb(e,{excludeImages:i.excludeImages});if(o.length==0){this.close();return}let l={codes:s,highlights:a,maxWidth:i.maxWidth||80,pumbounding:t};i.border&&(l.border=[1,1,1,1]),i.highlight&&(l.highlight=i.highlight),i.borderhighlight&&(l.borderhighlight=i.borderhighlight),this.isVim||(typeof i.winblend=="number"&&(l.winblend=i.winblend),l.focusable=i.focusable===!0?1:0,i.shadow&&(l.shadow=1));let u=await r.call("coc#dialog#create_pum_float",[this.winid,this.bufnr,o,l]);r.redrawVim(),!(!u||u.length==0)&&(this.winid=u[0],this.bufnr=u[1],E.pumvisible||this.close())}close(){let{winid:e,nvim:t}=this;this.winid=0,e&&(t.call("coc#float#close",[e],!0),t.redrawVim())}};lf();var BD=class{constructor(e){this.selection=e;this.max=0;this.items=new Map;this.itemsNoPrefex=new Map;this.mru=new oo(`suggest${globalThis.__TEST__?process.pid:""}.txt`,process.env.COC_DATA_HOME,1e3)}async load(){let{selection:e}=this;if(e=="none")return;let t=await this.mru.load(),i=t.length;for(let r=i-1;r>=0;r--){let o=t[r];if(!o.includes("|"))continue;let[s,a,l,u]=o.split("|");!l||(this.items.set(o,i-1-r),this.itemsNoPrefex.set(`${a}|${l}|${u||""}`,i-1-r))}this.max=i-1}getScore(e,t){var o,s;let i=dte(t);return e.length==0?(o=this.itemsNoPrefex.get(i))!=null?o:-1:(this.selection==="recentlyUsedByPrefix"&&(i=`${e}|${i}`),(s=(this.selection==="recentlyUsed"?this.itemsNoPrefex:this.items).get(i))!=null?s:-1)}add(e,t){if(this.selection=="none")return;let i=dte(t),r=`${e}|key`;this.items.set(r,this.max),this.itemsNoPrefex.set(i,this.max),this.max+=1,this.mru.add(r)}};function dte(n){var r;let e=n.filterText,t=n.source,i=(r=n.kind)!=null?r:"";return`${e}|${t}|${i}`}le();Pe();var Ctt=q()("completion-util");async function gte(){let n=await E.race(["InsertLeave","CursorMovedI","MenuPopupChanged","TextChangedI","InsertCharPre"],300);return n==null?void 0:n.name}async function fte(){let n=await E.race(["InsertCharPre","CursorMoved","InsertLeave","TextChangedI"],100);return!n||n.name!=="TextChangedI"?n?n.name:void 0:n.args[1]}function pte(n="",e){if(!n)return!1;for(let t of n.split(","))if(t.indexOf("=")>-1){let[i,r]=t.split("="),o=r.startsWith("~")?r.slice(1):r;if(e.lengtho.length&&!/^\s/.test(e.slice(-o.length-1))||!(r.startsWith("~")?e.toLowerCase().endsWith(o):e.endsWith(o)))continue;if(i==""||i=="0"&&(e.length==o.length||/^\s*$/.test(e.slice(0,e.length-o.length))))return!0}return!1}function mte(n,e,t,i){let{pre:r}=t;if(r.length===0||r[r.length-1]===" "||r.length{e.affectsConfiguration("suggest")&&(this.config=this.getCompleteConfig())},null,this.disposables),this.floating=new ND(y.nvim,y.env.isVim),E.on("InsertLeave",()=>{this.stop()},null,this.disposables),E.on("CursorMovedI",(e,t,i)=>{if(this.triggerTimer&&clearTimeout(this.triggerTimer),!(i||!this.option||e!==this.option.bufnr)){if(this.option.linenr===t[0]){let r=y.getDocument(e),o=r.getline(t[0]-1),s=Ui(o,t[1]-1),a=Ui(o,this.option.colnr-1);if(a{var t;if(this.previousItem=(t=this.popupEvent)==null?void 0:t.completed_item,this.popupEvent=null,this.hasInsert=!1,!(!this.activated||e.closed)){if(this.cancelResolve(),e.close)return this.stop();uc(e)?await this.onCompleteDone(e):await gte()=="CursorMovedI"&&this.stop()}},null,this.disposables),E.on("MenuPopupChanged",async e=>{var t;!this.activated||((t=this.document)==null?void 0:t.isCommandLine)||Fe(this.popupEvent,e)||(this.cancelResolve(),this.popupEvent=e,await this.onPumChange())},null,this.disposables)}get option(){return this.complete?this.complete.option:null}get selectedItem(){if(!this.popupEvent)return null;let{completed_item:e}=this.popupEvent;return uc(e)?e:null}get isActivated(){return this.activated}get document(){return this.option?y.getDocument(this.option.bufnr):null}getCompleteConfig(){let e=y.getConfiguration("suggest");function t(a,l){return e.get(a,l)}let i=t("keepCompleteopt",!1),r=t("autoTrigger","always");if(i&&r!="none"){let{completeOpt:a}=y;!a.includes("noinsert")&&!a.includes("noselect")&&(i=!1,this.nvim.echoError("suggest.keepCompleteopt disabled, completeopt should includes noinsert or noselect"))}let o=y.floatSupported&&t("floatEnable",!0),s=y.env.pumevent&&t("acceptSuggestionOnCommitCharacter",!1);return{autoTrigger:r,floatEnable:o,keepCompleteopt:i,selection:t("selection","recentlyUsed"),floatConfig:t("floatConfig",{}),defaultSortMethod:t("defaultSortMethod","length"),removeDuplicateItems:t("removeDuplicateItems",!1),disableMenuShortcut:t("disableMenuShortcut",!1),acceptSuggestionOnCommitCharacter:s,disableKind:t("disableKind",!1),disableMenu:t("disableMenu",!1),previewIsKeyword:t("previewIsKeyword","@,48-57,_192-255"),enablePreview:t("enablePreview",!1),enablePreselect:t("enablePreselect",!1),triggerCompletionWait:t("triggerCompletionWait",0),labelMaxLength:t("labelMaxLength",200),triggerAfterInsertEnter:t("triggerAfterInsertEnter",!1),noselect:t("noselect",!0),maxItemCount:t("maxCompleteItemCount",50),timeout:t("timeout",500),minTriggerInputLength:t("minTriggerInputLength",1),snippetIndicator:t("snippetIndicator","~"),fixInsertedWord:t("fixInsertedWord",!0),localityBonus:t("localityBonus",!0),highPrioritySourceLimit:t("highPrioritySourceLimit",null),lowPrioritySourceLimit:t("lowPrioritySourceLimit",null),ignoreRegexps:t("ignoreRegexps",[]),asciiCharactersOnly:t("asciiCharactersOnly",!1)}}async startCompletion(e,t){try{let i=y.getAttachedDocument(e.bufnr);if(e.filetype=i.filetype,gs.debug("trigger completion with",e),this.stop(),this.pretext=et(e.line,0,e.colnr-1),t=t!=null?t:this.getSources(e),!t||t.length===0)return;E.completing=!0,this.changedtick=e.changedtick;let r=this.complete=new MD(e,i,this.config,t,this.mru,this.nvim);r.onDidRefresh(async()=>{if(this.triggerTimer!=null&&clearTimeout(this.triggerTimer),r.isEmpty){this.stop();return}this.hasInsert||await this.filterResults()}),await r.doComplete()}catch(i){this.stop(),this.nvim.echoError(i)}}getSources(e){let{source:t}=e;if(t){let i=Lt.getSource(t);return i?[i]:[]}return Lt.getCompleteSources(e)}hasSelected(){return y.env.pumevent?this.selectedItem!=null:!this.config.noselect}showCompletion(e){let{nvim:t,option:i,changedtick:r}=this;if(!i)return;let{disableKind:o,labelMaxLength:s,disableMenuShortcut:a,disableMenu:l}=this.config,u=this.config.enablePreselect?e.findIndex(d=>d.preselect):-1,c=wTe.slice();o&&(c=c.filter(d=>d!="kind")),l&&(c=c.filter(d=>d!="menu"));let h=e.map(d=>{let g={word:d.word,equal:1};for(let f of c)d.hasOwnProperty(f)&&(a&&f=="menu"?g[f]=d[f].replace(/\[.+\]$/,""):f=="abbr"&&d[f].length>s?g[f]=d[f].slice(0,s):g[f]=d[f]);return g});t.pauseNotification(),h.length&&this.start(),t.call("coc#_do_complete",[i.col,h,u,r],!0),t.resumeNotification(!1,!0)}async onTextChangedP(e,t){let{option:i,document:r}=this;if(!i||i.bufnr!=e||(t.insertChar||this.pretext==t.pre)&&pte(i.indentkeys,t.pre)&&(gs.debug(`trigger indent by ${t.pre}`),await this.nvim.call("coc#complete_indent",[]))||(this.changedtick=t.changedtick,this.pretext==t.pre))return;let o=this.pretext=t.pre;if(t.pre.match(/^\s*/)[0]!==i.line.match(/^\s*/)[0]){this.stop();let s=await E.race(["TextChangedI","InsertCharPre"],50);s.name==="TextChangedI"&&await this.triggerCompletion(r,s.args[1]);return}if(this.selectedItem&&!t.insertChar&&et(i.line,0,i.col)+this.selectedItem.word==o){this.hasInsert=!0;return}await this.filterResults()}async onTextChangedI(e,t){if(!y.isAttached(e)||this.config.autoTrigger==="none"||this.option&&mte(e,this.pretext,t,this.option)&&(this.stop(),!t.insertChar)||(this.changedtick=t.changedtick,t.pre===this.pretext))return;this.triggerTimer&&clearTimeout(this.triggerTimer);let i=this.pretext=t.pre,r=y.getDocument(e);if(this.activated&&this.config.acceptSuggestionOnCommitCharacter&&uc(this.previousItem)){let o=this.getCompleteItem(this.previousItem),s=i.slice(-1);if(Lt.shouldCommit(o,s)){gs.debug("commit by commit character.");let{linenr:a,col:l,line:u,colnr:c}=this.option;this.stop();let{word:h}=o,d=`${u.slice(0,l)}${h}${t.insertChar}${u.slice(c-1)}`;await this.nvim.call("coc#util#setline",[a,d]);let g=l+h.length+2;await this.nvim.call("cursor",[a,g]),await r.patchChange();return}}if(t.insertChar&&!hc(t.insertChar)){let o=r.getVar("disabled_sources",[]),s=Lt.getTriggerSources(i,r.filetype,r.uri,o);if(s.length>0){await this.triggerCompletion(r,t,s);return}}if(!this.complete){if(!t.insertChar)return;await this.triggerCompletion(r,t);return}if(t.insertChar&&this.complete.isEmpty){this.triggerTimer=setTimeout(async()=>{await this.triggerCompletion(r,t)},200);return}await this.filterResults()}async triggerCompletion(e,t,i){let{minTriggerInputLength:r}=this.config,{pre:o}=t;if(!i&&!this.shouldTrigger(e,o))return!1;if(e.getVar("suggest_disable"))return gs.warn(`Completion of ${e.bufnr} disabled by b:coc_suggest_disable`),!1;let a=this.getInput(e,o),l={input:a,line:t.line,filetype:e.filetype,linenr:t.lnum,col:t.col-1-Q(a),colnr:t.col,bufnr:e.bufnr,word:a+this.getPrependWord(e,t.line.slice(o.length)),changedtick:t.changedtick,indentkeys:e.indentkeys,synname:"",filepath:e.schema==="file"?O.parse(e.uri).fsPath:"",triggerCharacter:o.length?o.slice(-1):void 0,blacklist:e.getVar("suggest_blacklist",[]),disabled:e.getVar("disabled_sources",[])};return i==null&&a.length0&&l.input.length>0&&this.config.ignoreRegexps.some(c=>{if(new RegExp(c).test(l.input))return gs.warn(`Suggest disabled by ignore regexp: ${c}`),!0})?!1:(await this.startCompletion(l,i),!0)}async onCompleteDone(e){let{document:t,complete:i}=this;if(!t||!uc(e))return;let r=i.input,o=Object.assign({},this.option),s=this.getCompleteItem(e);if(this.stop(),!s)return;this.mru.add(r,s);let a=await fte();if(typeof a=="string"||a&&(a.lnum!=o.linenr||a.pre!==et(o.line,0,o.col)+e.word)||await E.race(["InsertCharPre","CursorMovedI"],20))return;let u=new rR.CancellationTokenSource,{token:c}=u;await this.doCompleteResolve(s,u),!c.isCancellationRequested&&await this.doCompleteDone(s,o)}doCompleteResolve(e,t){let i=Lt.getSource(e.source);return new Promise(r=>{if(i&&typeof i.onCompleteResolve=="function"){let o=setTimeout(()=>{t.cancel(),gs.warn(`Resolve timeout after 500ms: ${i.name}`),r()},500);Promise.resolve(i.onCompleteResolve(e,t.token)).then(()=>{clearTimeout(o),r()},s=>{gs.error(`Error on complete resolve: ${s.message}`,s),clearTimeout(o),r()})}else r()})}async doCompleteDone(e,t){let i=Lt.getSource(e.source);i&&typeof i.onCompleteDone=="function"&&await Promise.resolve(i.onCompleteDone(e,t))}async onInsertEnter(e){if(!this.config.triggerAfterInsertEnter||this.config.autoTrigger!=="always"||!y.isAttached(e))return;let t=await this.nvim.call("coc#util#change_info");if(t.pre=et(t.line,0,t.col-1),!t.pre)return;let i=y.getDocument(e);await this.triggerCompletion(i,t)}shouldTrigger(e,t){let{autoTrigger:i}=this.config;return i=="none"?!1:Lt.shouldTrigger(t,e.filetype,e.uri)?!0:i==="always"}async onPumChange(){if(!this.popupEvent)return;let{col:e,row:t,height:i,width:r,scrollbar:o}=this.popupEvent,s={col:e,row:t,height:i,width:r,scrollbar:o},a=this.getCompleteItem(this.selectedItem);if(!a){this.floating.close();return}let l=this.resolveTokenSource=new rR.CancellationTokenSource,{token:u}=l;if(await this.doCompleteResolve(a,l),u.isCancellationRequested)return;let c=a.documentation;if(!c&&a.info){let{info:h}=a;c=[{filetype:/^[\w-\s.,\t]+$/.test(h)?"txt":this.document.filetype,content:h}]}if(!!this.config.floatEnable)if(!c||c.length==0)this.floating.close();else{let h=y.getConfiguration("coc.preferences").get("excludeImageLinksInMarkdownDocument"),d=Object.assign({},this.config.floatConfig,{excludeImages:h});await this.floating.show(c,s,d)}}start(){this.activated||(this.activated=!0,this.config.keepCompleteopt||this.nvim.command(`noa set completeopt=${this.completeOpt}`,!0))}cancelResolve(){this.resolveTokenSource&&(this.resolveTokenSource.cancel(),this.resolveTokenSource.dispose(),this.resolveTokenSource=null)}stop(){if(E.completing=!1,this.cancel(),this.activated){this.activated=!1;let{nvim:e,config:t}=this,i=t.keepCompleteopt?"":y.completeOpt;e.call("coc#_cancel",[1,i],!0),e.redrawVim()}}getInput(e,t){let{asciiCharactersOnly:i}=this.config,r=0;for(let o=t.length-1;o>=0;o--){let s=t[o];if(e.isWord(s)&&(i?s.charCodeAt(0)<255:!0))r+=1;else break}return r==0?"":t.slice(-r)}getPrependWord(e,t){let i=0;for(let r=0;r0&&e.blacklist&&e.blacklist.includes(a)?null:a}async filterResults(){let{complete:e}=this,t=this.getResumeInput();if(t==null){this.stop();return}let i=await e.filterResults(t);if(i!==void 0){if(i.length==0){e.isCompleting||this.stop();return}this.showCompletion(i)}}get completeOpt(){let{noselect:e,enablePreview:t}=this.config,i=t&&!y.env.pumevent?",preview":"";return e?`noselect,menuone${i}`:`noinsert,menuone${i}`}getCompleteItem(e){return!this.complete||!uc(e)?null:this.complete.resolveCompletionItem(e)}cancel(){this.complete!=null&&(this.complete.dispose(),this.complete=null),this.triggerTimer!=null&&(clearTimeout(this.triggerTimer),this.triggerTimer=null),this.cancelResolve(),this.previousItem=void 0,this.pretext=void 0,this.hasInsert=!1}dispose(){this.cancelResolve(),Z(this.disposables)}},Ih=new bte;wb();var Oh=C(H());yt();ke();V();var Ah=C(Lg()),fs=C(H());Ec();z();yt();jr();ke();V();Qr();yt();jr();var oR=C(H());Jt();jr();function sR(n,e){let t=[];for(let i=e.start.line;i<=e.end.line;i++){let r=n.getline(i)||"",o=i==e.start.line?e.start.character:0,s=i==e.end.line?e.end.character:r.length;o!=s&&t.push(oR.Range.create(i,o,i,s))}return t}function yte(n,e){let{start:t,end:i}=Zb(e),r=t.characterr}};var cp=q()("cursors-session"),qD=class{constructor(e,t){this.nvim=e;this.doc=t;this._onDidCancel=new fs.Emitter;this._onDidUpdate=new fs.Emitter;this.onDidCancel=this._onDidCancel.event;this.onDidUpdate=this._onDidUpdate.event;this.disposables=[];this.ranges=[];this.activated=!0;this.changing=!1;t.buffer.setVar("coc_cursors_activated",1,!0),this.loadConfig();let{cancelKey:i,nextKey:r,previousKey:o}=this.config;this.disposables.push(y.registerLocalKeymap("n",i,()=>{this.cancel()})),this.disposables.push(y.registerLocalKeymap("n",r,async()=>{let s=this.ranges.map(u=>u.range),a=await k.getCursorPosition();for(let u of s)if(De(u.start,a)>0){await k.moveTo(u.start);return}let l=this.config.wrapscan;s.length&&l&&await k.moveTo(s[0].start)})),this.disposables.push(y.registerLocalKeymap("n",o,async()=>{let s=this.ranges.map(u=>u.range),a=await k.getCursorPosition();for(let u=s.length-1;u>=0;u--){let c=s[u];if(De(c.end,a)<0){await k.moveTo(c.start);return}}let l=this.config.wrapscan;s.length&&l&&await k.moveTo(s[s.length-1].start)})),this.doc.onDocumentChange(async s=>{await this.onChange(s),this.activated&&!this.changing&&this._onDidUpdate.fire()},this,this.disposables)}loadConfig(){let e=y.getConfiguration("cursors",this.doc.uri);this.config={nextKey:e.get("nextKey",""),previousKey:e.get("previousKey",""),cancelKey:e.get("cancelKey",""),wrapscan:e.get("wrapscan",!0)}}addRange(e){let{ranges:t}=this,i=t.findIndex(r=>Dl(r.range,e));i!==-1?t.splice(i,1):(this.createRange(e),t.sort((r,o)=>De(r.range.start,o.range.start))),this.ranges.length==0?this.cancel():this.doHighlights()}addRanges(e){this.doc._forceSync(),this.ranges=this.ranges.filter(t=>!e.some(i=>Sc(i,t.range)));for(let t of e)this.createRange(t);return this.ranges.sort((t,i)=>De(t.range.start,i.range.start)),this.doHighlights(),!0}createRange(e){let{textDocument:t}=this.doc,{line:i,character:r}=e.start,o=t.getText(e);this.ranges.push(new jh(i,r,o))}async onChange(e){if(!this.activated||this.changing)return;if(e.contentChanges.length===0){this.doHighlights();return}let t=e.contentChanges[0],{text:i,range:r}=t,o=this.ranges.filter(s=>!(!Dl(r,s.range)||yb(r,s.range)&&(i.includes(` -`)||!Ct(r))));if(Ct(r)&&o.length>0&&(o=o.slice(0,1)),o.length==0)cp.debug("no affected ranges"),this.ranges.forEach(s=>{s.adjustFromEdit({range:r,newText:i})}),this.doHighlights();else if(o.length==1&&Pi(r,o[0].range)){if(cp.debug("affected single range"),i.includes(` -`)){this.cancel();return}await this.applySingleEdit(o[0],{range:r,newText:i})}else if(!i.length||!this.validChange(r,i)){cp.debug("filter affected ranges.");let s=this.ranges.filter(a=>!o.includes(a));s.length>0?(this.ranges=s,s.forEach(a=>{a.adjustFromEdit({range:r,newText:i})}),this.doHighlights()):this.cancel()}else{cp.debug("Check undo & redo");let s=this.ranges[0],a=this.ranges[this.ranges.length-1],l=e.originalLines.slice(s.line,a.line+1),u=this.doc.textDocument.lines.slice(s.line,a.line+1);this.applyComposedEdit(l,u)}}validChange(e,t){if(ra(fs.TextEdit.replace(e,t))!=0||!Pi(e,this.range))return!1;let i=this.ranges[0],r=this.ranges[this.ranges.length-1];return!(e.start.line!=i.position.line||e.end.line!=r.position.line)}get range(){let e=this.ranges[0],t=this.ranges[this.ranges.length-1];return fs.Range.create(e.position,t.range.end)}doHighlights(){let{nvim:e,ranges:t,doc:i}=this,r=i.buffer,o=[];t.forEach(s=>{i.addHighlights(o,"CocCursorRange",s.range,{combine:!1,start_incl:!0,end_incl:!0})}),o.sort((s,a)=>s.lnum!=a.lnum?s.lnum-a.lnum:s.colStart!=a.colStart?s.colStart-a.colStart:0),r.updateHighlights("cursors",o,{priority:4096}),e.redrawVim()}get currentRanges(){return this.ranges.map(e=>e.range)}cancel(){if(!this.activated)return;cp.debug("cursors cancel");let{nvim:e,doc:t}=this,i=t.buffer;this.activated=!1,this.ranges=[],e.pauseNotification(),i.clearNamespace("cursors"),i.setVar("coc_cursors_activated",0,!0),e.resumeNotification(!0,!0),this._onDidUpdate.fire(),this._onDidCancel.fire()}dispose(){!this.doc||(this._onDidCancel.dispose(),this._onDidUpdate.dispose(),Z(this.disposables),this.ranges=[],this.doc=null)}async applySingleEdit(e,t){let{doc:i,ranges:r}=this;r.filter(u=>u!==e&&u.position.line==e.position.line).forEach(u=>u.adjustFromEdit(t));let s=HD(e,t.range,t.newText),a=lp(s);r.forEach(u=>u.applyChange(s));let l=r.filter(u=>u!==e).map(u=>u.textEdit);if(this.changing=!0,await i.applyEdits(l,!0,!0),this.changing=!1,a!=0)for(let u of r){let c=up(u,this.ranges,e);u.move(c*a)}this.doHighlights()}applyComposedEdit(e,t){var v,w,D;let i=(0,Ah.default)(e[0],t[0]),r=this.ranges[0],o=r.position.character,s=r.position.line,a=r.text.length,l=i[0];if(o>0&&(l[0]!=Ah.default.EQUAL||!l[1].startsWith(e[0].slice(0,o))))return this.cancel(),!1;let u=0,c=!1,h=[];for(let S=0;S0&&(L=L.slice(o)),F==Ah.default.EQUAL){if(u+=L.length,u>a)break}else if(F==Ah.default.DELETE){let j=u;if(u+=L.length,u>a){c=!0;break}h.push({offset:j,remove:L})}else{let j=i[S-1];j&&j[0]==Ah.default.DELETE?h[h.length-1].add=L:h.push({offset:u,add:L})}}if(c||!h.length)return this.cancel(),!1;let d=jn.create("file:///1","",0,e.join(` -`)),g;if(h.length==1)g={offset:h[0].offset,remove:h[0].remove?h[0].remove.length:0,insert:(v=h[0].add)!=null?v:""};else if(DTe(h,a))g={prepend:[h[0].remove?h[0].remove.length:0,(w=h[0].add)!=null?w:""],append:[h[1].remove?h[1].remove.length:0,(D=h[1].add)!=null?D:""]};else{let S=r.text,F="",L="",j=h[0].offset;for(let W of h){if(W.offset>j+F.length){let B=S.slice(j+F.length,W.offset);F+=B,L+=B}W.add&&(L+=W.add),W.remove&&(F+=W.remove)}g={offset:j,remove:F.length,insert:L}}let f=this.ranges.map(S=>{let F=S.position.line-s,{start:L,end:j}=S.range,W=fs.Range.create(F,L.character,F,j.character);return S.applyChange(g),fs.TextEdit.replace(W,S.text)});if(jn.applyEdits(d,f)!==t.join(` -`))return this.cancel(),!1;let b=lp(g);if(b!=0)for(let S of this.ranges){let F=up(S,this.ranges);S.move(F*b)}return this.doHighlights(),!0}};function DTe(n,e){return!(n.length!=2||n[0].offset!=0||n[1].offset+(n[1].remove?n[1].remove.length:0)!==e)}var vit=q()("cursors"),YD=class{constructor(e){this.nvim=e;this.sessionsMap=new Map;this.disposables=[];y.onDidCloseTextDocument(t=>{let i=this.getSession(t.bufnr);!i||(this.sessionsMap.delete(t.bufnr),i.cancel())},null,this.disposables)}cancel(e){let t=y.getDocument(e);if(!t)return;let i=this.getSession(t.bufnr);i&&i.cancel()}getSession(e){return this.sessionsMap.get(e)}async isActivated(){let e=await this.nvim.call("bufnr",["%"]);return this.sessionsMap.get(e)!=null}async select(e,t,i){let r=y.getAttachedDocument(e),{nvim:o}=this,s=this.createSession(r),a=await k.getCursorPosition(),l;if(t=="operator"){await o.command(`normal! ${i=="line"?"'[":"`["}`);let u=await k.getCursorPosition();await o.command(`normal! ${i=="line"?"']":"`]"}`);let c=await k.getCursorPosition();await k.moveTo(a);let h=De(u,c);if(h==0)return;h>=0&&([u,c]=[c,u]);let d=r.getline(c.line);c.character(coc-cursors-${t})", -1)`)}else if(t=="position"){let u=r.getline(a.line);a.character>=u.length?l=Oh.Range.create(a.line,u.length-1,a.line,u.length):l=Oh.Range.create(a.line,a.character,a.line,a.character+1),s.addRange(l),await o.command(`silent! call repeat#set("\\(coc-cursors-${t})", -1)`)}else if(t=="range"){await o.call("eval",'feedkeys("\\", "in")');let u=await k.getSelectedRange(i);if(!u)return;let c=i==""?yte(r,u):sR(r,u);for(let h of c)s.addRange(h)}else throw new Error(`select kind "${t}" not supported`)}createSession(e){let{bufnr:t}=e,i=this.getSession(t);return i||(i=new qD(this.nvim,e),this.sessionsMap.set(t,i),i.onDidCancel(()=>{i.dispose(),this.sessionsMap.delete(t)}),i)}async addRanges(e){let{nvim:t}=this,i=await t.call("bufnr",["%"]),r=y.getAttachedDocument(i);return this.createSession(r).addRanges(e)}reset(){for(let e of this.sessionsMap.values())e.cancel();this.sessionsMap.clear()}};eu();le();bo();var Dx=C(H());le();Ce();z();ke();V();var Mh=C(H());wi();eu();Ce();ke();V();var Eit=q()("handler-codeActions"),WD=class{constructor(e,t){this.nvim=e;this.handler=t;t.addDisposable(oe.registerCommand("editor.action.organizeImport",async i=>{await this.organizeImport(i)})),oe.titles.set("editor.action.organizeImport","run organize import code action.")}async codeActionRange(e,t,i){let{doc:r}=await this.handler.getCurrentState();await r.synchronize();let o=r.getline(t-1),s=Mh.Range.create(e-1,0,t-1,o.length),a=await this.getCodeActions(r,s,i?[i]:null);if(a=a.filter(c=>!c.disabled),!a||a.length==0){k.showMessage(`No${i?" "+i:""} code action available`,"warning");return}let l=await k.showMenuPicker(a.map(c=>c.title),"Choose action"),u=a[l];u&&await this.applyCodeAction(u)}async organizeImport(e){let{doc:t}=await this.handler.getCurrentState();if(e&&t.bufnr!=e)return;await t.synchronize();let i=await this.getCodeActions(t,void 0,[Mh.CodeActionKind.SourceOrganizeImports]);if(i&&i.length){await this.applyCodeAction(i[0]);return}throw new Error("Organize import action not found.")}async getCodeActions(e,t,i){t=t||Mh.Range.create(0,0,e.lineCount,0);let o={diagnostics:Ft.getDiagnosticsInRange(e.textDocument,t)};i&&Array.isArray(i)&&(o.only=i);let s=await this.handler.withRequestToken("code action",a=>A.getCodeActions(e.textDocument,t,o,a));return!s||s.length==0?[]:(s.sort((a,l)=>a.isPreferred&&!l.isPreferred?-1:l.isPreferred&&!a.isPreferred||a.disabled&&!l.disabled?1:l.disabled&&!a.disabled?-1:0),s)}get floatActions(){return y.floatSupported?y.getConfiguration("coc.preferences").get("floatActions",!0):!1}async doCodeAction(e,t){let{doc:i}=await this.handler.getCurrentState(),r;e&&(r=await k.getSelectedRange(e)),await i.synchronize();let o=await this.getCodeActions(i,r,Array.isArray(t)?t:null);if(typeof t=="string"?o=o.filter(l=>l.title==t||l.command&&l.command.title==t):Array.isArray(t)&&(o=o.filter(l=>t.some(u=>l.kind&&l.kind.startsWith(u)))),!o||o.length==0){k.showMessage(`No${t?" "+t:""} code action available`,"warning");return}if(t&&o.length==1&&!o[0].disabled){await this.applyCodeAction(o[0]);return}this.floatActions||(o=o.filter(l=>!l.disabled));let s=this.floatActions?await k.showMenuPicker(o.map(l=>({text:l.title,disabled:l.disabled})),"Choose action"):await k.showQuickpick(o.map(l=>l.title)),a=o[s];a&&await this.applyCodeAction(a)}async getCurrentCodeActions(e,t){let{doc:i}=await this.handler.getCurrentState(),r;return e&&(r=await k.getSelectedRange(e)),(await this.getCodeActions(i,r,t)).filter(s=>!s.disabled)}async doQuickfix(){let e=await this.getCurrentCodeActions("line",[Mh.CodeActionKind.QuickFix]);if(!e||e.length==0)throw new Error("No quickfix action available");await this.applyCodeAction(e[0]),this.nvim.command('silent! call repeat#set("\\(coc-fix-current)", -1)',!0)}async applyCodeAction(e){if(e.disabled)throw new Error(`Action "${e.title}" is disabled: ${e.disabled.reason}`);if(!e.providerId)throw new Error("providerId not found with codeAction");let t=await this.handler.withRequestToken("resolve codeAction",o=>A.resolveCodeAction(e,o)),{edit:i,command:r}=t;i&&await y.applyEdit(i),r&&await oe.execute(r)}};le();z();V();var vte=C(Ei()),lR=C(H());wi();Ce();ke();V();var Ait=q()("codelens-buffer"),ZD=class{constructor(e,t,i){this.nvim=e;this.document=t;this.config=i;this.resolveCodeLens=(0,vte.default)(()=>{this._resolveCodeLenses()},global.__TEST__?20:200),this.fetchCodeLenses()}get bufnr(){return this.document.bufnr}onChange(e){e.contentChanges.length===0&&this.codeLenses!=null?this._resolveCodeLenses():(this.cancel(),this.fetchCodeLenses())}get currentCodeLens(){var e;return(e=this.codeLenses)==null?void 0:e.codeLenses}get enabled(){var e;return(e=this.document)!=null&&e.attached?this.config.enabled&&A.hasProvider("codeLens",this.document.textDocument):!1}async forceFetch(){!this.enabled||(await this.document.synchronize(),this.cancel(),await this.fetchCodeLenses())}async fetchCodeLenses(){var t;if(!this.enabled)return;if(this.cancel(),!(((t=this.codeLenses)==null?void 0:t.version)==this.document.version)){let{textDocument:i}=this.document,r=i.version,s=(this.tokenSource=new lR.CancellationTokenSource).token,a=await A.getCodeLens(i,s);if(a=Array.isArray(a)?a.filter(l=>l!=null):[],this.tokenSource=void 0,s.isCancellationRequested||a.length==0)return;this.codeLenses={version:r,codeLenses:a}}await this._resolveCodeLenses()}async _resolveCodeLenses(){if(!this.enabled||!this.codeLenses||this.isChanged||!y.has("nvim-0.4.0"))return;let{codeLenses:e}=this.codeLenses,[t,i,r]=await this.nvim.eval("[bufnr('%'),line('w0'),line('w$')]");if(!(this.isChanged||t!=this.bufnr)){if(this.resolveTokenSource&&this.resolveTokenSource.cancel(),e=e.filter(o=>{let s=o.range.start.line+1;return s>=i&&s<=r}),e.length){let s=(this.resolveTokenSource=new lR.CancellationTokenSource).token;if(await Promise.all(e.map(a=>A.resolveCodeLens(a,s))),this.resolveTokenSource=void 0,s.isCancellationRequested||this.isChanged)return}this.nvim.pauseNotification(),this.clear(i-1,r),this.setVirtualText(e),this.nvim.resumeNotification(!1,!0)}}get isChanged(){if(!this.codeLenses||this.document.dirty)return!0;let{version:e}=this.codeLenses;return this.document.textDocument.version!==e}setVirtualText(e){let{document:t}=this;if(!t||!e.length)return;let i=new Map,{position:r}=this.config;for(let o of e){let{range:s,command:a}=o;if(!a)continue;let{line:l}=s.start;i.has(l)?i.get(l).push(o):i.set(l,[o])}for(let o of i.keys()){let a=i.get(o).map(h=>h.command);a=a.filter(h=>h&&h.title);let l=[],u=a.length;for(let h=0;h0&&l.unshift([g,"Normal"]),h.setExtMark(c,o,0,{virt_lines:[l],virt_lines_above:!0})}else h.setExtMark(c,o,0,{hl_mode:"combine",virt_text:l,virt_text_pos:r})}else this.nvim.call("nvim_buf_set_virtual_text",[this.bufnr,c,o,l,{}],!0)}}clear(e=0,t=-1){let{srcId:i}=this.config;if(!i)return;this.nvim.createBuffer(this.bufnr).clearNamespace(i,e,t)}async doAction(e){var i;let t=xTe(e,(i=this.codeLenses)==null?void 0:i.codeLenses);if(t.length==1)await oe.execute(t[0]);else if(t.length>1){let r=await k.showMenuPicker(t.map(o=>o.title));r!=-1&&await oe.execute(t[r])}}cancel(){this.resolveCodeLens.clear(),this.resolveTokenSource&&(this.resolveTokenSource.cancel(),this.resolveTokenSource.dispose(),this.resolveTokenSource=null),this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null)}dispose(){this.cancel(),this.codeLenses=void 0}};function xTe(n,e){if(!(e!=null&&e.length))return[];let t=[];for(let i of e){let{range:r,command:o}=i;!o||n==r.start.line&&t.push(o)}return t}var Yit=q()("codelens"),JD=class{constructor(e){this.nvim=e;this.disposables=[];this.setConfiguration(),this.nvim.createNamespace("coc-codelens").then(t=>{this.config.srcId=t}).logError(),y.onDidChangeConfiguration(this.setConfiguration,this,this.disposables),this.buffers=y.registerBufferSync(t=>{if(t.buftype=="")return new ZD(e,t,this.config)}),this.disposables.push(this.buffers),this.listen()}listen(){E.on("CursorMoved",e=>{let t=this.buffers.getItem(e);t&&t.resolveCodeLens()},null,this.disposables),E.on("CursorHold",async e=>{let t=this.buffers.getItem(e);t&&await t.forceFetch()},this,this.disposables)}async checkProvider(){for(let e of this.buffers.items)await e.forceFetch()}setConfiguration(e){if(e&&!e.affectsConfiguration("codeLens"))return;let t=y.getConfiguration("codeLens"),i=this.nvim.hasFunction("nvim_buf_set_virtual_text")&&t.get("enable",!1);this.config=Object.assign(this.config||{},{enabled:i,position:t.get("position","top"),separator:t.get("separator","\u2023"),subseparator:t.get("subseparator"," ")})}async doAction(){let[e,t]=await this.nvim.eval('[bufnr("%"),line(".")-1]'),i=this.buffers.getItem(e);await(i==null?void 0:i.doAction(t))}dispose(){Z(this.disposables)}};var Ste=C(H());wi();bo();Ce();z();function uR(n){return n.length==1?`0${n}`:n}function hp(n){let e=CTe(n);return`${uR(e.red.toString(16))}${uR(e.green.toString(16))}${uR(e.blue.toString(16))}`}function CTe(n){let{red:e,green:t,blue:i}=n;return{red:Math.round(e*255),green:Math.round(t*255),blue:Math.round(i*255)}}function wte(n){let e=[n.red,n.green,n.blue],t=[];for(let r=0;r{this.doHighlight().logError()},global.hasOwnProperty("__TEST__")?10:300),this.highlight()}get enabled(){let{filetypes:e}=this.config,t=y.getDocument(this.bufnr);return t?e.includes("*")?!0:A.hasProvider("documentColor",t.textDocument)?e.includes(t.filetype):!1:!1}onChange(){this.cancel(),this.highlight()}get buffer(){return this.nvim.createBuffer(this.bufnr)}get colors(){return this._colors}hasColor(){return this._colors.length>0}async doHighlight(){if(!this.enabled)return;let{nvim:e}=this,t=y.getDocument(this.bufnr);this.tokenSource=new Cte.CancellationTokenSource;let{token:i}=this.tokenSource,r;if(r=await A.provideDocumentColors(t.textDocument,i),i.isCancellationRequested)return;r=r||[],r.sort((a,l)=>De(a.range.start,l.range.start)),this._colors=r;let o=[];r.forEach(a=>{let l=STe(a.color);t.addHighlights(o,l,a.range,{combine:!1})});let s=await k.diffHighlights(this.bufnr,Dte,o);i.isCancellationRequested||!s||(e.pauseNotification(),this.defineColors(r),e.resumeNotification(!1,!0),await k.applyDiffHighlights(this.bufnr,Dte,this.config.highlightPriority,s,!0))}defineColors(e){for(let t of e){let i=hp(t.color);this.usedColors.has(i)||(this.nvim.command(`hi BG${i} guibg=#${i} guifg=#${wte(t.color)?"ffffff":"000000"}`,!0),this.usedColors.add(i))}}hasColorAtPosition(e){return this.colors.some(t=>ut(e,t.range)==0)}clearHighlight(){this.highlight.clear(),this._colors=[],this.buffer.clearNamespace("color")}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null)}dispose(){this._colors=[],this.highlight.clear(),this.cancel()}};function STe(n){return`BG${hp(n)}`}var fnt=q()("colors-index"),XD=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.setConfiguration();let i=new Set;this.highlighters=y.registerBufferSync(r=>new $D(this.nvim,r.bufnr,this.config,i)),ye.onDidActiveExtension(()=>{this.highlightAll()},null,this.disposables),y.onDidChangeConfiguration(this.setConfiguration,this,this.disposables),this.disposables.push(oe.registerCommand("editor.action.pickColor",()=>this.pickColor())),oe.titles.set("editor.action.pickColor","pick color from system color picker when possible."),this.disposables.push(oe.registerCommand("editor.action.colorPresentation",()=>this.pickPresentation())),oe.titles.set("editor.action.colorPresentation","change color presentation.")}setConfiguration(e){if(!e||e.affectsConfiguration("colors")){let t=y.getConfiguration("colors");this.config=Object.assign(this.config||{},{filetypes:t.get("filetypes",[]),highlightPriority:t.get("highlightPriority",1e3)})}}async pickPresentation(){let{doc:e}=await this.handler.getCurrentState();this.handler.checkProvier("documentColor",e.textDocument);let t=await this.getColorInformation(e.bufnr);if(!t)return k.showMessage("Color not found at current position","warning");let i=new Ste.CancellationTokenSource,r=await A.provideColorPresentations(t,e.textDocument,i.token);if(!(r!=null&&r.length))return;let o=await k.showMenuPicker(r.map(c=>c.label),"choose color:");if(o==-1)return;let s=r[o],{textEdit:a,additionalTextEdits:l,label:u}=s;a||(a={range:t.range,newText:u}),await e.applyEdits([a]),l&&await e.applyEdits(l)}async pickColor(){let{doc:e}=await this.handler.getCurrentState();this.handler.checkProvier("documentColor",e.textDocument);let t=await this.getColorInformation(e.bufnr);if(!t)return k.showMessage("Color not found at current position","warning");let{color:i}=t,r=[(i.red*255).toFixed(0),(i.green*255).toFixed(0),(i.blue*255).toFixed(0)],o=await this.nvim.call("coc#color#pick_color",[r]);if(!o)return;let s=hp({red:o[0]/65535,green:o[1]/65535,blue:o[2]/65535,alpha:1});await e.applyEdits([{range:t.range,newText:`#${s}`}])}isEnabled(e){let t=this.highlighters.getItem(e);return t!=null&&t.enabled===!0}clearHighlight(e){let t=this.highlighters.getItem(e);t&&t.clearHighlight()}hasColor(e){let t=this.highlighters.getItem(e);return t?t.hasColor():!1}hasColorAtPosition(e,t){let i=this.highlighters.getItem(e);return i?i.hasColorAtPosition(t):!1}highlightAll(){for(let e of this.highlighters.items)e.highlight()}async doHighlight(e){let t=this.highlighters.getItem(e);t&&await t.doHighlight()}async getColorInformation(e){let t=this.highlighters.getItem(e);if(!t)return null;let i=await k.getCursorPosition();for(let r of t.colors){let{range:o}=r,{start:s,end:a}=o;if(i.line==s.line&&i.character>=s.character&&i.character<=a.character)return r}return null}dispose(){this.highlighters.dispose(),Z(this.disposables)}};wi();sD();var ynt=q()("handler-commands"),UD=class{constructor(e,t){this.nvim=e;this.env=t;for(let i of t.vimCommands)this.addVimCommand(i)}addVimCommand(e){let t=`vim.${e.id}`;oe.registerCommand(t,()=>{this.nvim.command(e.cmd,!0),this.nvim.redrawVim()}),e.title&&oe.titles.set(t,e.title)}getCommandList(){return oe.commandList.map(e=>e.id)}async repeat(){await oe.repeatCommand()}async runCommand(e,...t){if(e)return await oe.fireCommand(e,...t);await Di.start(["commands"])}getCommands(){let e=oe.commandList,t=[],{titles:i}=oe;for(let r of e)t.push({id:r.id,title:i.get(r.id)||""});return t}};Ce();var GD=class{constructor(e,t){this.nvim=e;this.handler=t}async fold(e){let{doc:t,winid:i}=await this.handler.getCurrentState();this.handler.checkProvier("foldingRange",t.textDocument),await t.synchronize();let r=this.nvim.createWindow(i),o=await this.nvim.eval("&foldlevel"),s=await this.handler.withRequestToken("foldingrange",a=>A.provideFoldingRanges(t.textDocument,{},a),!0);if(!s||!s.length)return!1;e&&(s=s.filter(a=>a.kind==e)),s.sort((a,l)=>l.startLine-a.startLine),this.nvim.pauseNotification(),r.setOption("foldmethod","manual",!0),this.nvim.command("normal! zE",!0);for(let a of s){let{startLine:l,endLine:u}=a,c=`${l+1}, ${u+1}fold`;this.nvim.command(c,!0)}return r.setOption("foldenable",!0,!0),r.setOption("foldlevel",o,!0),await this.nvim.resumeNotification(!0),!0}};var ps=C(H());wi();le();Ce();iu();Pe();ke();V();var cR=q()("handler-format"),Tte=new Map([["<",">"],[">","<"],["{","}"],["[","]"],["(",")"]]),QD=class{constructor(e,t){this.nvim=e;this.handler=t;this.loadPreferences(),t.addDisposable(y.onDidChangeConfiguration(this.loadPreferences,this)),t.addDisposable(y.onWillSaveTextDocument(o=>{let{languageId:s}=o.document,a=this.preferences.formatOnSaveFiletypes;if(a.includes(s)||a.includes("*")){let l=async()=>{if(!A.hasFormatProvider(o.document)){cR.warn(`Format provider not found for ${o.document.uri}`);return}let u=await y.getFormatOptions(o.document.uri),c=new ps.CancellationTokenSource,h,d=new Promise(p=>{h=setTimeout(()=>{cR.warn(`Format on save ${o.document.uri} timeout after 0.5s`),c.cancel(),p(void 0)},500)}),g=A.provideDocumentFormattingEdits(o.document,u,c.token),f=await Promise.race([d,g]);return clearTimeout(h),Array.isArray(f)?f:void 0};o.waitUntil(l())}}));let i,r;t.addDisposable(E.on("Enter",async o=>{i=Date.now(),r=o})),t.addDisposable(E.on("CursorMovedI",async o=>{o==r&&Date.now()-i<100&&(r=void 0,await this.handleEnter(o))})),t.addDisposable(E.on("TextInsert",async(o,s,a)=>{E.pumvisible||await this.tryFormatOnType(a,o)})),t.addDisposable(oe.registerCommand("editor.action.formatDocument",async o=>{let s=o?y.getDocument(o):(await this.handler.getCurrentState()).doc;await this.documentFormat(s)})),oe.titles.set("editor.action.formatDocument","Format Document")}loadPreferences(e){if(!e||e.affectsConfiguration("coc.preferences")){let t=y.getConfiguration("coc.preferences");this.preferences={formatOnType:t.get("formatOnType",!1),formatOnSaveFiletypes:t.get("formatOnSaveFiletypes",[]),formatOnTypeFiletypes:t.get("formatOnTypeFiletypes",[]),bracketEnterImprove:t.get("bracketEnterImprove",!0)}}}async tryFormatOnType(e,t,i=!1){if(!e||hc(e)||!this.preferences.formatOnType||Ut.getSession(t)!=null)return;let r=y.getDocument(t);if(!r||!r.attached||r.isCommandLine)return;let o=this.preferences.formatOnTypeFiletypes;if(o.length&&!o.includes(r.filetype)&&!o.includes("*"))return;if(!A.hasProvider("formatOnType",r.textDocument)){cR.warn(`Format on type provider not found for buffer: ${r.uri}`);return}if(!A.canFormatOnType(e,r.textDocument))return;let s,a=await this.handler.withRequestToken("Format on type",async l=>{s=await k.getCursorPosition();let u=r.getline(s.line-1);if(!(i&&/^\s*$/.test(u)))return await r.synchronize(),await A.provideDocumentOnTypeEdits(e,r.textDocument,s,l)});!a||!a.length||await r.applyEdits(a,!1,!0)}async formatCurrentBuffer(){let{doc:e}=await this.handler.getCurrentState();return await this.documentFormat(e)}async formatCurrentRange(e){let{doc:t}=await this.handler.getCurrentState();return await this.documentRangeFormat(t,e)}async documentFormat(e){if(await e.synchronize(),!A.hasFormatProvider(e.textDocument))throw new Error(`Format provider not found for buffer: ${e.bufnr}`);let t=await y.getFormatOptions(e.uri),i=await this.handler.withRequestToken("format",r=>A.provideDocumentFormattingEdits(e.textDocument,t,r));return i&&i.length>0?(await e.applyEdits(i,!1,!0),!0):!1}async handleEnter(e){let{nvim:t}=this,{bracketEnterImprove:i}=this.preferences;if(await this.tryFormatOnType(` -`,e),i){let r=await t.call("line",".")-1,o=y.getDocument(e);if(!o)return;await o.patchChange();let s=o.getline(r-1),a=o.getline(r),l=s[s.length-1];if(l&&Tte.has(l)){let u=a.trim()[0];if(u&&Tte.get(l)==u){let c=[],h=await y.getFormatOptions(o.uri),d=h.insertSpaces?" ".repeat(h.tabSize):" ",g=a.match(/^\s*/)[0],f=ps.Position.create(r-1,s.length);if(o.filetype=="vim"){let p=` -`+g+d;c.push({range:ps.Range.create(r,g.length,r,g.length),newText:" \\ "}),p=p+"\\ ",c.push({range:ps.Range.create(f,f),newText:p}),await o.applyEdits(c),await k.moveTo(ps.Position.create(r,p.length-1))}else await t.eval(`feedkeys("\\O", 'in')`)}}}}async documentRangeFormat(e,t){this.handler.checkProvier("formatRange",e.textDocument),await e.synchronize();let i;if(t){if(i=await k.getSelectedRange(t),!i)return-1}else{let[s,a,l]=await this.nvim.eval("[v:lnum,v:count,mode()]");if(a==0||l=="i"||l=="R")return-1;i=ps.Range.create(s-1,0,s-1+a,0)}let r=await y.getFormatOptions(e.uri),o=await this.handler.withRequestToken("Format range",s=>A.provideDocumentRangeFormattingEdits(e.textDocument,i,r,s));return o&&o.length>0?(await e.applyEdits(o,!1,!0),0):-1}};var uu=C(H());le();Ce();z();V();var Nnt=q()("documentHighlight"),KD=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.highlights=new Map;E.on(["CursorMoved","CursorMovedI"],()=>{this.cancel(),this.clearHighlights()},null,this.disposables),this.getConfiguration(),y.onDidChangeConfiguration(this.getConfiguration,this,this.disposables)}getConfiguration(e){let t=y.getConfiguration("documentHighlight");(!e||e.affectsConfiguration("documentHighlight"))&&(this.config=Object.assign(this.config||{},{priority:t.get("priority",-1),timeout:t.get("timeout",300)}))}isEnabled(e,t){let i=y.getDocument(e);return!(!i||!i.attached||t||!A.hasProvider("documentHighlight",i.textDocument))}clearHighlights(){if(this.highlights.size!=0){for(let e of this.highlights.keys())this.nvim.createWindow(e).clearMatchGroup("^CocHighlight");this.highlights.clear()}}async highlight(){let{nvim:e}=this;this.cancel();let[t,i,r,o]=await e.eval(`[bufnr("%"),win_getid(),coc#cursor#position(),get(b:,'coc_cursors_activated',0)]`);if(!this.isEnabled(t,o))return;let s=y.getDocument(t),a=await this.getHighlights(s,uu.Position.create(r[0],r[1]));if(!a)return;let l={};for(let c of a){if(!c.range)continue;let h=c.kind==uu.DocumentHighlightKind.Text?"CocHighlightText":c.kind==uu.DocumentHighlightKind.Read?"CocHighlightRead":"CocHighlightWrite";l[h]=l[h]||[],l[h].push(c.range)}let u=e.createWindow(i);e.pauseNotification(),u.clearMatchGroup("^CocHighlight");for(let c of Object.keys(l))u.highlightRanges(c,l[c],this.config.priority,!0);e.resumeNotification(!0,!0),this.highlights.set(i,a)}async getSymbolsRanges(){let{doc:e,position:t}=await this.handler.getCurrentState();this.handler.checkProvier("documentHighlight",e.textDocument);let i=await this.getHighlights(e,t);return i?i.map(r=>r.range):null}hasHighlights(e){return this.highlights.get(e)!=null}async getHighlights(e,t){let r=e.getline(t.line)[t.character];if(!r||!e.isWord(r))return null;await e.synchronize(),this.cancel();let o=this.tokenSource=new uu.CancellationTokenSource,s=this.timer=setTimeout(()=>{o.token.isCancellationRequested||o.cancel()},this.config.timeout),a=await A.getDocumentHighLight(e.textDocument,t,o.token);return clearTimeout(s),o.token.isCancellationRequested?null:a}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null)}dispose(){this.timer&&clearTimeout(this.timer),this.cancel(),this.highlights.clear(),Z(this.disposables)}};var kte=C(require("fs")),ms=C(H());we();Ce();Zo();z();Je();V();var Unt=q()("handler-hover"),zD=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.documentLines=[];this.hasProvider=!1;this.excludeImages=!0;this.loadConfiguration(),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),this.hoverFactory=new ci(e),this.disposables.push(this.hoverFactory)}registerProvider(){if(this.hasProvider)return;this.hasProvider=!0;let{nvim:e}=this,t={onDidChange:null,provideTextDocumentContent:async()=>(e.pauseNotification(),e.command("setlocal conceallevel=2 nospell nofoldenable wrap",!0),e.command("setlocal bufhidden=wipe nobuflisted",!0),e.command("setfiletype markdown",!0),e.command(`if winnr('j') != winnr('k') | exe "normal! z${Math.min(this.documentLines.length,this.config.previewMaxHeight)}\\ | endif"`,!0),await e.resumeNotification(),this.documentLines.join(` -`))};this.disposables.push(y.registerTextDocumentContentProvider("coc",t))}loadConfiguration(e){if(!e||e.affectsConfiguration("hover")){let t=y.getConfiguration("hover"),i=t.get("target","float");this.config={floatConfig:t.get("floatConfig",{}),autoHide:t.get("autoHide",!0),target:i=="float"&&!y.floatSupported?"preview":i,previewMaxHeight:t.get("previewMaxHeight",12)},this.config.target=="preview"&&this.registerProvider();let r=y.getConfiguration("coc.preferences");this.excludeImages=r.get("excludeImageLinksInMarkdownDocument",!0)}}async onHover(e){let{doc:t,position:i,winid:r}=await this.handler.getCurrentState();e=="preview"&&this.registerProvider(),this.handler.checkProvier("hover",t.textDocument),await t.synchronize();let o=await this.handler.withRequestToken("hover",a=>A.getHover(t.textDocument,i,a),!0);if(o==null||!o.length)return!1;let s=o.find(a=>ms.Range.is(a.range));if(s!=null&&s.range){let a=this.nvim.createWindow(r);a.highlightRanges("CocHoverRange",[s.range],99,!0),this.timer=setTimeout(()=>{a.clearMatchGroup("CocHoverRange"),this.nvim.redrawVim()},500)}return await this.previewHover(o,e),!0}async definitionHover(e){let{doc:t,position:i}=await this.handler.getCurrentState();e=="preview"&&this.registerProvider(),this.handler.checkProvier("hover",t.textDocument),await t.synchronize();let r=await this.handler.withRequestToken("hover",s=>A.getHover(t.textDocument,i,s),!0);if(!(r!=null&&r.length))return!1;let o=await this.handler.withRequestToken("definitionHover",s=>A.getDefinitionLinks(t.textDocument,i,s),!1);if(o!=null&&o.length)for(let s of o){if(!s.targetRange)continue;let{start:a,end:l}=s.targetRange,u=l.line-a.line>=100?a.line+100:l.character==0?l.line-1:l.line,c=await kTe(s.targetUri,a.line,u);if(c.length){let h=c[0].match(/^\s*/)[0];h&&(c=c.map(d=>d.startsWith(h)?d.substring(h.length):d)),r.push({content:c.join(` -`),filetype:t.filetype})}}return await this.previewHover(r,e),!0}async previewHover(e,t){let i=[];t=t||this.config.target;let r=t==="preview";for(let s of e){if(TTe(s)){i.push(s);continue}let{contents:a}=s;if(Array.isArray(a))for(let l of a)typeof l=="string"?dp(i,l,"markdown",r):dp(i,l.value,l.language,r);else ms.MarkedString.is(a)?typeof a=="string"?dp(i,a,"markdown",r):dp(i,a.value,a.language,r):ms.MarkupContent.is(a)&&dp(i,a.value,og(a)?"markdown":"txt",r)}if(t=="float"){let s=this.hoverFactory.applyFloatConfig({modes:["n"],autoHide:this.config.autoHide,excludeImages:this.excludeImages,maxWidth:80},this.config.floatConfig);await this.hoverFactory.show(i,s);return}let o=i.reduce((s,a)=>{let l=a.content.split(/\r?\n/);return s.length>0&&s.push(""),s.push(...l),s},[]);if(t=="echo"){let s=o.join(` -`).trim();await this.nvim.call("coc#ui#echo_hover",[s])}else this.documentLines=o,await this.nvim.command("noswapfile pedit coc://document")}async getHover(){let e=[],{doc:t,position:i}=await this.handler.getCurrentState();this.handler.checkProvier("hover",t.textDocument),await t.synchronize();let r=new ms.CancellationTokenSource,o=await A.getHover(t.textDocument,i,r.token);if(Array.isArray(o))for(let s of o){let{contents:a}=s;Array.isArray(a)?a.forEach(l=>{e.push(typeof l=="string"?l:l.value)}):ms.MarkupContent.is(a)?e.push(a.value):e.push(typeof a=="string"?a:a.value)}return e=e.filter(s=>s!=null&&s.length>0),e}dispose(){this.timer&&clearTimeout(this.timer),Z(this.disposables)}};function dp(n,e,t,i=!1){let r=e.trim();!r.length||(i&&t!=="markdown"&&(r="``` "+t+` -`+r+"\n```"),n.push({content:r,filetype:t}))}function TTe(n){return n?typeof n.filetype=="string"&&typeof n.content=="string":!1}async function kTe(n,e,t){let i=y.getDocument(n);if(i)return i.getLines(e,t+1);let r=O.parse(n).fsPath;return kte.default.existsSync(r)?await ia(r,e,t):[]}var cu=C(H());le();Ce();Zo();z();yt();ke();V();var rrt=q()("handler-links"),ETe=/CocAction(Async)?\(["']openLink["']\)/,VD=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.setConfiguration(),y.onDidChangeConfiguration(this.setConfiguration,this,this.disposables),this.floatFactory=new ci(e),E.on("CursorHold",async()=>{!this._tooltip||!e.hasFunction("nvim_get_keymap")||await this.showTooltip()},null,this.disposables),E.on(["CursorMoved","InsertEnter"],()=>{this.cancel()},null,this.disposables)}setConfiguration(e){if(!e||e.affectsConfiguration("links")){let t=y.getConfiguration("links");this._tooltip=t.get("tooltip",!1)}}async showTooltip(){let{nvim:e,floatFactory:t}=this,r=(await e.getKeymap("n")).find(u=>ETe.test(u.rhs)),o=r?r.lhs:void 0,s=await this.getCurrentLink();if(!s||!s.target)return;let a="";if(s.tooltip&&(a=s.tooltip+" "),o&&(a+=`Press "${o}" to open link`),!a.length)return;let l={content:a,filetype:"txt"};await t.show([l],{autoHide:!0})}async getLinks(){try{let{doc:e}=await this.handler.getCurrentState();if(!A.hasProvider("documentLink",e.textDocument))return[];let t=this.tokenSource=new cu.CancellationTokenSource,i=await A.getDocumentLinks(e.textDocument,t.token);return t.token.isCancellationRequested?[]:i}catch{return[]}}async openLink(e){if(!e.target)throw new Error("Failed to resolve link target");await y.openResource(e.target)}async getCurrentLink(){let e=await this.getLinks(),t=await k.getCursorPosition();if(e&&e.length){for(let a of e)if(ut(t,a.range)==0){if(!a.target){let l=this.tokenSource=this.tokenSource||new cu.CancellationTokenSource;if(a=await A.resolveDocumentLink(a,this.tokenSource.token),!a.target||l.token.isCancellationRequested)continue}return a}}let i=await this.nvim.call("getline",["."]),r=/\w+?:\/\/[^)\]'" ]+/g,o,s;for(;(o=r.exec(i))!==null;){let a=o.index;if(a<=t.character&&a+o[0].length>=t.character){s=cu.DocumentLink.create(cu.Range.create(t.line,a,t.line,a+o[0].length),o[0]);break}}return s}async openCurrentLink(){let e=await this.getCurrentLink();return e?(await this.openLink(e),!0):!1}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource=null)}dispose(){var e;(e=this.floatFactory)==null||e.dispose(),Z(this.disposables)}};var Yr=C(H());we();Ce();$f();V();var grt=q()("handler-hover"),ex=class{constructor(e,t){this.nvim=e;this.handler=t}async request(e,t){let{doc:i,position:r}=await this.handler.getCurrentState();return this.handler.checkProvier(e,i.textDocument),await i.synchronize(),await this.handler.withRequestToken(e,o=>t(i.textDocument,r,o),!0)}async definitions(){let{doc:e,position:t}=await this.handler.getCurrentState();this.handler.checkProvier("definition",e.textDocument),await e.synchronize();let i=new Yr.CancellationTokenSource;return A.getDefinition(e.textDocument,t,i.token)}async declarations(){let{doc:e,position:t}=await this.handler.getCurrentState();this.handler.checkProvier("declaration",e.textDocument),await e.synchronize();let i=new Yr.CancellationTokenSource;return A.getDeclaration(e.textDocument,t,i.token)}async typeDefinitions(){let{doc:e,position:t}=await this.handler.getCurrentState();this.handler.checkProvier("typeDefinition",e.textDocument),await e.synchronize();let i=new Yr.CancellationTokenSource;return A.getTypeDefinition(e.textDocument,t,i.token)}async implementations(){let{doc:e,position:t}=await this.handler.getCurrentState();this.handler.checkProvier("implementation",e.textDocument),await e.synchronize();let i=new Yr.CancellationTokenSource;return A.getImplementation(e.textDocument,t,i.token)}async references(e){let{doc:t,position:i}=await this.handler.getCurrentState();this.handler.checkProvier("reference",t.textDocument),await t.synchronize();let r=new Yr.CancellationTokenSource;return A.getReferences(t.textDocument,{includeDeclaration:!e},i,r.token)}async gotoDefinition(e){let t=await this.request("definition",(i,r,o)=>A.getDefinition(i,r,o));return await this.handleLocations(t,e),t?t.length>0:!1}async gotoDeclaration(e){let t=await this.request("declaration",(i,r,o)=>A.getDeclaration(i,r,o));return await this.handleLocations(t,e),t?Array.isArray(t)?t.length>0:!0:!1}async gotoTypeDefinition(e){let t=await this.request("typeDefinition",(i,r,o)=>A.getTypeDefinition(i,r,o));return await this.handleLocations(t,e),t?t.length>0:!1}async gotoImplementation(e){let t=await this.request("implementation",(i,r,o)=>A.getImplementation(i,r,o));return await this.handleLocations(t,e),t?t.length>0:!1}async gotoReferences(e,t=!0){let i=await this.request("reference",(r,o,s)=>A.getReferences(r,{includeDeclaration:t},o,s));return await this.handleLocations(i,e),i?i.length>0:!1}async getTagList(){let{doc:e,position:t}=await this.handler.getCurrentState(),i=await this.nvim.call("expand","");if(!i||!A.hasProvider("definition",e.textDocument))return null;let r=new Yr.CancellationTokenSource,o=await A.getDefinition(e.textDocument,t,r.token);return!o||!o.length?null:o.map(s=>{let a=O.parse(s.uri),l=a.scheme=="file"?a.fsPath:a.toString();return{name:i,cmd:`keepjumps ${s.range.start.line+1} | normal ${s.range.start.character+1}|`,filename:l}})}async findLocations(e,t,i,r){let{doc:o,position:s}=await this.handler.getCurrentState();i=i||{},Object.assign(i,{textDocument:{uri:o.uri},position:s});let a=await Mi.sendRequest(e,t,i);a=a||[];let l=[];if(Array.isArray(a))l=a;else if(a.hasOwnProperty("location")&&a.hasOwnProperty("children")){let u=c=>{if(l.push(c.location),c.children&&c.children.length)for(let h of c.children)u(h)};u(a)}return await this.handleLocations(l,r),l?l.length>0:!1}async handleLocations(e,t){if(!e)return;let i=Array.isArray(e)?e:[e];i=i.map(o=>Yr.LocationLink.is(o)?Yr.Location.create(o.targetUri,o.targetRange):o);let r=i.length;if(r!=0)if(r==1&&t!==!1){let{uri:o,range:s}=i[0];await y.jumpTo(o,s.start,t)}else await y.showLocations(i)}dispose(){}};var Bh=C(H());we();le();Ce();z();Je();jr();V();var Nh=C(Lg()),gp=C(require("path")),Ge=C(H());Ec();we();oa();z();Je();Vo();io();Jt();yt();Pe();jr();ke();V();Jt();var tx=class{constructor(){this.stack=[]}add(e){let t=new Map;for(let i of e)t.set(i.lnum,i);this.stack.push(t)}checkInsert(e){if(!this.stack.length)return;let t=this.stack[this.stack.length-1],i=Array.from(t.keys()).sort((r,o)=>r-o);if(!!Fe(i,e))return this.stack.pop(),Array.from(t.values())}};var PTe=q()("handler-refactorBuffer"),Wr="\u3000",ix=class{constructor(e,t,i,r,o){this.bufnr=e;this.srcId=t;this.nvim=i;this.config=r;this.opts=o;this._disposed=!1;this._fileItems=[];this.mutex=new ei;this.disposables=[];this.matchIds=new Set;this.changing=!1;this.changes=new tx,this.disposables.push(y.registerLocalKeymap("n","",this.splitOpen.bind(this),!0)),r.showMenu&&this.disposables.push(y.registerLocalKeymap("n",r.showMenu,this.showMenu.bind(this),!0)),y.onDidChangeTextDocument(this.onDocumentChange,this,this.disposables)}async showMenu(){let e=await k.showMenuPicker(["Tab open","Remove block"]);if(e==-1)return;let t=await this.searchCurrentRange();if(!!t){if(e==0){let r=(await this.nvim.eval("strpart(getline('.'), 0 ,col('.') - 1)")).length,o=this.getAbsolutePath(t.filepath);this.nvim.call("coc#util#jump",["tabe",o,[t.line,r]],!0)}if(e==1){let i=this.getDeleteRange(t);await this.document.applyEdits([Ge.TextEdit.del(i)])}}}get fileItems(){return this._fileItems}getFileItem(e){let t=O.parse(e).fsPath;return this._fileItems.find(i=>ii(i.filepath,t))}getFileRange(e){for(let t of this._fileItems)for(let i of t.ranges)if(i.lnum==e)return Object.assign(zi(i,["highlights"]),{filepath:t.filepath});throw new Error(`File range not found at lnum: ${e}`)}onChange(e){if(this.changing)return;if(e.contentChanges.length===0){this.highlightLineNr(),this.nvim.redrawVim();return}let{nvim:t}=this;e=RTe(e);let i=e.contentChanges[0],{original:r}=e;i.range.end.line>2&&t.call("setbufvar",[e.bufnr,"&modified",1],!0);let{range:o,text:s}=i;if(ra(Ge.TextEdit.replace(o,s))==0)return;let l=[Ge.TextEdit.replace(o,s)],u=[];if(!Ct(o)&&!s.includes("\u3000")){let c=o.start.line,h=[],d=r.split(/\r?\n/);for(let g=0;g1&&f.includes("\u3000")&&h.push(c+g+1)}if(h.length){let g=h.map(f=>this.getFileRange(f));for(let f of this._fileItems)f.ranges=f.ranges.filter(p=>!h.includes(p.lnum));this.changes.add(g)}}else if(Ct(o)&&s.includes("\u3000")){let c=s.split(/\r?\n/),h=[],d=o.start.line;for(let g=0;g1&&f.includes("\u3000")&&h.push(d+g+1)}if(h.length){let g=this.changes.checkInsert(h);g&&(u=g)}}else s.includes("\u3000")&&(l=this.diffChanges(r,s),l.forEach(c=>{c.range=H2(c.range,o.start)}));this.adjustLnums(l),t.pauseNotification(),this.highlightLineNr(),t.resumeNotification(!0,!0),u.length&&u.forEach(c=>{this._fileItems.find(d=>d.filepath==c.filepath).ranges.push(c)})}diffChanges(e,t){let i=[],r=(0,Nh.default)(e,t),o=0,s=jn.create("file:///1","",0,e);for(let a=0;a=c.start+c.lines.length)continue;if(r.end.line!l.includes(c))),this._fileItems=this._fileItems.filter(u=>u.ranges&&u.ranges.length>0),a.length&&(this.adjustLnums(a),this.changing=!0,await this.document.applyEdits(a),this.changing=!1),this.nvim.pauseNotification(),this.highlightLineNr(),this.buffer.setOption("modified",!1,!0),await this.nvim.resumeNotification(!0)}adjustLnums(e){for(let t of this._fileItems)for(let i of t.ranges){let r=i.lnum-1;i.lnum+=UT(Ge.Position.create(r,0),e)}}async getFileChanges(){let e=[],t=await this.buffer.lines;t.push(Wr);let i=[],r,o;for(let s=0;s1){let l=a.match(/^\u3000(.*)/);l&&(r=this.getAbsolutePath(l[1].replace(/\s+$/,"")),o=s+1,i=[])}}else i.push(a)}return e}async splitOpen(){let{nvim:e}=this,i=await e.createWindow(this.opts.fromWinid).valid,o=(await e.eval("strpart(getline('.'), 0 ,col('.') - 1)")).length,s=await this.searchCurrentRange();if(s){let a=this.getAbsolutePath(s.filepath);e.pauseNotification(),i?(e.call("win_gotoid",[this.opts.fromWinid],!0),this.nvim.call("coc#util#jump",["edit",a,[s.line,o]],!0)):this.nvim.call("coc#util#jump",["belowright vs",a,[s.line,o]],!0),e.command("normal! zz",!0),await e.resumeNotification(!0),i||(this.opts.fromWinid=await e.call("win_getid"))}}async searchCurrentRange(){let{nvim:e}=this,t=await e.eval('getline(1,line("."))'),i=t.length;for(let r=0;r_Te(S,p)));let{lines:b,start:v,end:w,highlights:D}=d;b||(b=await this.getLines(c.filepath,v,w)),h.push({lines:b,lnum:g,start:v,highlights:D}),s.addLines(b)}if(h.length){let d={filepath:c.filepath,ranges:h},g=this._fileItems.find(f=>f.filepath==c.filepath);g?g.ranges.push(...d.ranges):this._fileItems.push(d)}}let{nvim:l,buffer:u}=this;if(this.changing=!0,l.pauseNotification(),s.render(u,o),this.highlightLineNr(),u.setOption("modified",!1,!0),u.setOption("undolevels",1e3,!0),o==2&&a.length){let c=a[0].start;l.call("coc#cursor#move_to",[c.line,c.character],!0)}await l.resumeNotification(!0),await i.patchChange(),this.changing=!1,await k.cursors.addRanges(a)}catch(o){this.changing=!1,PTe.error("Error on add file item:",o)}r()}findRange(e,t){let r=this.fileItems.find(o=>ii(this.getAbsolutePath(o.filepath),e)).ranges.find(o=>o.lnum==t);if(!r)throw new Error(`File range not found at lnum: ${t}`);return r}async save(){let{nvim:e}=this,t=this.document,{buffer:i}=t;await t.patchChange();let r=await this.getFileChanges();if(!r)return;r.sort((a,l)=>a.lnum-l.lnum);let o=[];for(let a=0;a0&&a.ranges.forEach(c=>{c.start+=UT(Ge.Position.create(c.start,0),u)})}return e.pauseNotification(),i.setOption("modified",!1,!0),this.config.saveToFile&&e.command("silent noa wa",!0),this.highlightLineNr(),await e.resumeNotification(),!0}async getLines(e,t,i){let r=O.file(e).toString(),o=y.getDocument(r);return o?o.getLines(t,i):await ia(e,t,i-1)}getAbsolutePath(e){return gp.default.isAbsolute(e)?e:gp.default.join(this.opts.cwd,e)}highlightLineNr(){let{fileItems:e,nvim:t,srcId:i,bufnr:r}=this,{winid:o,cwd:s}=this.opts,a={};if(i){t.call("nvim_buf_clear_namespace",[r,i,0,-1],!0);for(let l of e)for(let u of l.ranges){let c=u.start+u.lines.length,h=`${u.start+1}:${c}`;a[u.lnum]=[u.start+1,c],t.call("nvim_buf_set_virtual_text",[r,i,u.lnum-1,[[h,"LineNr"]],{}],!0)}}else{this.matchIds.size&&(t.call("coc#highlight#clear_matches",[o,Array.from(this.matchIds)],!0),this.matchIds.clear());let l=2e3;for(let u of e){let c=`${s?gp.default.relative(s,u.filepath):u.filepath}`,h=Q(c)+1;for(let d of u.ranges){let g=d.start+d.lines.length,f=`:${d.start+1}:${g}`;for(let p=0;p1?u[u.length-2]:"";if(c==""&&d.startsWith(Wr)&&h==d&&s.start.character==0&&s.end.character==0){r=h+` -`+u.slice(0,-2).join(` -`)+` -`;let{start:g,end:f}=s;l[0].range=Ge.Range.create(g.line-1,0,f.line-1,0)}}else if(Ct(s)&&s.start.character!=0){let u=a.split(/\r?\n/),c=u[u.length-1],h=o[s.start.line].slice(0,s.start.character);if(c.startsWith(Wr)&&h==c){l[0].text=h+u.slice(0,-1).join(` -`)+` -`;let{start:d,end:g}=s;l[0].range=Ge.Range.create(d.line,0,g.line,0)}}return{contentChanges:l,bufnr:t,textDocument:i,original:r,originalLines:o}}var Ete=require("child_process"),Pte=require("events"),hR=C(require("path")),_te=C(require("readline"));Qr();oa();bc();io();ke();var LTe=q()("handler-search"),FTe=["--color","ansi","--colors","path:fg:black","--colors","line:fg:green","--colors","match:fg:red","--no-messages","--heading","-n"],ITe="\x1B",Rte=class extends Pte.EventEmitter{start(e,t,i){this.process=(0,Ete.spawn)(e,t,{cwd:i}),this.process.on("error",c=>{this.emit("error",c.message)});let r=_te.default.createInterface(this.process.stdout),o,s,a=[],l=[],u=!0;r.on("line",c=>{if(c.includes(ITe)){let h=hg(c);if(h[0].foreground=="black"){s={filepath:hR.default.join(i,h[0].text),ranges:[]};return}if(h[0].foreground=="green"){let g=parseInt(h[0].text,10)-1,f=h[0].text.length+1;u&&(o=g,u=!1);let p="";for(let v of h){if(v.foreground=="red"){let w=g-o,D=p.length-f;l.push(Ne.create(w,D,w,D+v.text.length))}p+=v.text}let b=p.slice(f);a.push(b)}}else{let h=c.trim().length==0;s&&(h||c.trim()=="--")&&s.ranges.push({lines:a,highlights:l,start:o}),h&&(this.emit("item",s),s=null),a=[],l=[],u=!0}}),r.on("close",()=>{s&&(a.length&&s.ranges.push({lines:a,highlights:l,start:o}),this.emit("item",s)),a=l=s=null,this.emit("end")})}dispose(){this.process&&this.process.kill()}},nx=class{constructor(e,t="rg"){this.nvim=e;this.cmd=t}run(e,t,i){let{nvim:r,cmd:o}=this,{afterContext:s,beforeContext:a}=i.config,l=["-A",s.toString(),"-B",a.toString()].concat(FTe,e),u=jTe(e);u&&l.pop(),l.push("--",u?hR.default.isAbsolute(u)?u:`./${u.replace(/^\.\//,"")}`:"./"),this.task=new Rte,this.task.start(o,l,t);let c=new ei,h=0,d=0,g=Date.now(),f=[],p=async()=>{if(f.length==0)return;let b=f.slice();f=[];let v=await c.acquire();try{await i.addFileItems(b)}catch(w){LTe.error(w)}v()};return new Promise((b,v)=>{let w=setInterval(p,300);this.task.on("item",async D=>{h++,d=d+D.ranges.reduce((S,F)=>S+F.highlights.length,0),f.push(D)}),this.task.on("error",D=>{clearInterval(w),k.showMessage(`Error on command "${o}": ${D}`,"error"),this.task=null,v(new Error(D))}),this.task.on("end",async()=>{clearInterval(w);try{await p(),(await c.acquire())(),this.task.removeAllListeners(),this.task=null;let S=i.buffer;if(S){if(r.pauseNotification(),h==0)S.setLines(["No match found"],{start:1,end:2,strictIndexing:!1},!0),S.addHighlight({line:1,srcId:-1,colEnd:-1,colStart:0,hlGroup:"Error"}),S.setOption("modified",!1,!0);else{let F=new Ri;F.addText("Files","MoreMsg"),F.addText(": "),F.addText(`${h} `,"Number"),F.addText("Matches","MoreMsg"),F.addText(": "),F.addText(`${d} `,"Number"),F.addText("Duration","MoreMsg"),F.addText(": "),F.addText(`${Date.now()-g}ms`,"Number"),F.render(S,1,2)}S.setOption("modified",!1,!0),r.resumeNotification(!1,!0)}}catch(D){v(D);return}b()})})}abort(){var e;(e=this.task)==null||e.dispose()}};function jTe(n){if(n.length<2)return;let e=n.length;if(!n[e-1].startsWith("-")&&!n[e-2].startsWith("-"))return n[e-1]}var rot=q()("handler-refactor"),ATe="__coc_refactor__",OTe=0,rx=class{constructor(e,t){this.nvim=e;this.handler=t;this.buffers=new Map;this.disposables=[];this._onCreate=new Bh.Emitter;this.onCreate=this._onCreate.event;this.setConfiguration(),y.onDidChangeConfiguration(this.setConfiguration,this,this.disposables),E.on("BufUnload",i=>{let r=this.buffers.get(i);r&&(r.dispose(),this.buffers.delete(i))},null,this.disposables),y.onDidChangeTextDocument(i=>{let r=this.buffers.get(i.bufnr);r&&r.onChange(i)},null,this.disposables)}async init(){y.isNvim&&this.nvim.hasFunction("nvim_create_namespace")&&(this.srcId=await this.nvim.createNamespace("coc-refactor"))}has(e){return this.buffers.has(e)}setConfiguration(e){if(e&&!e.affectsConfiguration("refactor"))return;let t=y.getConfiguration("refactor");this.config=Object.assign(this.config||{},{afterContext:t.get("afterContext",3),beforeContext:t.get("beforeContext",3),openCommand:t.get("openCommand","edit"),saveToFile:t.get("saveToFile",!0),showMenu:t.get("showMenu","")})}async doRefactor(){let{doc:e,position:t}=await this.handler.getCurrentState();if(!A.hasProvider("rename",e.textDocument))throw new Error("Rename provider not found for current buffer");await e.synchronize();let i=await this.handler.withRequestToken("refactor",async r=>{let o=await A.prepareRename(e.textDocument,t,r);if(r.isCancellationRequested)return null;if(o===!1)throw new Error("Provider returns null on prepare, unable to rename at current position");let s=await A.provideRenameEdits(e.textDocument,t,"NewName",r);if(r.isCancellationRequested)return null;if(!s)throw new Error("Provider returns null for rename edits.");return s});i&&await this.fromWorkspaceEdit(i,e.filetype)}async search(e){let t=await this.createRefactorBuffer(),i=await this.nvim.call("getcwd",[]);await new nx(this.nvim).run(e,i,t)}async save(e){let t=this.buffers.get(e);if(t)return await t.save()}getBuffer(e){return this.buffers.get(e)}async createRefactorBuffer(e,t=!1){let{nvim:i}=this,[r,o]=await i.eval("[win_getid(),getcwd()]"),{openCommand:s}=this.config;i.pauseNotification(),i.command(`${s} ${ATe}${OTe++}`,!0),i.command("setl buftype=acwrite nobuflisted bufhidden=wipe nofen wrap conceallevel=2 concealcursor=n",!0),i.command("setl undolevels=-1 nolist nospell noswapfile foldmethod=expr foldexpr=coc#util#refactor_foldlevel(v:lnum)",!0),i.command("setl foldtext=coc#util#refactor_fold_text(v:foldstart)",!0),i.call("setline",[1,["Save current buffer to make changes",Wr]],!0),i.call("matchadd",["Comment","\\%1l"],!0),i.call("matchadd",["Conceal","^\\%u3000"],!0),i.call("matchadd",["Label","^\\%u3000\\zs\\S\\+"],!0),i.command("setl nomod",!0),e&&i.command(`runtime! syntax/${e}.vim`,!0),i.call("coc#util#do_autocmd",["CocRefactorOpen"],!0),await i.resumeNotification();let[a,l]=await i.eval('[bufnr("%"),win_getid()]'),u={fromWinid:r,winid:l,cwd:o};await y.document;let c=new ix(a,t?void 0:this.srcId,this.nvim,this.config,u);return this.buffers.set(a,c),c}async fromLines(e){let t=await this.createRefactorBuffer();return await t.buffer.setLines(e,{start:0,end:-1,strictIndexing:!1}),t}async fromLocations(e,t){if(!e||e.length==0)return;let i={},r={changes:i};for(let o of e){let s=i[o.uri]||[];s.push({range:o.range,newText:""}),i[o.uri]=s}return await this.fromWorkspaceEdit(r,t)}async fromWorkspaceEdit(e,t){if(!e||jY(e))return;let i=[],{beforeContext:r,afterContext:o}=this.config,{changes:s,documentChanges:a}=e;if(!s){s={};for(let u of a||[])if(Bh.TextDocumentEdit.is(u)){let{textDocument:c,edits:h}=u;s[c.uri]=h}}for(let u of Object.keys(s)){let c=await this.getLineCount(u),h=s[u],d=[],g=null,f=null,p=[];h.sort((b,v)=>b.range.start.line-v.range.start.line);for(let b of h){let{line:v}=b.range.start,w=Math.max(0,v-r);g!=null&&w({range:s,newText:r}))}}}async rename(e){let{doc:t,position:i}=await this.handler.getCurrentState();this.handler.checkProvier("rename",t.textDocument),await t.synchronize();let r=new fp.CancellationTokenSource().token,o=await A.prepareRename(t.textDocument,i,r);if(o===!1)return k.showWarningMessage("Invalid position for rename"),!1;let s;if(!e){fp.Range.is(o)?(s=t.textDocument.getText(o),await k.moveTo(o.start)):o&&typeof o.placeholder=="string"?s=o.placeholder:s=await this.nvim.eval('expand("")');let l=y.getConfiguration("coc.preferences");e=await k.requestInput("New name",l.get("renameFillCurrent",!0)?s:void 0)}if(e===""&&k.showWarningMessage("Empty word, rename canceled"),!e)return!1;let a=await A.provideRenameEdits(t.textDocument,i,e,r);return r.isCancellationRequested||!a?!1:(await y.applyEdit(a),this.nvim.redrawVim(),!0)}};we();var dR=C(require("fs")),Ite=C(require("path"));bo();Fr();V();iu();var Fte=q()("handler-workspace"),sx=class{constructor(e,t){this.nvim=e;this.handler=t}async openLog(){let e=Fte.logfile;await y.jumpTo(O.file(e).toString())}async doAutocmd(e,t){await y.autocmds.doAutocmd(e,t)}async getConfiguration(e){let t=await y.document;return y.getConfiguration(e,t?t.uri:void 0)}getRootPatterns(e){let t=y.getDocument(e);return t?{buffer:y.workspaceFolderControl.getRootPatterns(t,0),server:y.workspaceFolderControl.getRootPatterns(t,1)||[],global:y.workspaceFolderControl.getRootPatterns(t,2)}:null}async ensureDocument(){let e=await y.document;return e&&!e.isCommandLine&&e.attached}async doKeymap(e,t="",i){return await y.keymaps.doKeymap(e,t,i)}async snippetCheck(e,t){if(e&&!ye.has("coc-snippets"))return this.nvim.echoError("coc-snippets required for check expand status!"),!1;if(t&&Ut.jumpable())return!0;if(e){let i=ye.getExtensionApi("coc-snippets");if(i&&i.hasOwnProperty("expandable")&&await Promise.resolve(i.expandable()))return!0}return!1}async showInfo(){let e=[],t=y.version+"-2522eee5 2022-06-14 19:03:29 +0800";e.push("## versions"),e.push("");let r=(await this.nvim.call("execute",["version"])).trim().split(/\r?\n/,2)[0].replace(/\(.*\)/,"").trim();e.push("vim version: "+r+`${y.isVim?" "+y.env.version:""}`),e.push("node version: "+process.version),e.push("coc.nvim version: "+t),e.push("coc.nvim directory: "+Ite.default.dirname(__dirname)),e.push("term: "+(process.env.TERM_PROGRAM||process.env.TERM)),e.push("platform: "+process.platform),e.push(""),e.push("## Log of coc.nvim"),e.push("");let o=Fte.logfile;if(dR.default.existsSync(o)){let a=dR.default.readFileSync(o,{encoding:"utf8"});e.push(...a.split(/\r?\n/))}await this.nvim.command("vnew +setl\\ buftype=nofile\\ bufhidden=wipe\\ nobuflisted"),await(await this.nvim.buffer).setLines(e,{start:0,end:-1,strictIndexing:!1})}};var gR=C(H());Ce();Jt();yt();ke();var ax=class{constructor(e,t){this.nvim=e;this.handler=t;this.selectionRange=null}async getSelectionRanges(){let{doc:e,position:t}=await this.handler.getCurrentState();return this.handler.checkProvier("selectionRange",e.textDocument),await e.synchronize(),await this.handler.withRequestToken("selection ranges",r=>A.getSelectionRanges(e.textDocument,[t],r))}async selectRange(e,t){let{nvim:i}=this,{doc:r}=await this.handler.getCurrentState();this.handler.checkProvier("selectionRange",r.textDocument);let o=[];if(!t&&(!this.selectionRange||!e))return;if(e){let u=await k.getSelectedRange(e);o.push(u.start,u.end)}else{let u=await k.getCursorPosition();o.push(u)}if(!t){let u=gR.Range.create(o[0],o[1]),{selectionRange:c}=this;for(;c&&c.parent&&!Fe(c.parent.range,u);)c=c.parent;c&&c.parent&&await k.selectRange(c.range);return}await r.synchronize();let s=await this.handler.withRequestToken("selection ranges",u=>A.getSelectionRanges(r.textDocument,o,u));if(!s||s.length==0)return;await i.eval("mode()")!="n"&&await i.eval(`feedkeys("\\", 'in')`);let l;if(s.length==1)l=s[0];else{let u=o[1]||o[0],c=gR.Range.create(o[0],u);for(l=s[0];l;){if(Fe(c,l.range)){l=l.parent;continue}if(ut(o[0],l.range)==0&&ut(u,l.range)==0)break;l=l.parent}}!l||(this.selectionRange=s[0],await k.selectRange(l.range))}};var jte=C(require("path")),bs=C(H());we();wi();le();Ce();H_();ID();z();Vo();V();var Zot=q()("Handler-callHierarchy");function MTe(n){return!!(n&&n.name&&n.kind&&bs.Range.is(n.range)&&n.uri)}var ko=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.highlightWinids=new Set;this.loadConfiguration(),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),this.disposables.push(oe.registerCommand(ko.commandId,async(i,r,o)=>{var l;let{nvim:s}=this;await s.call("win_gotoid",[i]),await y.jumpTo(r.uri,r.selectionRange.start,o);let a=await s.window;if(a.clearMatchGroup(ko.rangesHighlight),a.highlightRanges(ko.rangesHighlight,[r.selectionRange],10,!0),!!((l=r.ranges)!=null&&l.length)){if(r.sourceUri){let u=y.getDocument(r.sourceUri);if(!u)return;let c=await s.call("coc#compat#buf_win_id",[u.bufnr]);if(c==-1)return;c!=a.id&&(a=s.createWindow(c),a.clearMatchGroup(ko.rangesHighlight))}a.highlightRanges(ko.rangesHighlight,r.ranges,100,!0),this.highlightWinids.add(a.id)}},null,!0)),E.on("BufWinEnter",(i,r)=>{this.highlightWinids.has(r)&&(this.highlightWinids.delete(r),e.createWindow(r).clearMatchGroup(ko.rangesHighlight))},null,this.disposables)}loadConfiguration(e){if(!e||e.affectsConfiguration("callHierarchy")){let t=y.getConfiguration("callHierarchy");this.config={splitCommand:t.get("splitCommand"),openCommand:t.get("openCommand"),enableTooltip:t.get("enableTooltip")}}}createProvider(e,t,i,r){let o=new bs.Emitter,s,a,l=()=>{s&&(s.cancel(),s.dispose(),s=null)},u=(h,d)=>{let g=h.children;if(!Array.isArray(g))return;if(g.find(p=>p==d))return h;for(let p of g){let b=u(p,d);if(b)return b}},c={kind:r,onDidChangeTreeData:o.event,getTreeItem:h=>{var g;let d=new Co(h.name,h.children?2:1);return this.config.enableTooltip&&(d.tooltip=jte.default.relative(y.cwd,O.parse(h.uri).fsPath)),d.description=h.detail,d.deprecated=(g=h.tags)==null?void 0:g.includes(bs.SymbolTag.Deprecated),d.icon=this.handler.getIcon(h.kind),d.command={command:ko.commandId,title:"open location",arguments:[t,h,this.config.openCommand]},d},getChildren:async h=>{l(),s=new bs.CancellationTokenSource;let{token:d}=s;if(!h){if(!a&&(a=await this.prepare(e,i,d),!(a!=null&&a.length)))return;for(let f of a){let p=await this.getChildren(e,f,c.kind,d);if(d.isCancellationRequested)break;Array.isArray(p)&&(f.children=p)}return a}if(h.children)return h.children;let g=await this.getChildren(e,h,c.kind,d);return s=null,d.isCancellationRequested?[]:(h.children=g,g)},resolveActions:()=>[{title:"Open in new tab",handler:async h=>{await oe.executeCommand(ko.commandId,t,h,"tabe")}},{title:"Show Incoming Calls",handler:h=>{a=[zi(h,["children","ranges","sourceUri"])],c.kind="incoming",o.fire(void 0)}},{title:"Show Outgoing Calls",handler:h=>{a=[zi(h,["children","ranges","sourceUri"])],c.kind="outgoing",o.fire(void 0)}},{title:"Dismiss",handler:async h=>{let d;for(let f of a)if(d=u(f,h),d)break;if(!d)return;let g=d.children.findIndex(f=>f===h);d.children.splice(g,1),o.fire(d)}}],dispose:()=>{l(),o.dispose(),a=void 0,o=void 0}};return c}async getChildren(e,t,i,r){let o=[];if(i=="incoming"){let s=await A.provideIncomingCalls(e,t,r);s&&(o=s.map(a=>Object.assign(a.from,{ranges:a.fromRanges})))}else{let s=await A.provideOutgoingCalls(e,t,r);s&&(o=s.map(a=>Object.assign(a.to,{ranges:a.fromRanges,sourceUri:t.uri})))}return o}async prepare(e,t,i){this.handler.checkProvier("callHierarchy",e);let r=await A.prepareCallHierarchy(e,t,i);return MTe(r)?[r]:r}async getCallHierarchyItems(e,t){let{doc:i,position:r}=await this.handler.getCurrentState(),o=new bs.CancellationTokenSource;if(!e){await i.synchronize();let a=await this.prepare(i.textDocument,r,o.token);if(e=a?a[0]:void 0,!a)return}let s=t=="incoming"?"provideIncomingCalls":"provideOutgoingCalls";return await A[s](i.textDocument,e,o.token)}async getIncoming(e){return await this.getCallHierarchyItems(e,"incoming")}async getOutgoing(e){return await this.getCallHierarchyItems(e,"outgoing")}async showCallHierarchyTree(e){let{doc:t,position:i,winid:r}=await this.handler.getCurrentState();await t.synchronize();let o=this.createProvider(t.textDocument,r,i,e),s=new au("calls",{treeDataProvider:o});s.title=`${e.toUpperCase()} CALLS`,o.onDidChangeTreeData(a=>{a||(s.title=`${o.kind.toUpperCase()} CALLS`)}),s.onDidChangeVisibility(a=>{a.visible||o.dispose()}),this.disposables.push(s),await s.show(this.config.splitCommand)}dispose(){this.highlightWinids.clear(),Z(this.disposables)}},Hh=ko;Hh.commandId="callHierarchy.reveal",Hh.rangesHighlight="CocSelectedRange";wi();le();Ce();Zo();oa();z();Go();Pe();V();var Ate=C(Ei()),Zr=C(H());Ce();var hu=class{constructor(){this.ranges=[]}get current(){let e=[];return this.ranges.sort((t,i)=>t[0]-i[0]),this.ranges.forEach(t=>{e.push(t[0],t[1])}),e}clear(){this.ranges=[]}add(e,t){e>t&&([e,t]=[t,e]);let{ranges:i}=this;if(i.length==0)i.push([e,t]);else{i.sort((l,u)=>l[0]-u[0]);let r,o,s=[];for(let l=0;lt||(s.push(l),r==null&&(r=Math.min(e,u[0])),o=Math.max(t,u[1]))}let a=s.length?i.filter((l,u)=>!s.includes(u)):i;this.ranges=a,r!=null&&o!=null?this.ranges.push([r,o]):this.ranges.push([e,t])}}has(e,t){return this.ranges.findIndex(r=>r[0]<=e&&r[1]>=t)!==-1}static mergeSpans(e){let t=[];for(let i of e){let r=t.findIndex(o=>!(i[1]o[1]));if(r==-1)t.push(i);else{let o=t[r];t[r]=[Math.min(i[0],o[0]),Math.max(i[1],o[1])]}}return t}};z();Pe();ke();V();var rst=q()("semanticTokens-buffer"),NTe=15,qh="CocSem",Eo="semanticTokens",BTe=50,lx=class{constructor(e,t,i){this.nvim=e;this.doc=t;this.config=i;this._dirty=!1;this.regions=new hu;this._onDidRefresh=new Zr.Emitter;this.onDidRefresh=this._onDidRefresh.event;this.highlight=(0,Ate.default)(()=>{this.doHighlight()},BTe),this.highlight()}get bufnr(){return this.doc.bufnr}onChange(){this.highlight()}onTextChange(){this.cancel()}async forceHighlight(){this.previousResults=void 0,this._highlights=void 0,this.clearHighlight(),this.cancel(),await this.doHighlight(!0)}async onShown(){if(this.shouldRangeHighlight)return;let{doc:e}=this;e.dirty||e.version===this._version||await this.doHighlight(!1,!0)}get hasProvider(){let{textDocument:e}=this.doc;return A.hasProvider("semanticTokens",e)||A.hasProvider("semanticTokensRange",e)}get hasLegend(){let{textDocument:e}=this.doc;return A.getLegend(e)!=null||A.getLegend(e,!0)!=null}get rangeProviderOnly(){let{textDocument:e}=this.doc;return!A.hasProvider("semanticTokens",e)&&A.hasProvider("semanticTokensRange",e)}get shouldRangeHighlight(){let{textDocument:e}=this.doc;return A.hasProvider("semanticTokensRange",e)&&this.previousResults==null}get lineCount(){return this.doc.lineCount}get highlights(){if(!!this._highlights&&this._highlights[0]==this.doc.version)return this._highlights[1]}get buffer(){return this.nvim.createBuffer(this.bufnr)}get enabled(){var e;return!this.config.filetypes.length||!y.env.updateHighlight||!((e=this.doc)!=null&&e.attached)||!this.hasLegend||!this.config.filetypes.includes("*")&&!this.config.filetypes.includes(this.doc.filetype)?!1:this.hasProvider}checkState(){if(!y.env.updateHighlight)throw new Error("Can't perform highlight update, highlight update requires vim >= 8.1.1719 or neovim >= 0.5.0");if(!this.doc.attached)throw new Error("Document not attached");let{filetypes:e}=this.config;if(!(e!=null&&e.includes("*"))&&!e.includes(this.doc.filetype))throw new Error(`Semantic tokens highlight not enabled for current filetype: ${this.doc.filetype}`);if(!this.hasProvider)throw new Error("SemanticTokens provider not found, your languageserver may not support it")}async getTokenRanges(e,t,i){let r=0,o=0,s=Date.now(),a=[];for(let l=0;lNTe){if(await zr(),i.isCancellationRequested)break;s=Date.now()}let u=e[l],c=e[l+1],h=e[l+2],d=t.tokenTypes[e[l+3]],g=t.tokenModifiers.filter((v,w)=>e[l+4]&1<=i))continue;let u={lnum:l,hlGroup:a.hlGroup,colStart:a.range[1],colEnd:a.range[2],combine:a.combine};r.includes(a.tokenType)&&(u.end_incl=!0,u.start_incl=!0),s.push(u)}return s}async doHighlight(e=!1,t=!1){var l;if(this.cancel(),!this.enabled)return;let r=(this.tokenSource=new Zr.CancellationTokenSource).token;if(!t&&(await this.nvim.eval(`get(get(getbufinfo(${this.bufnr}),0,{}),'hidden',0)`)==1||r.isCancellationRequested))return;if(this.shouldRangeHighlight){let u=this.rangeTokenSource=new Zr.CancellationTokenSource;if(await this.doRangeHighlight(u.token),r.isCancellationRequested||this.rangeProviderOnly)return}let{doc:o}=this,s=o.version,a;if(s===((l=this.previousResults)==null?void 0:l.version))if(this._highlights&&this._highlights[0]==s)a=this._highlights[1];else{let u=this.previousResults.tokens,c=A.getLegend(o.textDocument);a=await this.getTokenRanges(u,c,r),a&&(this._highlights=[s,a])}else a=await this.requestAllHighlights(r,e),a&&(this._highlights=[s,a]);if(!(!a||r.isCancellationRequested)){if(!this._dirty||a.length<200){let u=this.toHighlightItems(a),c=await k.diffHighlights(this.bufnr,Eo,u,void 0,r);if(r.isCancellationRequested||!c)return;this._dirty=!0,this._version=s;let h=this.config.highlightPriority;await k.applyDiffHighlights(this.bufnr,Eo,h,c)}else this.regions.clear(),await this.highlightRegions(r);this._onDidRefresh.fire()}}async waitRefresh(){return new Promise((e,t)=>{let i=setTimeout(()=>{r.dispose(),t(new Error("Timeout after 500ms"))},500),r=this.onDidRefresh(()=>{r.dispose(),clearTimeout(i),e()})})}async doRangeHighlight(e){if(!this.enabled)return;let{version:t}=this.doc,i=await this.requestRangeHighlights(e);if(!i||e.isCancellationRequested)return;let{highlights:r,start:o,end:s}=i;if(this.rangeProviderOnly||!this.previousResults){(!this._highlights||t!==this._highlights[0])&&(this._highlights=[t,[]]);let c=this._highlights[1],h=c.reduce((d,g)=>d.add(g.range[0]),new Set);r.forEach(d=>{h.has(d.range[0])||c.push(d)})}let a=this.toHighlightItems(r),l=this.config.highlightPriority,u=await k.diffHighlights(this.bufnr,Eo,a,[o,s],e);u&&(await k.applyDiffHighlights(this.bufnr,Eo,l,u,!0),this._dirty=!0)}async highlightRegions(e){let{regions:t,highlights:i,config:r,lineCount:o,bufnr:s}=this;if(!i)return;let a=r.highlightPriority,l=await this.nvim.call("coc#window#visible_ranges",[s]);if(e.isCancellationRequested||l.length===0)return;let u=y.env.lines;l.forEach(c=>{let h=c[0];c[0]=Math.max(0,Math.floor(h-u*1.5)),c[1]=Math.min(o,Math.ceil(c[1]+u*1.5),h+u*2)});for(let[c,h]of hu.mergeSpans(l)){if(t.has(c,h))continue;let d=this.toHighlightItems(i,c,h),g=await k.diffHighlights(s,Eo,d,[c,h],e);if(e.isCancellationRequested)break;t.add(c,h),g&&k.applyDiffHighlights(s,Eo,a,g,!0)}}async onCursorMoved(){if(this.cancel(!0),!this.enabled||this.doc.dirty)return;let t=(this.rangeTokenSource=new Zr.CancellationTokenSource).token;await bt(global.__TEST__?10:100),!t.isCancellationRequested&&(this.shouldRangeHighlight?await this.doRangeHighlight(t):await this.highlightRegions(t))}async requestRangeHighlights(e){let{nvim:t,doc:i}=this,r=await t.call("coc#window#visible_range",[this.bufnr]);if(!r||e.isCancellationRequested)return null;let o=Math.min(r[0]+y.env.lines*2,r[1]),s=Zr.Range.create(r[0]-1,0,o,0),a=await A.provideDocumentRangeSemanticTokens(i.textDocument,s,e);if(!a||!Zr.SemanticTokens.is(a)||e.isCancellationRequested)return null;let l=A.getLegend(i.textDocument,!0),u=await this.getTokenRanges(a.data,l,e);return e.isCancellationRequested?null:{highlights:u,start:r[0]-1,end:r[1]}}async requestAllHighlights(e,t){let{doc:i}=this,r=A.getLegend(i.textDocument),o=A.hasSemanticTokensEdits(i.textDocument),s=t?null:this.previousResults,a=i.version,l;if(o&&(s==null?void 0:s.resultId)?l=await A.provideDocumentSemanticTokensEdits(i.textDocument,s.resultId,e):l=await A.provideDocumentSemanticTokens(i.textDocument,e),e.isCancellationRequested||l==null)return;let u=[];return Zr.SemanticTokens.is(l)?u=l.data:s&&Array.isArray(l.edits)&&(u=s.tokens,l.edits.forEach(c=>{var h;u.splice(c.start,c.deleteCount?c.deleteCount:0,...(h=c.data)!=null?h:[])})),this.previousResults={resultId:l.resultId,tokens:u,version:a},await this.getTokenRanges(u,r,e)}clearHighlight(){this.buffer.clearNamespace(Eo)}abandonResult(){this.previousResults=void 0}cancel(e=!1){this.rangeTokenSource&&(this.rangeTokenSource.cancel(),this.rangeTokenSource.dispose(),this.rangeTokenSource=null),!e&&(this.regions.clear(),this.highlight.clear(),this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null))}dispose(){this.cancel(),this.previousResults=void 0,this._highlights=void 0,this._onDidRefresh.dispose(),this.regions.clear()}};var bst=q()("semanticTokens"),ux="Statement",cx=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.loadConfiguration(),this.floatFactory=new ci(e),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),oe.register({id:"semanticTokens.checkCurrent",execute:async()=>{await this.showHighlightInfo()}},!1,"show semantic tokens highlight information of current buffer"),oe.register({id:"semanticTokens.refreshCurrent",execute:()=>this.highlightCurrent()},!1,"refresh semantic tokens highlight of current buffer."),oe.register({id:"semanticTokens.inspect",execute:()=>this.inspectSemanticToken()},!1,"Inspect semantic token information at cursor position."),oe.register({id:"semanticTokens.clearCurrent",execute:async()=>{(await e.buffer).clearNamespace(Eo,0,-1)}},!1,"clear semantic tokens highlight of current buffer"),oe.register({id:"semanticTokens.clearAll",execute:async()=>{let i=await e.buffers;for(let r of i)r.clearNamespace(Eo,0,-1)}},!1,"clear semantic tokens highlight of all buffers"),this.highlighters=y.registerBufferSync(i=>new lx(this.nvim,i,this.config)),A.onDidSemanticTokensRefresh(async i=>{let r=await this.nvim.call("coc#window#bufnrs");for(let o of this.highlighters.items){let s=y.getDocument(o.bufnr);!s||!y.match(i,s.textDocument)||(o.abandonResult(),r.includes(o.bufnr)&&o.highlight())}},null,this.disposables),E.on("BufWinEnter",async i=>{let r=this.highlighters.getItem(i);r&&await r.onShown()},null,this.disposables),E.on("CursorMoved",async i=>{let r=this.highlighters.getItem(i);r&&await r.onCursorMoved()},null,this.disposables)}loadConfiguration(e){var t;if(!e||e.affectsConfiguration("semanticTokens")){let i=[];(t=this.config)!=null&&t.highlightGroups?i=this.config.highlightGroups:i=y.env.semanticHighlights||[];let r=y.getConfiguration("semanticTokens");this.config=Object.assign(this.config||{},{highlightGroups:i,filetypes:r.get("filetypes",[]),highlightPriority:r.get("highlightPriority",2048),incrementTypes:r.get("incrementTypes",[]),combinedModifiers:r.get("combinedModifiers",[])})}}async inspectSemanticToken(){var a;let e=await this.getCurrentItem();if(!e||!e.enabled){this.floatFactory.close();return}let[t,i,r]=await this.nvim.call("getcurpos",[]),s=((a=e.highlights)!=null?a:[]).find(l=>{let u=r-1;return l.range[0]===i-1&&u>=l.range[1]&&ug.hlGroup!=null).map(({hlGroup:g})=>g));for(let g of c)r.addTexts([{text:"-",hlGroup:"Comment"},{text:" "},{text:g,hlGroup:g}]);r.addLine(""),r.addLine("Tokens types that current Language Server supported:",ux),r.addLine("");let h=y.getDocument(i.bufnr),d=(l=A.getLegend(h.textDocument))!=null?l:A.getLegend(h.textDocument,!0);if(d.tokenTypes.length){for(let g of[...new Set(d.tokenTypes)]){let f=qh+hn(g);r.addTexts([{text:"-",hlGroup:"Comment"},{text:" "},{text:f,hlGroup:f}])}r.addLine("")}else r.addLine("No token types supported","Comment"),r.addLine("");if(r.addLine("Tokens modifiers that current Language Server supported:",ux),r.addLine(""),d.tokenModifiers.length){for(let g of[...new Set(d.tokenModifiers)]){let f=qh+hn(g);r.addTexts([{text:"-",hlGroup:"Comment"},{text:" "},{text:f,hlGroup:f}])}r.addLine("")}else r.addLine("No token modifiers exist","Comment"),r.addLine("")}catch(u){r.addLine(u instanceof Error?u.message:u.toString(),"Error")}t.pauseNotification();let s=o[0][2];r.render(t.createBuffer(s)),t.resumeNotification(!0,!0)}dispose(){this.floatFactory.dispose(),this.highlighters.dispose(),Z(this.disposables)}};var pp=C(H());le();Ce();Zo();z();Pe();V();var _st=q()("handler-signature"),hx=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.signatureFactory=new ci(e),this.loadConfiguration(),this.disposables.push(this.signatureFactory),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),E.on("CursorMovedI",async(i,r)=>{let o=this.lastPosition;!o||o.bufnr==i&&o.lnum==r[0]&&o.col<=r[1]||this.signatureFactory.close()},null,this.disposables),E.on(["InsertLeave","BufEnter"],()=>{var i;(i=this.tokenSource)==null||i.cancel()},null,this.disposables),E.on("TextChangedI",()=>{this.config.hideOnChange&&this.signatureFactory.close()},null,this.disposables),E.on("TextInsert",async(i,r,o)=>{if(!this.config.trigger)return;let s=this.getTextDocument(i);!s||!A.shouldTriggerSignatureHelp(s.textDocument,o)||await this._triggerSignatureHelp(s,{line:r.lnum-1,character:r.pre.length},!1)},null,this.disposables)}getTextDocument(e){let t=y.getDocument(e);if(!(!t||t.isCommandLine||!t.attached))return t}loadConfiguration(e){if(!e||e.affectsConfiguration("signature")){let t=y.getConfiguration("signature"),i=t.get("target","float");i=="float"&&!y.floatSupported&&(i="echo"),this.config={target:i,floatConfig:t.get("floatConfig",{}),trigger:t.get("enable",!0),wait:Math.max(t.get("triggerSignatureWait",500),200),preferAbove:t.get("preferShownAbove",!0),hideOnChange:t.get("hideOnTextChange",!1)}}}async triggerSignatureHelp(){let{doc:e,position:t}=await this.handler.getCurrentState();return A.hasProvider("signature",e.textDocument)?await this._triggerSignatureHelp(e,t,!0,0):!1}async _triggerSignatureHelp(e,t,i=!0,r=0){var d;(d=this.tokenSource)==null||d.cancel();let o=this.tokenSource=new pp.CancellationTokenSource,s=o.token;s.onCancellationRequested(()=>{o.dispose(),this.tokenSource=void 0});let{target:a}=this.config,l=this.timer=setTimeout(()=>{o.cancel()},this.config.wait);await e.patchChange(!0);let u=await A.getSignatureHelp(e.textDocument,t,s,{isRetrigger:this.signatureFactory.checkRetrigger(e.bufnr),triggerKind:i?pp.SignatureHelpTriggerKind.Invoked:pp.SignatureHelpTriggerKind.TriggerCharacter});if(clearTimeout(l),s.isCancellationRequested)return!1;if(!u||u.signatures.length==0)return this.signatureFactory.close(),!1;let{activeSignature:c,signatures:h}=u;if(c){let[g]=h.splice(c,1);g&&h.unshift(g)}return a=="echo"?this.echoSignature(u):await this.showSignatureHelp(e,t,u,r),!0}async showSignatureHelp(e,t,i,r){let{signatures:o,activeParameter:s}=i,a=null,l=r,u=o.reduce((g,f,p)=>{var D,S,F;let b=null,v=((D=f.activeParameter)!=null?D:typeof s=="number")?s:void 0;v===void 0&&((S=f.parameters)==null?void 0:S.length)>0&&(v=0);let w=f.label.indexOf("(");if(p==0&&typeof v=="number"){let L=(F=f.parameters)==null?void 0:F[v];if(L){let j=f.label.slice(w==-1?0:w);if(a=L.documentation,typeof L.label=="string"){let W=j.slice(0),B=W.match(new RegExp("\\b"+L.label.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b")),N=B?B.index:W.indexOf(L.label);N!=-1&&(b=[N+w,N+L.label.length+w])}else b=L.label}}if(b==null&&(b=[w+1,w+1]),r==l&&(r=r+b[0]+1),g.push({content:f.label,filetype:e.filetype,active:b}),a){let L=typeof a=="string"?a:a.value;L.trim().length&&g.push({content:L,filetype:og(f.documentation)?"markdown":"txt"})}if(p==0&&f.documentation){let{documentation:L}=f,j=typeof L=="string"?L:L.value;j.trim().length&&g.push({content:j,filetype:og(f.documentation)?"markdown":"txt"})}return g},[]),c=e.getline(t.line,!1).slice(0,t.character);this.lastPosition={bufnr:e.bufnr,lnum:t.line+1,col:Q(c)+1};let h=y.getConfiguration("coc.preferences").get("excludeImageLinksInMarkdownDocument"),d=this.signatureFactory.applyFloatConfig({preferTop:this.config.preferAbove,autoHide:!1,offsetX:r,modes:["i","ic","s"],excludeImages:h},this.config.floatConfig);await this.signatureFactory.show(u,d)}echoSignature(e){var s;let{signatures:t,activeParameter:i}=e,r=y.env.columns;t=t.slice(0,y.env.cmdheight);let o=[];for(let a of t){let l=[],{label:u}=a;u=u.replace(/\n/g," "),u.length>=r-16&&(u=u.slice(0,r-16)+"...");let c=u.indexOf("(");if(c==-1)l=[{text:u,type:"Normal"}];else{l.push({text:u.slice(0,c),type:"Label"});let h=u.slice(c);if(o.length==0&&i!=null){let d=(s=a.parameters)==null?void 0:s[i];if(d){let g,f;if(typeof d.label=="string"){let p=h.slice(0),b=p.match(new RegExp("\\b"+d.label.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b")),v=b?b.index:p.indexOf(d.label);v==-1?l.push({text:h,type:"Normal"}):(g=v,f=v+d.label.length)}else[g,f]=d.label,g=g-c,f=f-c;g!=null&&f!=null&&(l.push({text:h.slice(0,g),type:"Normal"}),l.push({text:h.slice(g,f),type:"MoreMsg"}),l.push({text:h.slice(f),type:"Normal"}))}}else l.push({text:h,type:"Normal"})}o.push(l)}this.nvim.callTimer("coc#ui#echo_signatures",[o],!0)}dispose(){Z(this.disposables),this.timer&&clearTimeout(this.timer)}};var Yh=C(H());le();Ce();z();Jt();yt();ke();V();var qte=C(Ei()),Ma=C(H());Ce();z();V();var Ote=C(H());Kf();yt();function Mte(n){let e=[],t=n.slice();return t.sort(Nte),t.forEach(i=>Bte(e,i,0)),e}function Nte(n,e){let t=n.selectionRange,i=e.selectionRange;return De(t.start,i.start)}function Bte(n,e,t){let{name:i,selectionRange:r,detail:o,kind:s,children:a,range:l,tags:u}=e,{start:c}=r||l,h={col:c.character+1,lnum:c.line+1,text:i,level:t,kind:wo(s),range:l,selectionRange:r};if(o&&(h.detail=o),u&&u.includes(Ote.SymbolTag.Deprecated)&&(h.deprecated=!0),n.push(h),a&&a.length){a.sort(Nte);for(let d of a)Bte(n,d,t+1)}}function HTe(n){return n&&!n.hasOwnProperty("location")}function Hte(n){return HTe(n[0])}var dx=class{constructor(e,t){this.bufnr=e;this.autoUpdateBufnrs=t;this.disposables=[];this._onDidUpdate=new Ma.Emitter;this.onDidUpdate=this._onDidUpdate.event;this.fetchSymbols=(0,qte.default)(()=>{this._fetchSymbols().logError()},global.hasOwnProperty("__TEST__")?10:500)}async getSymbols(){var t;let e=y.getDocument(this.bufnr);return e?(await e.patchChange(),this.autoUpdateBufnrs.add(this.bufnr),e.version==this.version&&((t=this.symbols)==null?void 0:t.length)?this.symbols:(this.cancel(),await this._fetchSymbols(),this.symbols)):[]}onChange(e){e.contentChanges.length!==0&&(this.cancel(),this.autoUpdateBufnrs.has(this.bufnr)&&this.fetchSymbols())}get textDocument(){var e;return(e=y.getDocument(this.bufnr))==null?void 0:e.textDocument}async _fetchSymbols(){let{textDocument:e}=this;if(!e)return;let{version:t}=e,i=this.tokenSource=new Ma.CancellationTokenSource,{token:r}=i,o=await A.getDocumentSymbol(e,r);if(this.tokenSource=void 0,o==null||r.isCancellationRequested)return;let s;Hte(o)?s=o:s=o.map(a=>{let l=Ma.DocumentSymbol.create(a.name,"",a.kind,a.location.range,a.location.range);return a.deprecated&&(l.tags=[Ma.SymbolTag.Deprecated]),l}),this.version=t,this.symbols=s,this._onDidUpdate.fire(s)}cancel(){this.fetchSymbols.clear(),this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource.dispose(),this.tokenSource=null)}dispose(){this.cancel(),this.symbols=void 0,this._onDidUpdate.dispose(),Z(this.disposables)}};var fx=C(H());le();Ce();Oe();var Yte=C(H());wi();z();gD();function qTe(n){return n?typeof n.text=="string"&&typeof n.hlGroup=="string":!1}function YTe(n,e){return n.label===e.label&&n.deprecated===e.deprecated&&n.key===e.key}function WTe(n,e){return n.length!==e.length?!1:n.every((t,i)=>YTe(t,e[i]))}var gx=class{constructor(e){this.opts=e;this.disposables=[];this._onDidChangeTreeData=new Yte.Emitter;this.onDidChangeTreeData=this._onDidChangeTreeData.event;this.invokeCommand=`_invoke_${re()}`,this.disposables.push(oe.registerCommand(this.invokeCommand,async t=>{typeof e.handleClick=="function"?await e.handleClick(t):console.error("Handler not found")},null,!0)),typeof e.resolveActions=="function"&&(this.resolveActions=e.resolveActions.bind(this))}iterate(e,t,i,r){let o=r(e,t,i);if(o===!1)return!1;if(Array.isArray(e.children)){for(let s of e.children)if(this.iterate(s,e,i+1,r)===!1)return!1}return o}updateNodes(e,t,i,r=!0){let o=WTe(e,t),s=(a,l,u)=>{var h,d,g,f,p,b;let c=!1;for(let v of Object.keys(l))["children","key"].includes(v)||(a[v]=l[v]);if(((h=a.children)==null?void 0:h.length)&&!((d=l.children)!=null&&d.length)&&(delete a.children,c=!0),!((g=a.children)!=null&&g.length)&&((f=l.children)==null?void 0:f.length)&&(a.children=l.children,c=!0),c){u&&this._onDidChangeTreeData.fire(a);return}((p=a.children)==null?void 0:p.length)&&((b=l.children)==null?void 0:b.length)&&this.updateNodes(a.children,l.children,a,u)};if(o)for(let a=0;a!l.has(g)&&d.key==c.key):h=a.findIndex((d,g)=>!l.has(g)&&d.label==c.label),h===-1)e[u]=c;else{l.add(h);let d=a[h];s(d,c,!1),e[u]=d}}r&&this._onDidChangeTreeData.fire(i)}}update(e,t){if(!!this.data)return t?(this.data=e||[],this._onDidChangeTreeData.fire(void 0)):this.updateNodes(this.data,e||[],void 0),this.data}getTreeItem(e){var o;let t=e.label,{expandLevel:i}=this.opts,r;if(!((o=e.children)!=null&&o.length))r=new Co(t);else if(i&&i>0){let s=this.getLevel(e),a=s&&s<=i?2:1;r=new Co(t,a)}else r=new Co(t,1);if(r.description=e.description,e.deprecated&&(r.deprecated=!0),e.tooltip&&(r.tooltip=e.tooltip),qTe(e.icon))r.icon=e.icon;else if(typeof this.opts.resolveIcon=="function"){let s=this.opts.resolveIcon(e);s&&(r.icon=s)}return r}async getChildren(e){if(e)return e.children||[];if(this.data)return this.data;let t=await Promise.resolve(this.opts.provideData());if(!Array.isArray(t))throw new Error("Unable to fetch data");return this.data=t,t}getParent(e){if(!this.data)return;let t;for(let i of this.data)if(this.iterate(i,null,0,(o,s)=>{if(o===e)return t=s,!1})===!1)break;return t}getLevel(e){if(!this.data)return;let t=0;for(let i of this.data)if(this.iterate(i,null,1,(o,s,a)=>{if(o===e)return t=a,!1})===!1)break;return t}async resolveTreeItem(e,t,i){if(typeof this.opts.resolveItem=="function"){let r=await Promise.resolve(this.opts.resolveItem(e,t,i));r&&Object.assign(e,r)}return e.command||(e.command={title:`invoke ${t.label}`,command:this.invokeCommand,arguments:[t]}),e}dispose(){this.data=[],this._onDidChangeTreeData.dispose(),typeof this.opts.onDispose=="function"&&this.opts.onDispose(),Z(this.disposables)}};ID();z();yt();ke();V();var mat=q()("symbols-outline"),px=class{constructor(e,t,i){this.nvim=e;this.buffers=t;this.handler=i;this.treeViewList=[];this.providersMap=new Map;this.sortByMap=new Map;this.disposables=[];this.loadConfiguration(),y.onDidChangeConfiguration(this.loadConfiguration,this,this.disposables),y.onDidCloseTextDocument(async r=>{let{bufnr:o}=r,s=this.providersMap.get(o);!s||await e.call("bufloaded",[o])||(this.providersMap.delete(o),s.dispose())},null,this.disposables),k.onDidChangeActiveTextEditor(async r=>{if(!this.config.checkBufferSwitch)return;this.treeViewList.find(s=>s.visible&&s.targetTabnr==r.tabpagenr)&&(await this.showOutline(r.document.bufnr,r.tabpagenr),await e.command(`noa call win_gotoid(${r.winid})`))},null,this.disposables),E.on("CursorHold",async r=>{if(!this.config.followCursor||!this.providersMap.get(r))return;let s=await e.call("tabpagenr"),a=this.treeViewList.find(u=>u.visible&&u.targetBufnr==r&&u.targetTabnr==s);if(!a)return;let l=await k.getCursorPosition();await this.revealPosition(a,l)},null,this.disposables)}async revealPosition(e,t){let i,r=a=>{if(ut(t,a.range)!=0)return!1;if(i=a,Array.isArray(a.children)){for(let l of a.children)if(l.kind!==fx.SymbolKind.Variable&&r(l))break}return!0},o=this.providersMap.get(e.targetBufnr);if(!o)return;let s=await Promise.resolve(o.getChildren());for(let a of s)if(r(a))break;i&&await e.reveal(i)}loadConfiguration(e){if(!e||e.affectsConfiguration("outline")){let t=y.getConfiguration("outline");this.config={splitCommand:t.get("splitCommand"),switchSortKey:t.get("switchSortKey"),followCursor:t.get("followCursor"),keepWindow:t.get("keepWindow"),expandLevel:t.get("expandLevel"),autoWidth:t.get("autoWidth"),checkBufferSwitch:t.get("checkBufferSwitch"),detailAsDescription:t.get("detailAsDescription"),sortBy:t.get("sortBy"),showLineNumber:t.get("showLineNumber"),codeActionKinds:t.get("codeActionKinds")}}}convertSymbolToNode(e,t){var s;let i=[],{detailAsDescription:r,showLineNumber:o}=this.config;return r&&e.detail&&i.push(e.detail),o&&i.push(`${e.selectionRange.start.line+1}`),{label:e.name,tooltip:r?void 0:e.detail,description:i.join(" "),icon:this.handler.getIcon(e.kind),deprecated:(s=e.tags)==null?void 0:s.includes(fx.SymbolTag.Deprecated),kind:e.kind,range:e.range,selectRange:e.selectionRange,children:Array.isArray(e.children)?e.children.map(a=>this.convertSymbolToNode(a,t)).sort(t):void 0}}setMessage(e,t){let i=this.treeViewList.filter(r=>r.valid&&r.targetBufnr==e);i&&i.forEach(r=>{r.message=t})}convertSymbols(e,t){let i=this.getSortBy(e),r=(o,s)=>i==="name"?o.labelthis.convertSymbolToNode(o,r)).sort(r)}onSymbolsUpdate(e,t){let i=this.providersMap.get(e);i&&i.update(this.convertSymbols(e,t))}createProvider(e){let{nvim:t}=this,i,r=new gx({expandLevel:this.config.expandLevel,provideData:async()=>{let o=this.buffers.getItem(e);if(!o)throw new Error("Document not attached");let s=y.getDocument(e);if(!A.hasProvider("documentSymbol",s.textDocument))throw new Error("Document symbol provider not found");let a=A.getDocumentSymbolMetadata(s.textDocument);a&&a.label&&this.treeViewList.filter(c=>c.valid&&c.targetBufnr==e).forEach(c=>c.description=a.label),this.setMessage(e,"Loading document symbols");let l=await o.getSymbols();if(!l||l.length==0)throw new Error("Empty symbols returned from language server. ");return this.setMessage(e,void 0),this.convertSymbols(e,l)},handleClick:async o=>{let s=await t.call("bufwinnr",[e]);if(s==-1)return;t.pauseNotification(),t.command(`${s}wincmd w`,!0);let a=o.selectRange.start;t.call("coc#cursor#move_to",[a.line,a.character],!0),t.command("normal! zz",!0);let l=t.createBuffer(e);l.highlightRanges("outline-hover","CocHoverRange",[o.selectRange]),t.command("redraw",!0),await t.resumeNotification(),setTimeout(()=>{l.clearNamespace("outline-hover"),t.command("redraw",!0)},global.hasOwnProperty("__TEST__")?10:300)},resolveActions:async(o,s)=>{let a=await t.call("bufwinnr",[e]);if(a==-1)return;let l=y.getDocument(e);return[...(await this.handler.getCodeActions(l,s.range,this.config.codeActionKinds)).map(h=>({title:h.title,handler:async()=>{let d=s.range.start;await t.command(`${a}wincmd w`),await this.nvim.call("coc#cursor#move_to",[d.line,d.character]),await this.handler.applyCodeAction(h)}})),{title:"Visual Select",handler:async h=>{await t.command(`${a}wincmd w`),await k.selectRange(h.range)}}]},onDispose:()=>{i&&i.dispose();for(let o of this.treeViewList)o.provider===r&&o.dispose()}});return r}getSortBy(e){var t;return(t=this.sortByMap.get(e))!=null?t:this.config.sortBy}async showOutline(e,t){this.providersMap.has(e)||this.providersMap.set(e,this.createProvider(e));let i=this.treeViewList.find(o=>o.valid&&o.targetBufnr==e&&o.targetTabnr==t);if(!i){i=new au("OUTLINE",{autoWidth:this.config.autoWidth,bufhidden:"hide",enableFilter:!0,treeDataProvider:this.providersMap.get(e)});let o=this.getSortBy(e);i.description=`${o[0].toUpperCase()}${o.slice(1)}`,this.treeViewList.push(i),i.onDispose(()=>{let s=this.treeViewList.findIndex(a=>a===i);s!==-1&&this.treeViewList.splice(s,1)})}return await i.show(this.config.splitCommand)&&i.registerLocalKeymap("n",this.config.switchSortKey,async()=>{let o=["category","name","position"],s=this.getSortBy(e),a=o.map(d=>({text:d,disabled:d===s})),l=await k.showMenuPicker(a,{title:"Choose sort method"});if(l<0)return;let u=o[l];this.sortByMap.set(e,u),this.treeViewList.filter(d=>d.targetBufnr==e).forEach(d=>{d.description=`${u[0].toUpperCase()}${u.slice(1)}`});let h=this.buffers.getItem(e);h&&h.symbols&&this.onSymbolsUpdate(e,h.symbols)}),i}async show(e){let[t,i,r,o]=await this.nvim.eval('[&filetype,bufnr("%"),tabpagenr(),win_getid()]');if(t==="coctree")return;let s=await k.getCursorPosition(),a=await this.showOutline(i,r);if(e==1||e===void 0&&this.config.keepWindow)await this.nvim.command(`noa call win_gotoid(${o})`);else if(this.config.followCursor){let l=a.onDidRefrash(async()=>{l.dispose(),await this.nvim.eval("&filetype")=="coctree"&&a.visible&&await this.revealPosition(a,s)})}}has(e){return this.providersMap.has(e)}async hide(){let e=await this.nvim.call("coc#window#find",["cocViewId","OUTLINE"]);e!=-1&&await this.nvim.call("coc#window#close",[e])}dispose(){for(let e of this.treeViewList)e.dispose();this.treeViewList=[];for(let e of this.providersMap.values())e.dispose();this.providersMap.clear(),Z(this.disposables)}};var mx=class{constructor(e,t){this.nvim=e;this.handler=t;this.disposables=[];this.autoUpdateBufnrs=new Set;this.buffers=y.registerBufferSync(i=>{if(i.buftype!="")return;let r=new dx(i.bufnr,this.autoUpdateBufnrs);return r.onDidUpdate(o=>{!this.outline||this.outline.onSymbolsUpdate(r.bufnr,o)}),r}),this.outline=new px(e,this.buffers,t),E.on("CursorHold",async i=>{!this.functionUpdate||!this.buffers.getItem(i)||await this.getCurrentFunctionSymbol(i)},null,this.disposables),E.on("InsertEnter",i=>{let r=this.buffers.getItem(i);r&&r.cancel()},null,this.disposables)}get functionUpdate(){return y.getConfiguration("coc.preferences").get("currentFunctionSymbolAutoUpdate",!1)}get labels(){return y.getConfiguration("suggest").get("completionItemKindLabels",{})}async getWorkspaceSymbols(e){this.handler.checkProvier("workspaceSymbols",null);let t=new Yh.CancellationTokenSource;return await A.getWorkspaceSymbols(e,t.token)}async resolveWorkspaceSymbol(e){var i;if((i=e.location)!=null&&i.uri)return e;let t=new Yh.CancellationTokenSource;return await A.resolveWorkspaceSymbol(e,t.token)}async getDocumentSymbols(e){if(!e){let r=await y.document;if(!r||r.isCommandLine||!r.attached)return;await bt(1),e=r.bufnr}let t=this.buffers.getItem(e);if(!t)return;let i=await t.getSymbols();return i?Mte(i):void 0}async getCurrentFunctionSymbol(e){e||(e=await this.nvim.call("bufnr",["%"]));let t=y.getDocument(e);if(!t||!t.attached||!A.hasProvider("documentSymbol",t.textDocument))return;let i=await k.getCursorPosition(),r=await this.getDocumentSymbols(e),o=this.nvim.createBuffer(e);if(!r||r.length===0)return o.setVar("coc_current_function","",!0),this.nvim.call("coc#util#do_autocmd",["CocStatusChange"],!0),"";r=r.filter(a=>["Class","Method","Function","Struct"].includes(a.kind));let s="";for(let a of r.reverse())if(a.range&&ut(i,a.range)==0&&!a.text.endsWith(") callback")){s=a.text;let l=this.labels[a.kind.toLowerCase()];l&&(s=`${l} ${s}`);break}return this.functionUpdate&&(o.setVar("coc_current_function",s,!0),this.nvim.call("coc#util#do_autocmd",["CocStatusChange"],!0)),s}async selectSymbolRange(e,t,i){let{doc:r}=await this.handler.getCurrentState();this.handler.checkProvier("documentSymbol",r.textDocument);let o;if(t)o=await k.getSelectedRange(t);else{let l=await k.getCursorPosition();o=Yh.Range.create(l,l)}let s=await this.getDocumentSymbols(r.bufnr);if(!s||s.length===0){k.showMessage("No symbols found","warning");return}s=s.filter(l=>i.includes(l.kind));let a;for(let l of s.reverse())if(l.range&&!Fe(l.range,o)&&Pi(o,l.range)){a=l.range;break}if(e&&a){let{start:l,end:u}=a,c=r.getline(l.line+1),h=r.getline(u.line-1);a=Yh.Range.create(l.line+1,c.match(/^\s*/)[0].length,u.line-1,h.length)}a?await k.selectRange(a):["v","V",""].includes(t)&&await this.nvim.command("normal! gv")}async showOutline(e){await this.outline.show(e)}async hideOutline(){await this.outline.hide()}hasOutline(e){return this.outline.has(e)}dispose(){this.outline.dispose(),this.buffers.dispose(),Z(this.disposables)}};Kf();var Wte=C(Ei()),bx=C(H());le();Ce();yt();Pe();ke();V();var ZTe=q()("handler-linkedEditing"),yx=class{constructor(e,t){this.nvim=e;this.changing=!1;this.checkPosition=(0,Wte.default)(this._checkPosition,global.__TEST__?10:100),t.addDisposable(E.on("CursorMoved",(i,r)=>{this.cancel(),this.checkPosition(i,r)})),t.addDisposable(E.on("CursorMovedI",(i,r)=>{this.cancel(),this.checkPosition(i,r)})),t.addDisposable(k.onDidChangeActiveTextEditor(()=>{this.cancel(),this.cancelEdit()})),t.addDisposable(E.on("InsertCharPre",(i,r)=>{if(r!==this.bufnr)return;let o=y.getDocument(r);this.wordPattern?new RegExp(this.wordPattern).test(i)||this.cancelEdit():o.isWord(i)||this.cancelEdit()})),t.addDisposable(y.onDidChangeTextDocument(async i=>{await this.onChange(i)}))}cancelEdit(){var e;(e=this.window)==null||e.clearMatchGroup("^CocLinkedEditing"),this.ranges=void 0,this.window=void 0,this.bufnr=void 0}async onChange(e){if(e.bufnr!==this.bufnr||this.changing||!this.ranges)return;if(e.contentChanges.length===0){this.doHighlights();return}let t=e.contentChanges[0],{text:i,range:r}=t,o=this.ranges.filter(s=>!(!Dl(r,s.range)||yb(r,s.range)&&(i.includes(` -`)||!Ct(r))));if(o.length==1&&Pi(r,o[0].range)){if(i.includes(` -`)){this.cancelEdit();return}ZTe.debug("affected single range"),await this.applySingleEdit(o[0],{range:r,newText:i})}else this.cancelEdit()}async applySingleEdit(e,t){let{bufnr:i,ranges:r}=this,o=y.getDocument(i);r.filter(c=>c!==e&&c.position.line==e.position.line).forEach(c=>c.adjustFromEdit(t));let a=HD(e,t.range,t.newText),l=lp(a);r.forEach(c=>c.applyChange(a));let u=r.filter(c=>c!==e).map(c=>c.textEdit);if(this.changing=!0,await o.applyEdits(u,!0,!0),this.changing=!1,l!=0)for(let c of r){let h=up(c,this.ranges,e);c.move(h*l)}this.doHighlights()}doHighlights(){let{window:e,ranges:t}=this;e&&t&&(this.nvim.pauseNotification(),e.clearMatchGroup("^CocLinkedEditing"),e.highlightRanges("CocLinkedEditing",t.map(i=>i.range),99,!0),this.nvim.resumeNotification(!0,!0))}_checkPosition(e,t){if(E.pumvisible||!y.isAttached(e))return;let i=y.getDocument(e);if(!y.getConfiguration("coc.preferences",i.uri).get("enableLinkedEditing",!1)||!A.hasProvider("linkedEditing",i.textDocument))return;let s=Ui(i.getline(t[0]-1),t[1]-1),a=bx.Position.create(t[0]-1,s);if(this.ranges){if(this.ranges.some(l=>ut(a,l.range)==0))return;this.cancelEdit()}this.enable(i,a)}async enable(e,t){let i=e.textDocument,o=(this.tokenSource=new bx.CancellationTokenSource).token,s=await this.nvim.window,a=await A.provideLinkedEdits(i,t,o);if(o.isCancellationRequested||!a||a.ranges.length==0)return;let l=a.ranges.map(u=>new jh(u.start.line,u.start.character,i.getText(u)));this.wordPattern=a.wordPattern,this.bufnr=e.bufnr,this.window=s,this.ranges=l,this.doHighlights()}cancel(){this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource=null)}};le();Ce();V();var Zte=C(Ei()),Wh=C(H());Ce();Jk();yt();var JTe=global.hasOwnProperty("__TEST__")?10:100,$Te="CocInlayHint",vx=class{constructor(e,t,i){this.nvim=e;this.doc=t;this.config=i;this.regions=new hu;this.currentHints=[];this._onDidRefresh=new Wh.Emitter;this.onDidRefresh=this._onDidRefresh.event;this.render=(0,Zte.default)(()=>{this.renderRange()},JTe),this.render()}get current(){return this.currentHints}clearCache(){this.currentHints=[],this.regions.clear(),this.render.clear()}onChange(){this.clearCache(),this.cancel(),this.render()}cancel(){this.render.clear(),this.tokenSource&&(this.tokenSource.cancel(),this.tokenSource=null)}async renderRange(){if(this.cancel(),!A.hasProvider("inlayHint",this.doc.textDocument))return;this.tokenSource=new Wh.CancellationTokenSource;let e=this.tokenSource.token,t=await this.nvim.call("coc#window#visible_range",[this.doc.bufnr]);if(t==null||this.doc.dirty||e.isCancellationRequested||this.regions.has(t[0],t[1]))return;let i=Wh.Range.create(t[0]-1,0,t[1],0),r=await A.provideInlayHints(this.doc.textDocument,i,e);r==null||e.isCancellationRequested||(this.regions.add(t[0],t[1]),this.currentHints=this.currentHints.filter(o=>ut(o.position,i)!==0),this.currentHints.push(...r),this.setVirtualText(i,r))}setVirtualText(e,t){let{nvim:i,doc:r}=this,o=this.config.srcId,s=r.buffer,a={};for(let l of t){let u=[[cv(l),$Te]];a[l.position.line]===void 0?a[l.position.line]=u:(a[l.position.line].push([" ","Normal"]),a[l.position.line].push(u[0]))}i.pauseNotification(),s.clearNamespace(o,e.start.line,e.end.line+1);for(let l of Object.keys(a))s.setExtMark(o,Number(l),0,{virt_text:a[l],virt_text_pos:"eol",hl_mode:"combine"});i.resumeNotification(!1,!0),this._onDidRefresh.fire()}clearVirtualText(){let e=this.config.srcId;this.doc.buffer.clearNamespace(e)}dispose(){this.cancel()}};var wx=class{constructor(e,t){this.config={};e.createNamespace("coc-inlayHint").then(i=>{this.config.srcId=i}),this.buffers=y.registerBufferSync(i=>{if(!!y.has("nvim-0.5.0"))return new vx(e,i,this.config)}),t.addDisposable(this.buffers),t.addDisposable(A.onDidInlayHintRefresh(async i=>{for(let r of this.buffers.items)y.match(i,r.doc.textDocument)&&(r.clearCache(),A.hasProvider("inlayHint",r.doc.textDocument)?await r.renderRange():r.clearVirtualText())})),t.addDisposable(E.on("CursorMoved",i=>{this.refresh(i)})),t.addDisposable(E.on("WinScrolled",async i=>{let r=await e.call("winbufnr",[i]);r!=-1&&this.refresh(r)}))}getItem(e){return this.buffers.getItem(e)}refresh(e){let t=this.buffers.getItem(e);t&&t.render()}};var Flt=q()("Handler"),xx=class{constructor(e){this.nvim=e;this.disposables=[];this.requestStatusItem=k.createStatusBarItem(0,{progress:!0}),E.on(["CursorMoved","CursorMovedI","InsertEnter","InsertSnippet","InsertLeave"],()=>{this.requestTokenSource&&(this.requestTokenSource.cancel(),this.requestTokenSource=null)},null,this.disposables),this.labels=y.getConfiguration("suggest").get("completionItemKindLabels",{}),this.fold=new GD(e,this),this.links=new VD(e,this),this.codeLens=new JD(e),this.colors=new XD(e,this),this.format=new QD(e,this),this.symbols=new mx(e,this),this.refactor=new rx(e,this),this.hover=new zD(e,this),this.locations=new ex(e,this),this.signature=new hx(e,this),this.rename=new ox(e,this),this.workspace=new sx(e,this),this.codeActions=new WD(e,this),this.commands=new UD(e,y.env),this.callHierarchy=new Hh(e,this),this.documentHighlighter=new KD(e,this),this.semanticHighlighter=new cx(e,this),this.selectionRange=new ax(e,this),this.linkedEditingHandler=new yx(e,this),this.inlayHintHandler=new wx(e,this),this.disposables.push({dispose:()=>{this.callHierarchy.dispose(),this.codeLens.dispose(),this.links.dispose(),this.refactor.dispose(),this.signature.dispose(),this.symbols.dispose(),this.hover.dispose(),this.locations.dispose(),this.colors.dispose(),this.documentHighlighter.dispose(),this.semanticHighlighter.dispose()}}),this.refactor.init()}async getCurrentState(){let{nvim:e}=this,[t,[i,r],o,s]=await e.eval("[bufnr('%'),coc#cursor#position(),win_getid(),mode()]");return{doc:y.getAttachedDocument(t),mode:s,position:Dx.Position.create(i,r),winid:o}}addDisposable(e){this.disposables.push(e)}checkProvier(e,t){if(!A.hasProvider(e,t))throw new Error(`${e} provider not found for current buffer, your language server doesn't support it.`)}async withRequestToken(e,t,i){this.requestTokenSource&&(this.requestTokenSource.cancel(),this.requestTokenSource.dispose()),this.requestTimer&&clearTimeout(this.requestTimer);let r=this.requestStatusItem;this.requestTokenSource=new Dx.CancellationTokenSource;let{token:o}=this.requestTokenSource;o.onCancellationRequested(()=>{r.text=`${e} request canceled`,r.isProgress=!1,this.requestTimer=setTimeout(()=>{r.hide()},500)}),r.isProgress=!0,r.text=`requesting ${e}`,r.show();let s;try{s=await Promise.resolve(t(o))}catch(a){this.nvim.echoError(a)}return this.requestTokenSource&&(this.requestTokenSource.dispose(),this.requestTokenSource=void 0),o.isCancellationRequested?null:(r.hide(),i&&(!s||Array.isArray(s)&&s.length==0)?(k.showMessage(`${e} not found`,"warning"),null):s)}getIcon(e){let{labels:t}=this,i=wo(e),r=typeof t.default=="string"?t.default:i[0].toLowerCase(),o=i=="Unknown"?"":t[i[0].toLowerCase()+i.slice(1)];return(!o||typeof o!="string")&&(o=r),{text:o,hlGroup:i=="Unknown"?"CocSymbolDefault":`CocSymbol${i}`}}async getCodeActions(e,t,i){return(await this.codeActions.getCodeActions(e,t,i)).filter(o=>!o.disabled)}async applyCodeAction(e){await this.codeActions.applyCodeAction(e)}async hasProvider(e){let t=await this.nvim.call("bufnr","%"),i=y.getDocument(t);return i?A.hasProvider(e,i.textDocument):!1}dispose(){this.requestTimer&&clearTimeout(this.requestTimer),Z(this.disposables)}};sD();$f();iu();Ul();z();ke();V();var Jte=q()("plugin"),Cx=class extends $te.EventEmitter{constructor(e){super();this.nvim=e;this._ready=!1;this.actions=new Map;this.disposables=[];this.disposables.push(y.registerTextDocumentContentProvider("output",$o.getProvider(e))),Object.defineProperty(y,"nvim",{get:()=>this.nvim}),Object.defineProperty(k,"cursors",{get:()=>this.cursors}),y.onDidChangeWorkspaceFolders(()=>{e.setVar("WorkspaceFolders",y.folderPaths,!0)},null,this.disposables),E.on("VimResized",(t,i)=>{y.env&&Object.assign(y.env,{columns:t,lines:i})},null,this.disposables),this.cursors=new YD(e),oe.init(e,this),this.addAction("checkJsonExtension",()=>{ye.has("coc-json")||k.showMessage("Run :CocInstall coc-json for json intellisense","more")}),this.addAction("rootPatterns",t=>this.handler.workspace.getRootPatterns(t)),this.addAction("ensureDocument",()=>this.handler.workspace.ensureDocument()),this.addAction("getConfig",async t=>this.handler.workspace.getConfiguration(t)),this.addAction("doAutocmd",async(t,...i)=>this.handler.workspace.doAutocmd(t,i)),this.addAction("openLog",async()=>this.handler.workspace.openLog()),this.addAction("attach",()=>y.attach()),this.addAction("detach",()=>y.detach()),this.addAction("doKeymap",async(t,i,r)=>this.handler.workspace.doKeymap(t,i,r)),this.addAction("registExtensions",(...t)=>ye.loadExtension(t)),this.addAction("snippetCheck",async(t,i)=>this.handler.workspace.snippetCheck(t,i)),this.addAction("snippetNext",()=>Ut.nextPlaceholder()),this.addAction("snippetPrev",()=>Ut.previousPlaceholder()),this.addAction("snippetCancel",()=>Ut.cancel()),this.addAction("openLocalConfig",()=>k.openLocalConfig()),this.addAction("bufferCheck",()=>k.bufferCheck()),this.addAction("showInfo",()=>this.handler.workspace.showInfo()),this.addAction("hasProvider",t=>this.handler.hasProvider(t)),this.addAction("hasSelected",()=>Ih.hasSelected()),this.addAction("listNames",()=>Di.names),this.addAction("listDescriptions",()=>Di.descriptions),this.addAction("listLoadItems",t=>Di.loadItems(t)),this.addAction("search",(...t)=>this.handler.refactor.search(t)),this.addAction("cursorsSelect",(t,i,r)=>this.cursors.select(t,i,r)),this.addAction("fillDiagnostics",t=>Ft.setLocationlist(t)),this.addAction("saveRefactor",t=>this.handler.refactor.save(t)),this.addAction("commandList",()=>this.handler.commands.getCommandList()),this.addAction("selectSymbolRange",(t,i,r)=>this.handler.symbols.selectSymbolRange(t,i,r)),this.addAction("openList",(...t)=>Di.start(t)),this.addAction("listResume",t=>Di.resume(t)),this.addAction("listCancel",()=>Di.cancel(!0)),this.addAction("listPrev",t=>Di.previous(t)),this.addAction("listNext",t=>Di.next(t)),this.addAction("listFirst",t=>Di.first(t)),this.addAction("listLast",t=>Di.last(t)),this.addAction("sendRequest",(t,i,r)=>Mi.sendRequest(t,i,r)),this.addAction("sendNotification",(t,i,r)=>Mi.sendNotification(t,i,r)),this.addAction("registNotification",(t,i)=>Mi.registNotification(t,i)),this.addAction("updateConfig",(t,i)=>y.configurations.updateUserConfig({[t]:i})),this.addAction("links",()=>this.handler.links.getLinks()),this.addAction("openLink",()=>this.handler.links.openCurrentLink()),this.addAction("pickColor",()=>this.handler.colors.pickColor()),this.addAction("colorPresentation",()=>this.handler.colors.pickPresentation()),this.addAction("highlight",()=>this.handler.documentHighlighter.highlight()),this.addAction("fold",t=>this.handler.fold.fold(t)),this.addAction("startCompletion",t=>Ih.startCompletion(t)),this.addAction("stopCompletion",()=>Ih.stop()),this.addAction("sourceStat",()=>Lt.sourceStats()),this.addAction("refreshSource",t=>Lt.refresh(t)),this.addAction("toggleSource",t=>Lt.toggleSource(t)),this.addAction("diagnosticRefresh",t=>Ft.refresh(t)),this.addAction("diagnosticInfo",()=>Ft.echoMessage()),this.addAction("diagnosticToggle",t=>Ft.toggleDiagnostic(t)),this.addAction("diagnosticToggleBuffer",(t,i)=>Ft.toggleDiagnosticBuffer(t,i)),this.addAction("diagnosticNext",t=>Ft.jumpNext(t)),this.addAction("diagnosticPrevious",t=>Ft.jumpPrevious(t)),this.addAction("diagnosticPreview",()=>Ft.preview()),this.addAction("diagnosticList",async()=>Ft.getDiagnosticList()),this.addAction("findLocations",(t,i,r,o)=>this.handler.locations.findLocations(t,i,r,o)),this.addAction("getTagList",()=>this.handler.locations.getTagList()),this.addAction("jumpDefinition",t=>this.handler.locations.gotoDefinition(t)),this.addAction("definitions",()=>this.handler.locations.definitions()),this.addAction("jumpDeclaration",t=>this.handler.locations.gotoDeclaration(t)),this.addAction("declarations",()=>this.handler.locations.declarations()),this.addAction("jumpImplementation",t=>this.handler.locations.gotoImplementation(t)),this.addAction("implementations",()=>this.handler.locations.implementations()),this.addAction("jumpTypeDefinition",t=>this.handler.locations.gotoTypeDefinition(t)),this.addAction("typeDefinitions",()=>this.handler.locations.typeDefinitions()),this.addAction("jumpReferences",t=>this.handler.locations.gotoReferences(t)),this.addAction("references",t=>this.handler.locations.references(t)),this.addAction("jumpUsed",t=>this.handler.locations.gotoReferences(t,!1)),this.addAction("doHover",t=>this.handler.hover.onHover(t)),this.addAction("definitionHover",t=>this.handler.hover.definitionHover(t)),this.addAction("getHover",()=>this.handler.hover.getHover()),this.addAction("showSignatureHelp",()=>this.handler.signature.triggerSignatureHelp()),this.addAction("documentSymbols",t=>this.handler.symbols.getDocumentSymbols(t)),this.addAction("symbolRanges",()=>this.handler.documentHighlighter.getSymbolsRanges()),this.addAction("selectionRanges",()=>this.handler.selectionRange.getSelectionRanges()),this.addAction("rangeSelect",(t,i)=>this.handler.selectionRange.selectRange(t,i)),this.addAction("rename",t=>this.handler.rename.rename(t)),this.addAction("getWorkspaceSymbols",t=>this.handler.symbols.getWorkspaceSymbols(t)),this.addAction("resolveWorkspaceSymbol",t=>this.handler.symbols.resolveWorkspaceSymbol(t)),this.addAction("formatSelected",t=>this.handler.format.formatCurrentRange(t)),this.addAction("format",()=>this.handler.format.formatCurrentBuffer()),this.addAction("commands",()=>this.handler.commands.getCommands()),this.addAction("services",()=>Mi.getServiceStats()),this.addAction("toggleService",t=>Mi.toggle(t)),this.addAction("codeAction",(t,i)=>this.handler.codeActions.doCodeAction(t,i)),this.addAction("organizeImport",()=>this.handler.codeActions.organizeImport()),this.addAction("fixAll",()=>this.handler.codeActions.doCodeAction(null,[fR.CodeActionKind.SourceFixAll])),this.addAction("doCodeAction",t=>this.handler.codeActions.applyCodeAction(t)),this.addAction("codeActions",(t,i)=>this.handler.codeActions.getCurrentCodeActions(t,i)),this.addAction("quickfixes",t=>this.handler.codeActions.getCurrentCodeActions(t,[fR.CodeActionKind.QuickFix])),this.addAction("codeLensAction",()=>this.handler.codeLens.doAction()),this.addAction("runCommand",(...t)=>this.handler.commands.runCommand(...t)),this.addAction("doQuickfix",()=>this.handler.codeActions.doQuickfix()),this.addAction("refactor",()=>this.handler.refactor.doRefactor()),this.addAction("repeatCommand",()=>this.handler.commands.repeat()),this.addAction("installExtensions",(...t)=>ye.installExtensions(t)),this.addAction("updateExtensions",t=>ye.updateExtensions(t)),this.addAction("extensionStats",()=>ye.getExtensionStates()),this.addAction("loadedExtensions",()=>ye.loadedExtensions()),this.addAction("watchExtension",t=>ye.watchExtension(t)),this.addAction("activeExtension",t=>ye.activate(t)),this.addAction("deactivateExtension",t=>ye.deactivate(t)),this.addAction("reloadExtension",t=>ye.reloadExtension(t)),this.addAction("toggleExtension",t=>ye.toggleExtension(t)),this.addAction("uninstallExtension",(...t)=>ye.uninstallExtension(t)),this.addAction("getCurrentFunctionSymbol",()=>this.handler.symbols.getCurrentFunctionSymbol()),this.addAction("showOutline",t=>this.handler.symbols.showOutline(t)),this.addAction("hideOutline",()=>this.handler.symbols.hideOutline()),this.addAction("getWordEdit",()=>this.handler.rename.getWordEdit()),this.addAction("addCommand",t=>this.handler.commands.addVimCommand(t)),this.addAction("addRanges",t=>this.cursors.addRanges(t)),this.addAction("currentWorkspacePath",()=>y.rootPath),this.addAction("selectCurrentPlaceholder",t=>Ut.selectCurrentPlaceholder(!!t)),this.addAction("codeActionRange",(t,i,r)=>this.handler.codeActions.codeActionRange(t,i,r)),this.addAction("incomingCalls",t=>this.handler.callHierarchy.getIncoming(t)),this.addAction("outgoingCalls",t=>this.handler.callHierarchy.getOutgoing(t)),this.addAction("showIncomingCalls",()=>this.handler.callHierarchy.showCallHierarchyTree("incoming")),this.addAction("showOutgoingCalls",()=>this.handler.callHierarchy.showCallHierarchyTree("outgoing")),this.addAction("inspectSemanticToken",()=>this.handler.semanticHighlighter.inspectSemanticToken()),this.addAction("semanticHighlight",()=>this.handler.semanticHighlighter.highlightCurrent()),this.addAction("showSemanticHighlightInfo",()=>this.handler.semanticHighlighter.showHighlightInfo())}addAction(e,t){if(this.actions.has(e))throw new Error(`Action ${e} already exists`);this.actions.set(e,t)}async init(){let{nvim:e}=this,t=Date.now();try{await ye.init(),await y.init(k),e.setVar("coc_workspace_initialized",!0,!0),Ut.init(),Ih.init(),Ft.init(),Di.init(e),Lt.init(),this.handler=new xx(e),Mi.init(),ye.activateExtensions(),y.autocmds.setupDynamicAutocmd(!0),e.pauseNotification(),e.setVar("WorkspaceFolders",y.folderPaths,!0),e.setVar("coc_service_initialized",1,!0),e.call("coc#util#do_autocmd",["CocNvimInit"],!0),e.resumeNotification(!1,!0),this._ready=!0,await E.fire("ready",[]),Jte.info(`coc.nvim initialized with node: ${process.version} after ${Date.now()-t}ms`),this.emit("ready")}catch(i){e.echoError(i)}}get isReady(){return this._ready}get ready(){return this._ready?Promise.resolve():new Promise(e=>{this.once("ready",()=>{e()})})}hasAction(e){return this.actions.has(e)}async cocAction(e,...t){let i=this.actions.get(e);if(!i)throw new Error(`Action "${e}" doesn't exist`);let r=Date.now(),o=await Promise.resolve(i.apply(null,t)),s=Date.now()-r;return s>500&&Jte.warn(`Slow action "${e}" cost ${s}ms`),o}getHandler(){return this.handler}dispose(){this.removeAllListeners(),Z(this.disposables),ye.dispose(),Di.dispose(),y.dispose(),$o.dispose(),k.dispose(),Lt.dispose(),Mi.stopAll(),Mi.dispose(),this.handler&&this.handler.dispose(),Ut.dispose(),oe.dispose(),Ih.dispose(),Ft.dispose()}};var Gte=C(nf());In();we();kT();var Jr=q()("attach"),XTe=global.hasOwnProperty("__TEST__"),UTe=["installExtensions","updateExtensions"],Qte=(n,e=!0)=>{let t=(0,Xte.attach)(n,Ute.default.getLogger("node-client"),e);global.hasOwnProperty("__TEST__")||t.call("coc#util#path_replace_patterns").then(s=>{if(_t(s)){let a=O.file;O.file=l=>(l=l.replace(/\\/g,"/"),Object.keys(s).forEach(u=>l=l.replace(new RegExp("^"+u),s[u])),a(l))}}).logError(),t.setVar("coc_process_pid",process.pid,!0);let i=new Cx(t),r=!1,o=!1;return t.on("notification",async(s,a)=>{switch(s){case"VimEnter":{!o&&r&&(o=!0,await i.init());break}case"Log":{Jr.debug(...a);break}case"TaskExit":case"TaskStderr":case"TaskStdout":case"GlobalChange":case"PromptInsert":case"InputChar":case"MenuInput":case"OptionSet":case"PromptKeyPress":case"FloatBtnClick":Jr.trace("Event: ",s,...a),await E.fire(s,a);break;case"CocAutocmd":Jr.trace("Notification autocmd:",...a),await E.fire(a[0],a.slice(1));break;case"redraw":break;default:{if(!i.hasAction(s)){console.error(`action "${s}" does not exist`);return}try{i.isReady?Jr.info("receive notification:",s,a):Jr.warn(`Plugin not ready when received "${s}"`,a),await i.ready,await i.cocAction(s,...a)}catch(u){t.echoError(`Error on notification "${s}": ${u instanceof Error?u.message:u}`),Jr.error(u)}}}}),t.on("request",async(s,a,l)=>{if(s=="redraw"){l.send();return}let u=setTimeout(()=>{Jr.error("Request cost more than 3s",s,a)},3e3);try{if(s=="CocAutocmd")Jr.trace("Request autocmd:",...a),await E.fire(a[0],a.slice(1)),l.send(void 0);else{if(!i.isReady&&!UTe.includes(s)){Jr.warn(`Plugin not ready on request "${s}"`,a),l.send("Plugin not ready",!0);return}Jr.info("Request action:",s,a);let c=await i.cocAction(s,...a);l.send(c)}clearTimeout(u)}catch(c){clearTimeout(u),l.send(c instanceof Error?c.message:c.toString(),!0),Jr.error("Request error:",s,a,c)}}),t.channelId.then(async s=>{r=!0,XTe&&t.call("coc#rpc#set_channel",[s],!0);let{major:a,minor:l,patch:u}=Gte.default.parse(kb);t.setClientInfo("coc",{major:a,minor:l,patch:u},"remote",{},{}),await t.getVvar("vim_did_enter")&&!o&&(o=!0,await i.init())}).catch(s=>{console.error(`Channel create error: ${s.message}`)}),i};Object.defineProperty(console,"log",{value(){Sx&&Sx.info(...arguments)}});var Sx=q()("server");Qte({reader:process.stdin,writer:process.stdout});process.on("uncaughtException",function(n){let e="Uncaught exception: "+n.message;console.error(e),Sx.error("uncaughtException",n.stack)});process.on("unhandledRejection",function(n,e){n instanceof Error?console.error("UnhandledRejection: "+n.message+` -`+n.stack):console.error("UnhandledRejection: "+n),Sx.error("unhandledRejection ",e,n)}); -/*! - * bytes - * Copyright(c) 2012-2014 TJ Holowaychuk - * Copyright(c) 2015 Jed Watson - * MIT Licensed - */ -/*! - * content-disposition - * Copyright(c) 2014-2017 Douglas Christopher Wilson - * MIT Licensed - */ -/*! (c) 2020 Andrea Giammarchi */ -/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ -/** - * event-lite.js - Light-weight EventEmitter (less than 1KB when gzipped) - * - * @copyright Yusuke Kawasaki - * @license MIT - * @constructor - * @see https://github.com/kawanet/event-lite - * @see http://kawanet.github.io/event-lite/EventLite.html - * @example - * var EventLite = require("event-lite"); - * - * function MyClass() {...} // your class - * - * EventLite.mixin(MyClass.prototype); // import event methods - * - * var obj = new MyClass(); - * obj.on("foo", function() {...}); // add event listener - * obj.once("bar", function() {...}); // add one-time event listener - * obj.emit("foo"); // dispatch event - * obj.emit("bar"); // dispatch another event - * obj.off("foo"); // remove event listener - */ diff --git a/sources_non_forked/coc.nvim/esbuild.js b/sources_non_forked/coc.nvim/esbuild.js new file mode 100644 index 00000000..4e186547 --- /dev/null +++ b/sources_non_forked/coc.nvim/esbuild.js @@ -0,0 +1,77 @@ +const cp = require('child_process') +const fs = require('fs') +const path = require('path') +let revision = 'master' +if (process.env.NODE_ENV !== 'development') { + try { + let res = cp.execSync(`git log -1 --date=iso --pretty=format:'"%h","%ad"'`, {encoding: 'utf8'}) + revision = res.replaceAll('"', '').replace(',', ' ') + } catch (e) { + // ignore + } +} + +let envPlugin = { + name: 'env', + setup(build) { + build.onResolve({filter: /\/appenders$/}, args => { + let fullpath = path.join(args.resolveDir, args.path) + return { + path: path.relative(__dirname, fullpath).replace(/\\/g, '/'), + namespace: 'env-ns' + } + }) + build.onLoad({filter: /^node_modules\/log4js\/lib\/appenders$/, namespace: 'env-ns'}, args => { + let content = fs.readFileSync(path.join(args.path, 'index.js'), 'utf8') + return { + contents: content.replace(/require\.main/g, '""'), + resolveDir: args.path + } + }) + } +} + +async function start(watch) { + await require('esbuild').build({ + entryPoints: ['src/main.ts'], + bundle: true, + watch, + minify: process.env.NODE_ENV === 'production', + sourcemap: process.env.NODE_ENV === 'development', + define: {REVISION: '"' + revision + '"', ESBUILD: 'true'}, + mainFields: ['module', 'main'], + platform: 'node', + target: 'node12.12', + outfile: 'build/index.js', + banner: { + js: `(function () { + var v = process.version + var parts = v.slice(1).split('.') + var major = parseInt(parts[0], 10) + var minor = parseInt(parts[1], 10) + if (major < 12 || (major == 12 && minor < 12)) { + throw new Error('coc.nvim requires node >= v12.12.0, current version: ' + v) + } +})(); ` + }, + plugins: [envPlugin] + }) +} + +let watch = false +if (process.argv.includes('--watch')) { + console.log('watching...') + watch = { + onRebuild(error) { + if (error) { + console.error('watch build failed:', error) + } else { + console.log('watch build succeeded') + } + }, + } +} + +start(watch).catch(e => { + console.error(e) +}) diff --git a/sources_non_forked/coc.nvim/history.md b/sources_non_forked/coc.nvim/history.md index c8704ec2..8f0a635c 100644 --- a/sources_non_forked/coc.nvim/history.md +++ b/sources_non_forked/coc.nvim/history.md @@ -1,3 +1,7 @@ +# 2022-06-14 + +- Add highlight groups `CocListLine` and `CocListSearch`. + # 2022-06-11 - Add configuration "notification.disabledProgressSources" diff --git a/sources_non_forked/coc.nvim/jest.js b/sources_non_forked/coc.nvim/jest.js new file mode 100644 index 00000000..43336a2f --- /dev/null +++ b/sources_non_forked/coc.nvim/jest.js @@ -0,0 +1,21 @@ +const path = require('path') +const os = require('os') +const fs = require('fs') + +process.on('uncaughtException', err => { + let msg = 'Uncaught exception: ' + err.stack + console.error(msg) +}) + +process.on('exit', () => { + fs.rmdirSync(process.env.TMPDIR, { recursive: true, force: true }) +}) + +module.exports = async () => { + let dataHome = path.join(os.tmpdir(), `coc-test/${process.pid}`) + fs.mkdirSync(dataHome, { recursive: true }) + process.env.NODE_ENV = 'test' + process.env.COC_DATA_HOME = dataHome + process.env.COC_VIMCONFIG = path.join(__dirname, 'src/__tests__') + process.env.TMPDIR = '/tmp/coc-test' +} diff --git a/sources_non_forked/coc.nvim/package.json b/sources_non_forked/coc.nvim/package.json index b1398eca..d805a056 100644 --- a/sources_non_forked/coc.nvim/package.json +++ b/sources_non_forked/coc.nvim/package.json @@ -1,17 +1,124 @@ { - "name": "coc.nvim-release", + "name": "coc.nvim-master", "version": "0.0.81", "description": "LSP based intellisense engine for neovim & vim8.", + "main": "./build/index.js", "engines": { "node": ">=12.12.0" }, + "scripts": { + "lint": "eslint . --ext .ts --quiet", + "lint:typecheck": "tsc -p tsconfig.json", + "build": "node esbuild.js", + "test": "./node_modules/.bin/jest --forceExit", + "test-build": "./node_modules/.bin/jest --coverage --forceExit", + "prepare": "node esbuild.js" + }, "repository": { "type": "git", "url": "git+https://github.com/neoclide/coc.nvim.git" }, + "keywords": [ + "complete", + "neovim" + ], "author": "Qiming Zhao ", "bugs": { "url": "https://github.com/neoclide/coc.nvim/issues" }, - "homepage": "https://github.com/neoclide/coc.nvim#readme" + "homepage": "https://github.com/neoclide/coc.nvim#readme", + "jest": { + "globals": { + "__TEST__": true + }, + "projects": [ + "" + ], + "watchman": false, + "clearMocks": true, + "globalSetup": "./jest.js", + "testEnvironment": "node", + "coveragePathIgnorePatterns": [ + "/src/__tests__/*" + ], + "moduleFileExtensions": [ + "ts", + "tsx", + "json", + "js" + ], + "transform": { + "^.+\\.tsx?$": [ + "@swc/jest" + ] + }, + "testRegex": "src/__tests__/.*\\.(test|spec)\\.ts$", + "coverageReporters": [ + "text", + "lcov" + ], + "coverageDirectory": "./coverage/" + }, + "devDependencies": { + "@swc/core": "^1.2.183", + "@swc/jest": "^0.2.21", + "@types/cli-table": "^0.3.0", + "@types/debounce": "^3.0.0", + "@types/fb-watchman": "^2.0.0", + "@types/fs-extra": "^9.0.6", + "@types/glob": "^7.2.0", + "@types/jest": "^27.0.3", + "@types/marked": "^4.0.1", + "@types/minimatch": "^3.0.3", + "@types/mkdirp": "^1.0.1", + "@types/node": "12.12.12", + "@types/semver": "^7.3.4", + "@types/tar": "^4.0.5", + "@types/uuid": "^8.3.0", + "@types/which": "^1.3.2", + "@typescript-eslint/eslint-plugin": "^5.20.0", + "@typescript-eslint/parser": "^5.20.0", + "bser": "^2.1.1", + "esbuild": "^0.14.25", + "eslint": "^8.14.0", + "eslint-plugin-jest": "^26.1.5", + "eslint-plugin-jsdoc": "^39.2.8", + "jest": "27.4.5", + "typescript": "^4.6.3", + "vscode-languageserver": "7.0.0" + }, + "dependencies": { + "@chemzqm/neovim": "^5.7.9", + "@chemzqm/string-width": "^5.1.2", + "ansi-styles": "^5.0.0", + "bytes": "^3.1.0", + "cli-table": "^0.3.4", + "content-disposition": "^0.5.3", + "debounce": "^1.2.0", + "decompress-response": "^6.0.0", + "fast-diff": "^1.2.0", + "fb-watchman": "^2.0.1", + "follow-redirects": "^1.14.8", + "fs-extra": "^9.0.1", + "glob": "^7.2.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "isuri": "^2.0.3", + "jsonc-parser": "^3.0.0", + "log4js": "^6.4.0", + "marked": "^4.0.12", + "minimatch": "^3.0.4", + "semver": "^7.3.2", + "strip-ansi": "^6.0.0", + "tar": "^6.1.9", + "tslib": "^2.0.3", + "unidecode": "^0.1.8", + "unzip-stream": "^0.3.1", + "uuid": "^7.0.3", + "vscode-languageserver-protocol": "^3.16.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-uri": "^2.1.2", + "which": "^2.0.2" + } } diff --git a/sources_non_forked/coc.nvim/requirements.txt b/sources_non_forked/coc.nvim/requirements.txt new file mode 100644 index 00000000..e69de29b diff --git a/sources_non_forked/coc.nvim/src/__tests__/autoload/coc/source/email.vim b/sources_non_forked/coc.nvim/src/__tests__/autoload/coc/source/email.vim new file mode 100644 index 00000000..de932ee7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/autoload/coc/source/email.vim @@ -0,0 +1,17 @@ +" vim source for emails +function! coc#source#email#init() abort + return { + \ 'priority': 9, + \ 'shortcut': 'Email', + \ 'triggerCharacters': ['@'] + \} +endfunction + +function! coc#source#email#should_complete(opt) abort + return 1 +endfunction + +function! coc#source#email#complete(opt, cb) abort + let items = ['foo@gmail.com', 'bar@yahoo.com'] + call a:cb(items) +endfunction diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/changedFiles.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/changedFiles.test.ts new file mode 100644 index 00000000..f2c78fd6 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/changedFiles.test.ts @@ -0,0 +1,62 @@ +/* eslint-disable */ +import helper from '../helper' +// import * as assert from 'assert' +import fs from 'fs' +import * as lsclient from '../../language-client' +import * as path from 'path' +import { URI } from 'vscode-uri' +// import which from 'which' + +beforeAll(async () => { + await helper.setup() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('Client integration', () => { + + it('should send file change notification', (done) => { + if (global.hasOwnProperty('__TEST__')) return done() + let serverModule = path.join(__dirname, './server/testFileWatcher.js') + let serverOptions: lsclient.ServerOptions = { + module: serverModule, + transport: lsclient.TransportKind.ipc + } + let clientOptions: lsclient.LanguageClientOptions = { + documentSelector: ['css'], + synchronize: {}, initializationOptions: {}, + middleware: { + } + } + let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions) + let disposable = client.start() + + client.onReady().then(_ => { + setTimeout(async () => { + let file = path.join(__dirname, 'test.js') + fs.writeFileSync(file, '', 'utf8') + await helper.wait(300) + let res = await client.sendRequest('custom/received') + expect(res).toEqual({ + changes: [{ + uri: URI.file(file).toString(), + type: 1 + }] + }) + fs.unlinkSync(file) + disposable.dispose() + done() + }, 200) + }, e => { + disposable.dispose() + done(e) + }) + }) + +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/connection.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/connection.test.ts new file mode 100644 index 00000000..2b563633 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/connection.test.ts @@ -0,0 +1,139 @@ +import { Duplex } from 'stream' +import { createProtocolConnection, ProgressType, DocumentSymbolParams, DocumentSymbolRequest, InitializeParams, InitializeRequest, InitializeResult, ProtocolConnection, StreamMessageReader, StreamMessageWriter } from 'vscode-languageserver-protocol/node' +import { SymbolInformation, SymbolKind } from 'vscode-languageserver-types' +import { NullLogger } from '../../language-client/client' + +class TestStream extends Duplex { + public _write(chunk: string, _encoding: string, done: () => void): void { + this.emit('data', chunk) + done() + } + + public _read(_size: number): void { + } +} + +let serverConnection: ProtocolConnection +let clientConnection: ProtocolConnection +let progressType: ProgressType = new ProgressType() + +beforeEach(() => { + const up = new TestStream() + const down = new TestStream() + const logger = new NullLogger() + serverConnection = createProtocolConnection(new StreamMessageReader(up), new StreamMessageWriter(down), logger) + clientConnection = createProtocolConnection(new StreamMessageReader(down), new StreamMessageWriter(up), logger) + serverConnection.listen() + clientConnection.listen() +}) + +afterEach(() => { + serverConnection.dispose() + clientConnection.dispose() +}) + +describe('Connection Tests', () => { + it('should ensure proper param passing', async () => { + let paramsCorrect = false + serverConnection.onRequest(InitializeRequest.type, params => { + paramsCorrect = !Array.isArray(params) + let result: InitializeResult = { + capabilities: { + } + } + return result + }) + + const init: InitializeParams = { + rootUri: 'file:///home/dirkb', + processId: 1, + capabilities: {}, + workspaceFolders: null, + } + await clientConnection.sendRequest(InitializeRequest.type, init) + expect(paramsCorrect).toBe(true) + }) + + it('should provide token', async () => { + serverConnection.onRequest(DocumentSymbolRequest.type, params => { + expect(params.partialResultToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2') + return [] + }) + + const params: DocumentSymbolParams = { + textDocument: { uri: 'file:///abc.txt' }, + partialResultToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2' + } + await clientConnection.sendRequest(DocumentSymbolRequest.type, params) + }) + + it('should report result', async () => { + let result: SymbolInformation = { + name: 'abc', + kind: SymbolKind.Class, + location: { + uri: 'file:///abc.txt', + range: { start: { line: 0, character: 1 }, end: { line: 2, character: 3 } } + } + } + serverConnection.onRequest(DocumentSymbolRequest.type, params => { + expect(params.partialResultToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2') + serverConnection.sendProgress(progressType, params.partialResultToken, [result]) + return [] + }) + + const params: DocumentSymbolParams = { + textDocument: { uri: 'file:///abc.txt' }, + partialResultToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2' + } + let progressOK = false + clientConnection.onProgress(progressType, '3b1db4c9-e011-489e-a9d1-0653e64707c2', values => { + progressOK = (values !== undefined && values.length === 1) + }) + await clientConnection.sendRequest(DocumentSymbolRequest.type, params) + expect(progressOK).toBeTruthy() + }) + + it('should provide workDoneToken', async () => { + serverConnection.onRequest(DocumentSymbolRequest.type, params => { + expect(params.workDoneToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2') + return [] + }) + + const params: DocumentSymbolParams = { + textDocument: { uri: 'file:///abc.txt' }, + workDoneToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2' + } + await clientConnection.sendRequest(DocumentSymbolRequest.type, params) + }) + + it('should report work done progress', async () => { + serverConnection.onRequest(DocumentSymbolRequest.type, params => { + expect(params.workDoneToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2') + serverConnection.sendProgress(progressType, params.workDoneToken, { + kind: 'begin', + title: 'progress' + }) + serverConnection.sendProgress(progressType, params.workDoneToken, { + kind: 'report', + message: 'message' + }) + serverConnection.sendProgress(progressType, params.workDoneToken, { + kind: 'end', + message: 'message' + }) + return [] + }) + + const params: DocumentSymbolParams = { + textDocument: { uri: 'file:///abc.txt' }, + workDoneToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2' + } + let result = '' + clientConnection.onProgress(progressType, '3b1db4c9-e011-489e-a9d1-0653e64707c2', value => { + result += value.kind + }) + await clientConnection.sendRequest(DocumentSymbolRequest.type, params) + expect(result).toBe('beginreportend') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/converter.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/converter.test.ts new file mode 100644 index 00000000..c1e8dcc1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/converter.test.ts @@ -0,0 +1,86 @@ +import { CompletionTriggerKind, Position, TextDocumentItem, TextDocumentSaveReason } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import * as cv from '../../language-client/utils/converter' + +describe('converter', () => { + + function createDocument(): TextDocument { + return TextDocument.create('file:///1', 'css', 1, '') + } + + it('should convertToTextDocumentItem', () => { + let doc = createDocument() + expect(cv.convertToTextDocumentItem(doc).uri).toBe(doc.uri) + expect(TextDocumentItem.is(cv.convertToTextDocumentItem(doc))).toBe(true) + }) + + it('should asCloseTextDocumentParams', () => { + let doc = createDocument() + expect(cv.asCloseTextDocumentParams(doc).textDocument.uri).toBe(doc.uri) + }) + + it('should asChangeTextDocumentParams', () => { + let doc = createDocument() + expect(cv.asChangeTextDocumentParams(doc).textDocument.uri).toBe(doc.uri) + }) + + it('should asWillSaveTextDocumentParams', () => { + let res = cv.asWillSaveTextDocumentParams({ document: createDocument(), reason: TextDocumentSaveReason.Manual, waitUntil: () => {} }) + expect(res.textDocument).toBeDefined() + expect(res.reason).toBeDefined() + }) + + it('should asVersionedTextDocumentIdentifier', () => { + let res = cv.asVersionedTextDocumentIdentifier(createDocument()) + expect(res.uri).toBeDefined() + expect(res.version).toBeDefined() + }) + + it('should asSaveTextDocumentParams', () => { + let res = cv.asSaveTextDocumentParams(createDocument(), true) + expect(res.textDocument.uri).toBeDefined() + expect(res.text).toBeDefined() + res = cv.asSaveTextDocumentParams(createDocument(), false) + expect(res.text).toBeUndefined() + }) + + it('should asUri', () => { + let uri = URI.file('/tmp/a') + expect(cv.asUri(uri)).toBe(uri.toString()) + }) + + it('should asCompletionParams', () => { + let params = cv.asCompletionParams(createDocument(), Position.create(0, 0), { triggerKind: CompletionTriggerKind.Invoked }) + expect(params.textDocument).toBeDefined() + expect(params.position).toBeDefined() + expect(params.context).toBeDefined() + }) + + it('should asTextDocumentPositionParams', () => { + let params = cv.asTextDocumentPositionParams(createDocument(), Position.create(0, 0)) + expect(params.textDocument).toBeDefined() + expect(params.position).toBeDefined() + }) + + it('should asTextDocumentIdentifier', () => { + let doc = cv.asTextDocumentIdentifier(createDocument()) + expect(doc.uri).toBeDefined() + }) + + it('should asReferenceParams', () => { + let params = cv.asReferenceParams(createDocument(), Position.create(0, 0), { includeDeclaration: false }) + expect(params.textDocument.uri).toBeDefined() + expect(params.position).toBeDefined() + }) + + it('should asDocumentSymbolParams', () => { + let doc = cv.asDocumentSymbolParams(createDocument()) + expect(doc.textDocument.uri).toBeDefined() + }) + + it('should asCodeLensParams', () => { + let doc = cv.asCodeLensParams(createDocument()) + expect(doc.textDocument.uri).toBeDefined() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/delayer.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/delayer.test.ts new file mode 100644 index 00000000..874e3085 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/delayer.test.ts @@ -0,0 +1,72 @@ +/* eslint-disable */ +import assert from 'assert' +import { Delayer } from '../../language-client/utils/async' +import { wait } from '../../util/index' + +test('Delayer', () => { + let count = 0 + let factory = () => { + return Promise.resolve(++count) + } + + let delayer = new Delayer(0) + let promises: Thenable[] = [] + + assert(!delayer.isTriggered()) + + promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) })) + assert(delayer.isTriggered()) + + promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) })) + assert(delayer.isTriggered()) + + promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) })) + assert(delayer.isTriggered()) + + return Promise.all(promises).then(() => { + assert(!delayer.isTriggered()) + }).finally(() => { + delayer.dispose() + }) +}) + +test('Delayer - forceDelivery', async () => { + let count = 0 + let factory = () => { + return Promise.resolve(++count) + } + + let delayer = new Delayer(150) + delayer.forceDelivery() + delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) }) + await wait(10) + delayer.forceDelivery() + expect(count).toBe(1) + void delayer.trigger(factory) + await wait(10) + delayer.cancel() + expect(count).toBe(1) +}) + +test('Delayer - last task should be the one getting called', function() { + let factoryFactory = (n: number) => () => { + return Promise.resolve(n) + } + + let delayer = new Delayer(0) + let promises: Thenable[] = [] + + assert(!delayer.isTriggered()) + + promises.push(delayer.trigger(factoryFactory(1)).then((n) => { assert.equal(n, 3) })) + promises.push(delayer.trigger(factoryFactory(2)).then((n) => { assert.equal(n, 3) })) + promises.push(delayer.trigger(factoryFactory(3)).then((n) => { assert.equal(n, 3) })) + + const p = Promise.all(promises).then(() => { + assert(!delayer.isTriggered()) + }) + + assert(delayer.isTriggered()) + + return p +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/features.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/features.test.ts new file mode 100644 index 00000000..c82da9c5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/features.test.ts @@ -0,0 +1,1054 @@ +import * as assert from 'assert' +import path from 'path' +import { URI } from 'vscode-uri' +import { LanguageClient, ServerOptions, TransportKind, Middleware, LanguageClientOptions } from '../../language-client/index' +import { CancellationTokenSource, Color, DocumentSelector, Position, Range, DefinitionRequest, Location, HoverRequest, Hover, CompletionRequest, CompletionTriggerKind, CompletionItem, SignatureHelpRequest, SignatureHelpTriggerKind, SignatureInformation, ParameterInformation, ReferencesRequest, DocumentHighlightRequest, DocumentHighlight, DocumentHighlightKind, CodeActionRequest, CodeAction, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, ProgressToken, DocumentFormattingRequest, TextEdit, DocumentRangeFormattingRequest, DocumentOnTypeFormattingRequest, RenameRequest, WorkspaceEdit, DocumentLinkRequest, DocumentLink, DocumentColorRequest, ColorInformation, ColorPresentation, DeclarationRequest, FoldingRangeRequest, FoldingRange, ImplementationRequest, SelectionRangeRequest, SelectionRange, TypeDefinitionRequest, ProtocolRequestType, CallHierarchyPrepareRequest, CallHierarchyItem, CallHierarchyIncomingCall, CallHierarchyOutgoingCall, SemanticTokensRegistrationType, LinkedEditingRangeRequest, WillCreateFilesRequest, DidCreateFilesNotification, WillRenameFilesRequest, DidRenameFilesNotification, WillDeleteFilesRequest, DidDeleteFilesNotification, TextDocumentEdit, CancellationToken } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import helper from '../helper' +import workspace from '../../workspace' + +describe('Client integration', () => { + let client!: LanguageClient + let middleware: Middleware + let uri!: string + let document!: TextDocument + let tokenSource!: CancellationTokenSource + const position: Position = Position.create(1, 1) + const range: Range = Range.create(1, 1, 1, 2) + + function rangeEqual(range: Range, sl: number, sc: number, el: number, ec: number): void { + assert.strictEqual(range.start.line, sl) + assert.strictEqual(range.start.character, sc) + assert.strictEqual(range.end.line, el) + assert.strictEqual(range.end.character, ec) + } + + function colorEqual(color: Color, red: number, green: number, blue: number, alpha: number): void { + assert.strictEqual(color.red, red) + assert.strictEqual(color.green, green) + assert.strictEqual(color.blue, blue) + assert.strictEqual(color.alpha, alpha) + } + + function uriEqual(actual: string, expected: string): void { + assert.strictEqual(actual, expected) + } + + function isArray(value: Array | undefined | null, clazz: any, length = 1): asserts value is Array { + assert.ok(Array.isArray(value), `value is array`) + assert.strictEqual(value!.length, length, 'value has given length') + if (clazz && typeof clazz.is === 'function') { + for (let item of value) { + assert.ok(clazz.is(item)) + } + } + } + + function isDefined(value: T | undefined | null): asserts value is Exclude { + if (value === undefined || value === null) { + throw new Error(`Value is null or undefined`) + } + } + + beforeAll(async () => { + await helper.setup() + workspace.registerTextDocumentContentProvider('lsptests', { + provideTextDocumentContent: (_uri: URI) => { + return [ + 'REM @ECHO OFF', + 'cd c:\\source', + 'REM This is the location of the files that you want to sort', + 'FOR %%f IN (*.doc *.txt) DO XCOPY c:\\source\\"%%f" c:\\text /m /y', + 'REM This moves any files with a .doc or', + 'REM .txt extension from c:\\source to c:\\text', + 'REM %%f is a variable', + 'FOR %%f IN (*.jpg *.png *.bmp) DO XCOPY C:\\source\\"%%f" c:\\images /m /y', + 'REM This moves any files with a .jpg, .png,', + 'REM or .bmp extension from c:\\source to c:\\images;;', + ].join('\n') + } + }) + + uri = URI.parse('lsptests://localhost/test.bat').toString() + let doc = await workspace.loadFile(uri.toString()) + document = doc.textDocument + tokenSource = new CancellationTokenSource() + const serverModule = path.join(__dirname, './server/testServer.js') + const serverOptions: ServerOptions = { + run: { module: serverModule, transport: TransportKind.ipc }, + debug: { module: serverModule, transport: TransportKind.ipc, options: { execArgv: ['--nolazy', '--inspect=6014'] } } + } + const documentSelector: DocumentSelector = [{ scheme: 'lsptests' }] + + middleware = {} + const clientOptions: LanguageClientOptions = { + documentSelector, synchronize: {}, initializationOptions: {}, middleware + } + + client = new LanguageClient('test svr', 'Test Language Server', serverOptions, clientOptions) + client.start() + await client.onReady() + }) + + afterAll(async () => { + await client.stop() + await helper.shutdown() + }) + + test('InitializeResult', () => { + let expected = { + capabilities: { + textDocumentSync: 1, + definitionProvider: true, + hoverProvider: true, + completionProvider: { resolveProvider: true, triggerCharacters: ['"', ':'] }, + signatureHelpProvider: { + triggerCharacters: [':'], + retriggerCharacters: [':'] + }, + referencesProvider: true, + documentHighlightProvider: true, + codeActionProvider: { + resolveProvider: true + }, + documentFormattingProvider: true, + documentRangeFormattingProvider: true, + documentOnTypeFormattingProvider: { + firstTriggerCharacter: ':' + }, + renameProvider: { + prepareProvider: true + }, + documentLinkProvider: { + resolveProvider: true + }, + colorProvider: true, + declarationProvider: true, + foldingRangeProvider: true, + implementationProvider: true, + selectionRangeProvider: true, + typeDefinitionProvider: true, + callHierarchyProvider: true, + semanticTokensProvider: { + legend: { + tokenTypes: [], + tokenModifiers: [] + }, + range: true, + full: { + delta: true + } + }, + workspace: { + fileOperations: { + didCreate: { filters: [{ scheme: 'file', pattern: { glob: '**/created-static/**{/,/*.txt}' } }] }, + didRename: { + filters: [ + { scheme: 'file', pattern: { glob: '**/renamed-static/**/', matches: 'folder' } }, + { scheme: 'file', pattern: { glob: '**/renamed-static/**/*.txt', matches: 'file' } } + ] + }, + didDelete: { filters: [{ scheme: 'file', pattern: { glob: '**/deleted-static/**{/,/*.txt}' } }] }, + willCreate: { filters: [{ scheme: 'file', pattern: { glob: '**/created-static/**{/,/*.txt}' } }] }, + willRename: { + filters: [ + { scheme: 'file', pattern: { glob: '**/renamed-static/**/', matches: 'folder' } }, + { scheme: 'file', pattern: { glob: '**/renamed-static/**/*.txt', matches: 'file' } } + ] + }, + willDelete: { filters: [{ scheme: 'file', pattern: { glob: '**/deleted-static/**{/,/*.txt}' } }] }, + }, + }, + linkedEditingRangeProvider: true + }, + customResults: { + hello: 'world' + } + } + assert.deepEqual(client.initializeResult, expected) + }) + + test('Goto Definition', async () => { + const provider = client.getFeature(DefinitionRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideDefinition(document, position, tokenSource.token)) as Location + assert.strictEqual(Location.is(result), true) + uriEqual(result.uri, uri) + rangeEqual(result.range, 0, 0, 0, 1) + let middlewareCalled = false + middleware.provideDefinition = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideDefinition(document, position, tokenSource.token) + middleware.provideDefinition = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Hover', async () => { + const provider = client.getFeature(HoverRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideHover(document, position, tokenSource.token) + assert.ok(Hover.is(result)) + assert.strictEqual((result.contents as any).kind, 'plaintext') + assert.strictEqual((result.contents as any).value, 'foo') + let middlewareCalled = false + middleware.provideHover = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideHover(document, position, tokenSource.token) + middleware.provideHover = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Completion', async () => { + const provider = client.getFeature(CompletionRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideCompletionItems(document, position, tokenSource.token, { triggerKind: CompletionTriggerKind.Invoked, triggerCharacter: ':' })) as CompletionItem[] + + isArray(result, CompletionItem) + const item = result[0] + assert.strictEqual(item.label, 'item') + assert.strictEqual(item.insertText, 'text') + assert.strictEqual(item.detail, undefined) + isDefined(provider.resolveCompletionItem) + + const resolved = await provider.resolveCompletionItem(item, tokenSource.token) + isDefined(resolved) + assert.strictEqual(resolved.detail, 'detail') + + let middlewareCalled = 0 + middleware.provideCompletionItem = (document, position, context, token, next) => { + middlewareCalled++ + return next(document, position, context, token) + } + middleware.resolveCompletionItem = (item, token, next) => { + middlewareCalled++ + return next(item, token) + } + await provider.provideCompletionItems(document, position, tokenSource.token, { triggerKind: CompletionTriggerKind.Invoked, triggerCharacter: ':' }) + await provider.resolveCompletionItem(item, tokenSource.token) + middleware.provideCompletionItem = undefined + middleware.resolveCompletionItem = undefined + assert.strictEqual(middlewareCalled, 2) + }) + + test('SignatureHelpRequest', async () => { + const provider = client.getFeature(SignatureHelpRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideSignatureHelp(document, position, tokenSource.token, + { + isRetrigger: false, + triggerKind: SignatureHelpTriggerKind.Invoked, + triggerCharacter: ':' + } + ) + + assert.strictEqual(result.activeSignature, 1) + assert.strictEqual(result.activeParameter, 1) + isArray(result.signatures, SignatureInformation) + + const signature = result.signatures[0] + assert.strictEqual(signature.label, 'label') + assert.strictEqual(signature.documentation, 'doc') + isArray(signature.parameters, ParameterInformation) + + const parameter = signature.parameters[0] + assert.strictEqual(parameter.label, 'label') + assert.strictEqual(parameter.documentation, 'doc') + + let middlewareCalled = false + middleware.provideSignatureHelp = (d, p, c, t, n) => { + middlewareCalled = true + return n(d, p, c, t) + } + await provider.provideSignatureHelp(document, position, tokenSource.token, + { + isRetrigger: false, + triggerKind: SignatureHelpTriggerKind.Invoked, + triggerCharacter: ':' + } + ) + middleware.provideSignatureHelp = undefined + assert.ok(middlewareCalled) + }) + + test('References', async () => { + const provider = client.getFeature(ReferencesRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideReferences(document, position, { + includeDeclaration: true + }, tokenSource.token) + + isArray(result, Location, 2) + for (let i = 0; i < result.length; i++) { + const location = result[i] + rangeEqual(location.range, i, i, i, i) + assert.strictEqual(location.uri.toString(), document.uri.toString()) + } + + let middlewareCalled = false + middleware.provideReferences = (d, p, c, t, n) => { + middlewareCalled = true + return n(d, p, c, t) + } + await provider.provideReferences(document, position, { + includeDeclaration: true + }, tokenSource.token) + middleware.provideReferences = undefined + assert.ok(middlewareCalled) + }) + + test('Document Highlight', async () => { + const provider = client.getFeature(DocumentHighlightRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideDocumentHighlights(document, position, tokenSource.token) + + isArray(result, DocumentHighlight, 1) + + const highlight = result[0] + assert.strictEqual(highlight.kind, DocumentHighlightKind.Read) + rangeEqual(highlight.range, 2, 2, 2, 2) + + let middlewareCalled = false + middleware.provideDocumentHighlights = (d, p, t, n) => { + middlewareCalled = true + return n(d, p, t) + } + await provider.provideDocumentHighlights(document, position, tokenSource.token) + middleware.provideDocumentHighlights = undefined + assert.ok(middlewareCalled) + }) + + test('Code Actions', async () => { + const provider = client.getFeature(CodeActionRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideCodeActions(document, range, { + diagnostics: [] + }, tokenSource.token)) as CodeAction[] + + isArray(result, CodeAction) + const action = result[0] + assert.strictEqual(action.title, 'title') + assert.strictEqual(action.command?.title, 'title') + assert.strictEqual(action.command?.command, 'id') + + const resolved = (await provider.resolveCodeAction(result[0], tokenSource.token)) + assert.strictEqual(resolved?.title, 'resolved') + + let middlewareCalled = false + middleware.provideCodeActions = (d, r, c, t, n) => { + middlewareCalled = true + return n(d, r, c, t) + } + + await provider.provideCodeActions(document, range, { diagnostics: [] }, tokenSource.token) + middleware.provideCodeActions = undefined + assert.ok(middlewareCalled) + + middlewareCalled = false + middleware.resolveCodeAction = (c, t, n) => { + middlewareCalled = true + return n(c, t) + } + + await provider.resolveCodeAction!(result[0], tokenSource.token) + middleware.resolveCodeAction = undefined + assert.ok(middlewareCalled) + }) + + test('Progress', async () => { + const progressToken = 'TEST-PROGRESS-TOKEN' + const middlewareEvents: Array = [] + let currentProgressResolver: (value: unknown) => void | undefined + + // Set up middleware that calls the current resolve function when it gets its 'end' progress event. + middleware.handleWorkDoneProgress = (token: ProgressToken, params, next) => { + if (token === progressToken) { + middlewareEvents.push(params) + if (params.kind === 'end') { + setImmediate(currentProgressResolver) + } + } + return next(token, params) + } + + // Trigger multiple sample progress events. + for (let i = 0; i < 2; i++) { + await new Promise((resolve, reject) => { + currentProgressResolver = resolve + client.sendRequest( + new ProtocolRequestType('testing/sendSampleProgress'), + {}, + tokenSource.token, + ).catch(reject) + }) + } + + middleware.handleWorkDoneProgress = undefined + + // Ensure all events were handled. + assert.deepStrictEqual( + middlewareEvents.map(p => p.kind), + ['begin', 'report', 'end', 'begin', 'report', 'end'], + ) + }) + + test('Document Formatting', async () => { + const provider = client.getFeature(DocumentFormattingRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideDocumentFormattingEdits(document, { tabSize: 4, insertSpaces: false }, tokenSource.token) + + isArray(result, TextEdit) + const edit = result[0] + assert.strictEqual(edit.newText, 'insert') + rangeEqual(edit.range, 0, 0, 0, 0) + + let middlewareCalled = true + middleware.provideDocumentFormattingEdits = (d, c, t, n) => { + middlewareCalled = true + return n(d, c, t) + } + await provider.provideDocumentFormattingEdits(document, { tabSize: 4, insertSpaces: false }, tokenSource.token) + middleware.provideDocumentFormattingEdits = undefined + assert.ok(middlewareCalled) + }) + + test('Document Range Formatting', async () => { + const provider = client.getFeature(DocumentRangeFormattingRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideDocumentRangeFormattingEdits(document, range, { tabSize: 4, insertSpaces: false }, tokenSource.token) + + isArray(result, TextEdit) + const edit = result[0] + assert.strictEqual(edit.newText, '') + rangeEqual(edit.range, 1, 1, 1, 2) + + let middlewareCalled = true + middleware.provideDocumentRangeFormattingEdits = (d, r, c, t, n) => { + middlewareCalled = true + return n(d, r, c, t) + } + await provider.provideDocumentRangeFormattingEdits(document, range, { tabSize: 4, insertSpaces: false }, tokenSource.token) + middleware.provideDocumentFormattingEdits = undefined + assert.ok(middlewareCalled) + }) + + test('Document on Type Formatting', async () => { + const provider = client.getFeature(DocumentOnTypeFormattingRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideOnTypeFormattingEdits(document, position, 'a', { tabSize: 4, insertSpaces: false }, tokenSource.token) + + isArray(result, TextEdit) + const edit = result[0] + assert.strictEqual(edit.newText, 'replace') + rangeEqual(edit.range, 2, 2, 2, 3) + + let middlewareCalled = true + middleware.provideOnTypeFormattingEdits = (d, p, s, c, t, n) => { + middlewareCalled = true + return n(d, p, s, c, t) + } + await provider.provideOnTypeFormattingEdits(document, position, 'a', { tabSize: 4, insertSpaces: false }, tokenSource.token) + middleware.provideDocumentFormattingEdits = undefined + assert.ok(middlewareCalled) + }) + + test('Rename', async () => { + const provider = client.getFeature(RenameRequest.method).getProvider(document) + isDefined(provider) + isDefined(provider.prepareRename) + const prepareResult = await provider.prepareRename(document, position, tokenSource.token) as Range + + rangeEqual(prepareResult, 1, 1, 1, 2) + const renameResult = await provider.provideRenameEdits(document, position, 'newName', tokenSource.token) + assert.ok(WorkspaceEdit.is(renameResult)) + let middlewareCalled = 0 + middleware.prepareRename = (d, p, t, n) => { + middlewareCalled++ + return n(d, p, t) + } + await provider.prepareRename(document, position, tokenSource.token) + middleware.prepareRename = undefined + middleware.provideRenameEdits = (d, p, w, t, n) => { + middlewareCalled++ + return n(d, p, w, t) + } + await provider.provideRenameEdits(document, position, 'newName', tokenSource.token) + middleware.provideRenameEdits = undefined + assert.strictEqual(middlewareCalled, 2) + }) + + test('Document Link', async () => { + const provider = client.getFeature(DocumentLinkRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideDocumentLinks(document, tokenSource.token) + + isArray(result, DocumentLink) + const documentLink = result[0] + rangeEqual(documentLink.range, 1, 1, 1, 2) + + let middlewareCalled = 0 + middleware.provideDocumentLinks = (d, t, n) => { + middlewareCalled++ + return n(d, t) + } + await provider.provideDocumentLinks(document, tokenSource.token) + middleware.provideDocumentLinks = undefined + + isDefined(provider.resolveDocumentLink) + const resolved = await provider.resolveDocumentLink(documentLink, tokenSource.token) + isDefined(resolved.target) + assert.strictEqual(resolved.target.toString(), URI.file('/target.txt').toString()) + + middleware.resolveDocumentLink = (i, t, n) => { + middlewareCalled++ + return n(i, t) + } + await provider.resolveDocumentLink(documentLink, tokenSource.token) + middleware.resolveDocumentLink = undefined + assert.strictEqual(middlewareCalled, 2) + }) + + test('Document Color', async () => { + const provider = client.getFeature(DocumentColorRequest.method).getProvider(document) + isDefined(provider) + const colors = await provider.provideDocumentColors(document, tokenSource.token) + + isArray(colors, ColorInformation) + const color = colors[0] + + rangeEqual(color.range, 1, 1, 1, 2) + colorEqual(color.color, 1, 1, 1, 1) + + let middlewareCalled = 0 + middleware.provideDocumentColors = (d, t, n) => { + middlewareCalled++ + return n(d, t) + } + await provider.provideDocumentColors(document, tokenSource.token) + middleware.provideDocumentColors = undefined + + const presentations = await provider.provideColorPresentations(color.color, { document, range }, tokenSource.token) + + isArray(presentations, ColorPresentation) + const presentation = presentations[0] + assert.strictEqual(presentation.label, 'label') + + middleware.provideColorPresentations = (c, x, t, n) => { + middlewareCalled++ + return n(c, x, t) + } + await provider.provideColorPresentations(color.color, { document, range }, tokenSource.token) + middleware.provideColorPresentations = undefined + assert.strictEqual(middlewareCalled, 2) + }) + + test('Goto Declaration', async () => { + const provider = client.getFeature(DeclarationRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideDeclaration(document, position, tokenSource.token)) as Location + + uriEqual(result.uri, uri) + rangeEqual(result.range, 1, 1, 1, 2) + + let middlewareCalled = false + middleware.provideDeclaration = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideDeclaration(document, position, tokenSource.token) + middleware.provideDeclaration = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Folding Ranges', async () => { + const provider = client.getFeature(FoldingRangeRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideFoldingRanges(document, {}, tokenSource.token)) + + isArray(result, FoldingRange, 1) + const range = result[0] + assert.strictEqual(range.startLine, 1) + assert.strictEqual(range.endLine, 2) + let middlewareCalled = true + middleware.provideFoldingRanges = (d, c, t, n) => { + middlewareCalled = true + return n(d, c, t) + } + await provider.provideFoldingRanges(document, {}, tokenSource.token) + middleware.provideFoldingRanges = undefined + assert.ok(middlewareCalled) + }) + + test('Goto Implementation', async () => { + const provider = client.getFeature(ImplementationRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideImplementation(document, position, tokenSource.token)) as Location + + uriEqual(result.uri, uri) + rangeEqual(result.range, 2, 2, 3, 3) + + let middlewareCalled = false + middleware.provideImplementation = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideImplementation(document, position, tokenSource.token) + middleware.provideImplementation = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Selection Range', async () => { + const provider = client.getFeature(SelectionRangeRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideSelectionRanges(document, [position], tokenSource.token)) + + isArray(result, SelectionRange, 1) + const range = result[0] + rangeEqual(range.range, 1, 2, 3, 4) + let middlewareCalled = false + middleware.provideSelectionRanges = (d, p, t, n) => { + middlewareCalled = true + return n(d, p, t) + } + await provider.provideSelectionRanges(document, [position], tokenSource.token) + middleware.provideSelectionRanges = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Type Definition', async () => { + const provider = client.getFeature(TypeDefinitionRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.provideTypeDefinition(document, position, tokenSource.token)) as Location + + uriEqual(result.uri, uri) + rangeEqual(result.range, 2, 2, 3, 3) + + let middlewareCalled = false + middleware.provideTypeDefinition = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideTypeDefinition(document, position, tokenSource.token) + middleware.provideTypeDefinition = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Call Hierarchy', async () => { + const provider = client.getFeature(CallHierarchyPrepareRequest.method).getProvider(document) + isDefined(provider) + const result = (await provider.prepareCallHierarchy(document, position, tokenSource.token)) as CallHierarchyItem[] + expect(result.length).toBe(1) + + let middlewareCalled = false + middleware.prepareCallHierarchy = (d, p, t, n) => { + middlewareCalled = true + return n(d, p, t) + } + await provider.prepareCallHierarchy(document, position, tokenSource.token) + middleware.prepareCallHierarchy = undefined + assert.strictEqual(middlewareCalled, true) + + const item = result[0] + const incoming = (await provider.provideCallHierarchyIncomingCalls(item, tokenSource.token)) as CallHierarchyIncomingCall[] + expect(incoming.length).toBe(1) + assert.deepEqual(incoming[0].from, item) + middlewareCalled = false + middleware.provideCallHierarchyIncomingCalls = (i, t, n) => { + middlewareCalled = true + return n(i, t) + } + await provider.provideCallHierarchyIncomingCalls(item, tokenSource.token) + middleware.provideCallHierarchyIncomingCalls = undefined + assert.strictEqual(middlewareCalled, true) + + const outgoing = (await provider.provideCallHierarchyOutgoingCalls(item, tokenSource.token)) as CallHierarchyOutgoingCall[] + expect(outgoing.length).toBe(1) + assert.deepEqual(outgoing[0].to, item) + middlewareCalled = false + middleware.provideCallHierarchyOutgoingCalls = (i, t, n) => { + middlewareCalled = true + return n(i, t) + } + await provider.provideCallHierarchyOutgoingCalls(item, tokenSource.token) + middleware.provideCallHierarchyOutgoingCalls = undefined + assert.strictEqual(middlewareCalled, true) + }) + + const referenceFileUri = URI.parse('/dummy-edit') + function ensureReferenceEdit(edits: WorkspaceEdit, type: string, expectedLines: string[]) { + // // Ensure the edits are as expected. + assert.strictEqual(edits.documentChanges?.length, 1) + const edit = edits.documentChanges[0] as TextDocumentEdit + assert.strictEqual(edit.edits.length, 1) + assert.strictEqual(edit.textDocument.uri, referenceFileUri.path) + assert.strictEqual(edit.edits[0].newText.trim(), `${type}:\n${expectedLines.join('\n')}`.trim()) + } + async function ensureNotificationReceived(type: string, params: any) { + const result = await client.sendRequest( + new ProtocolRequestType('testing/lastFileOperationRequest'), + {}, + tokenSource.token, + ) + assert.strictEqual(result.type, type) + assert.deepEqual(result.params, params) + assert.deepEqual(result, { + type, + params + }) + } + + const createFiles = [ + '/my/file.txt', + '/my/file.js', + '/my/folder/', + // Static registration for tests is [operation]-static and *.txt + '/my/created-static/file.txt', + '/my/created-static/file.js', + '/my/created-static/folder/', + // Dynamic registration for tests is [operation]-dynamic and *.js + '/my/created-dynamic/file.txt', + '/my/created-dynamic/file.js', + '/my/created-dynamic/folder/', + ].map(p => URI.file(p)) + + const renameFiles = [ + ['/my/file.txt', '/my-new/file.txt'], + ['/my/file.js', '/my-new/file.js'], + ['/my/folder/', '/my-new/folder/'], + // Static registration for tests is [operation]-static and *.txt + ['/my/renamed-static/file.txt', '/my-new/renamed-static/file.txt'], + ['/my/renamed-static/file.js', '/my-new/renamed-static/file.js'], + ['/my/renamed-static/folder/', '/my-new/renamed-static/folder/'], + // Dynamic registration for tests is [operation]-dynamic and *.js + ['/my/renamed-dynamic/file.txt', '/my-new/renamed-dynamic/file.txt'], + ['/my/renamed-dynamic/file.js', '/my-new/renamed-dynamic/file.js'], + ['/my/renamed-dynamic/folder/', '/my-new/renamed-dynamic/folder/'], + ].map(([o, n]) => ({ oldUri: URI.file(o), newUri: URI.file(n) })) + + const deleteFiles = [ + '/my/file.txt', + '/my/file.js', + '/my/folder/', + // Static registration for tests is [operation]-static and *.txt + '/my/deleted-static/file.txt', + '/my/deleted-static/file.js', + '/my/deleted-static/folder/', + // Dynamic registration for tests is [operation]-dynamic and *.js + '/my/deleted-dynamic/file.txt', + '/my/deleted-dynamic/file.js', + '/my/deleted-dynamic/folder/', + ].map(p => URI.file(p)) + + test('File Operations - Will Create Files', async () => { + const feature = client.getFeature(WillCreateFilesRequest.method) + isDefined(feature) + + const sendCreateRequest = () => new Promise(async (resolve, reject) => { + void feature.send({ token: CancellationToken.None, files: createFiles, waitUntil: resolve }) + // If feature.send didn't call waitUntil synchronously then something went wrong. + reject(new Error('Feature unexpectedly did not call waitUntil synchronously')) + }) + + // Send the event and ensure the server responds with an edit referencing the + // correct files. + let edits = await sendCreateRequest() + ensureReferenceEdit( + edits, + 'WILL CREATE', + [ + 'file:///my/created-static/file.txt', + 'file:///my/created-static/folder/', + 'file:///my/created-dynamic/file.js', + 'file:///my/created-dynamic/folder/', + ], + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.willCreateFiles = (event, next) => next({ + ...event, + files: event.files.filter(f => !f.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + edits = await sendCreateRequest() + ensureReferenceEdit( + edits, + 'WILL CREATE', + [ + 'file:///my/created-static/file.txt', + 'file:///my/created-dynamic/file.js', + ], + ) + + middleware.workspace.willCreateFiles = undefined + }) + + test('File Operations - Did Create Files', async () => { + const feature = client.getFeature(DidCreateFilesNotification.method) + isDefined(feature) + + // Send the event and ensure the server reports the notification was sent. + await feature.send({ files: createFiles }) + await ensureNotificationReceived( + 'create', + { + files: [ + { uri: 'file:///my/created-static/file.txt' }, + { uri: 'file:///my/created-static/folder/' }, + { uri: 'file:///my/created-dynamic/file.js' }, + { uri: 'file:///my/created-dynamic/folder/' }, + ], + }, + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.didCreateFiles = (event, next) => next({ + files: event.files.filter(f => !f.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + await feature.send({ files: createFiles }) + await ensureNotificationReceived( + 'create', + { + files: [ + { uri: 'file:///my/created-static/file.txt' }, + { uri: 'file:///my/created-dynamic/file.js' }, + ], + }, + ) + + middleware.workspace.didCreateFiles = undefined + }) + + test('File Operations - Will Rename Files', async () => { + const feature = client.getFeature(WillRenameFilesRequest.method) + isDefined(feature) + + const sendRenameRequest = () => new Promise(async (resolve, reject) => { + void feature.send({ files: renameFiles, waitUntil: resolve }) + // If feature.send didn't call waitUntil synchronously then something went wrong. + reject(new Error('Feature unexpectedly did not call waitUntil synchronously')) + }) + + // Send the event and ensure the server responds with an edit referencing the + // correct files. + let edits = await sendRenameRequest() + ensureReferenceEdit( + edits, + 'WILL RENAME', + [ + 'file:///my/renamed-static/file.txt -> file:///my-new/renamed-static/file.txt', + 'file:///my/renamed-static/folder/ -> file:///my-new/renamed-static/folder/', + 'file:///my/renamed-dynamic/file.js -> file:///my-new/renamed-dynamic/file.js', + 'file:///my/renamed-dynamic/folder/ -> file:///my-new/renamed-dynamic/folder/', + ], + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.willRenameFiles = (event, next) => next({ + ...event, + files: event.files.filter(f => !f.oldUri.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + edits = await sendRenameRequest() + ensureReferenceEdit( + edits, + 'WILL RENAME', + [ + 'file:///my/renamed-static/file.txt -> file:///my-new/renamed-static/file.txt', + 'file:///my/renamed-dynamic/file.js -> file:///my-new/renamed-dynamic/file.js', + ], + ) + + middleware.workspace.willRenameFiles = undefined + }) + + test('File Operations - Did Rename Files', async () => { + const feature = client.getFeature(DidRenameFilesNotification.method) + isDefined(feature) + + // Send the event and ensure the server reports the notification was sent. + await feature.send({ files: renameFiles }) + await ensureNotificationReceived( + 'rename', + { + files: [ + { oldUri: 'file:///my/renamed-static/file.txt', newUri: 'file:///my-new/renamed-static/file.txt' }, + { oldUri: 'file:///my/renamed-static/folder/', newUri: 'file:///my-new/renamed-static/folder/' }, + { oldUri: 'file:///my/renamed-dynamic/file.js', newUri: 'file:///my-new/renamed-dynamic/file.js' }, + { oldUri: 'file:///my/renamed-dynamic/folder/', newUri: 'file:///my-new/renamed-dynamic/folder/' }, + ], + }, + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.didRenameFiles = (event, next) => next({ + files: event.files.filter(f => !f.oldUri.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + await feature.send({ files: renameFiles }) + await ensureNotificationReceived( + 'rename', + { + files: [ + { oldUri: 'file:///my/renamed-static/file.txt', newUri: 'file:///my-new/renamed-static/file.txt' }, + { oldUri: 'file:///my/renamed-dynamic/file.js', newUri: 'file:///my-new/renamed-dynamic/file.js' }, + ], + }, + ) + + middleware.workspace.didRenameFiles = undefined + }) + + test('File Operations - Will Delete Files', async () => { + const feature = client.getFeature(WillDeleteFilesRequest.method) + isDefined(feature) + + const sendDeleteRequest = () => new Promise(async (resolve, reject) => { + void feature.send({ files: deleteFiles, waitUntil: resolve }) + // If feature.send didn't call waitUntil synchronously then something went wrong. + reject(new Error('Feature unexpectedly did not call waitUntil synchronously')) + }) + + // Send the event and ensure the server responds with an edit referencing the + // correct files. + let edits = await sendDeleteRequest() + ensureReferenceEdit( + edits, + 'WILL DELETE', + [ + 'file:///my/deleted-static/file.txt', + 'file:///my/deleted-static/folder/', + 'file:///my/deleted-dynamic/file.js', + 'file:///my/deleted-dynamic/folder/', + ], + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.willDeleteFiles = (event, next) => next({ + ...event, + files: event.files.filter(f => !f.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + edits = await sendDeleteRequest() + ensureReferenceEdit( + edits, + 'WILL DELETE', + [ + 'file:///my/deleted-static/file.txt', + 'file:///my/deleted-dynamic/file.js', + ], + ) + + middleware.workspace.willDeleteFiles = undefined + }) + + test('File Operations - Did Delete Files', async () => { + const feature = client.getFeature(DidDeleteFilesNotification.method) + isDefined(feature) + + // Send the event and ensure the server reports the notification was sent. + await feature.send({ files: deleteFiles }) + await ensureNotificationReceived( + 'delete', + { + files: [ + { uri: 'file:///my/deleted-static/file.txt' }, + { uri: 'file:///my/deleted-static/folder/' }, + { uri: 'file:///my/deleted-dynamic/file.js' }, + { uri: 'file:///my/deleted-dynamic/folder/' }, + ], + }, + ) + + // Add middleware that strips out any folders. + middleware.workspace = middleware.workspace || {} + middleware.workspace.didDeleteFiles = (event, next) => next({ + files: event.files.filter(f => !f.path.endsWith('/')), + }) + + // Ensure we get the same results minus the folders that the middleware removed. + await feature.send({ files: deleteFiles }) + await ensureNotificationReceived( + 'delete', + { + files: [ + { uri: 'file:///my/deleted-static/file.txt' }, + { uri: 'file:///my/deleted-dynamic/file.js' }, + ], + }, + ) + + middleware.workspace.didDeleteFiles = undefined + }) + + test('Semantic Tokens', async () => { + const provider = client.getFeature(SemanticTokensRegistrationType.method).getProvider(document) + const rangeProvider = provider?.range + isDefined(rangeProvider) + const rangeResult = await rangeProvider.provideDocumentRangeSemanticTokens(document, range, tokenSource.token) + assert.ok(rangeResult !== undefined) + + let middlewareCalled = false + middleware.provideDocumentRangeSemanticTokens = (d, r, t, n) => { + middlewareCalled = true + return n(d, r, t) + } + await rangeProvider.provideDocumentRangeSemanticTokens(document, range, tokenSource.token) + middleware.provideDocumentRangeSemanticTokens = undefined + assert.strictEqual(middlewareCalled, true) + + const fullProvider = provider?.full + isDefined(fullProvider) + const fullResult = await fullProvider.provideDocumentSemanticTokens(document, tokenSource.token) + assert.ok(fullResult !== undefined) + + middlewareCalled = false + middleware.provideDocumentSemanticTokens = (d, t, n) => { + middlewareCalled = true + return n(d, t) + } + await fullProvider.provideDocumentSemanticTokens(document, tokenSource.token) + middleware.provideDocumentSemanticTokens = undefined + assert.strictEqual(middlewareCalled, true) + + middlewareCalled = false + middleware.provideDocumentSemanticTokensEdits = (d, i, t, n) => { + middlewareCalled = true + return n(d, i, t) + } + await fullProvider.provideDocumentSemanticTokensEdits!(document, '2', tokenSource.token) + middleware.provideDocumentSemanticTokensEdits = undefined + assert.strictEqual(middlewareCalled, true) + }) + + test('Linked Editing Ranges', async () => { + const provider = client.getFeature(LinkedEditingRangeRequest.method).getProvider(document) + isDefined(provider) + const result = await provider.provideLinkedEditingRanges(document, position, tokenSource.token) + + isArray(result.ranges, Range, 1) + rangeEqual(result.ranges[0], 1, 1, 1, 1) + + let middlewareCalled = false + middleware.provideLinkedEditingRange = (document, position, token, next) => { + middlewareCalled = true + return next(document, position, token) + } + await provider.provideLinkedEditingRanges(document, position, tokenSource.token) + middleware.provideTypeDefinition = undefined + assert.strictEqual(middlewareCalled, true) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/integration.test.ts b/sources_non_forked/coc.nvim/src/__tests__/client/integration.test.ts new file mode 100644 index 00000000..351e69a3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/integration.test.ts @@ -0,0 +1,123 @@ +/* eslint-disable */ +import helper from '../helper' +import * as assert from 'assert' +import * as lsclient from '../../language-client' +import path from 'path' + +beforeAll(async () => { + await helper.setup() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +async function testLanguageServer(serverOptions: lsclient.ServerOptions): Promise { + let clientOptions: lsclient.LanguageClientOptions = { + documentSelector: ['css'], + synchronize: {}, + initializationOptions: {} + } + let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions) + client.start() + await client.onReady() + expect(client.initializeResult).toBeDefined() + return client +} + +describe('Client integration', () => { + + it('should initialize use IPC channel', (done) => { + let serverModule = path.join(__dirname, './server/testInitializeResult.js') + let serverOptions: lsclient.ServerOptions = { + run: { module: serverModule, transport: lsclient.TransportKind.ipc }, + debug: { module: serverModule, transport: lsclient.TransportKind.ipc, options: { execArgv: ['--nolazy', '--inspect=6014'] } } + } + let clientOptions: lsclient.LanguageClientOptions = { + documentSelector: ['css'], + synchronize: {}, initializationOptions: {}, + middleware: { + handleDiagnostics: (uri, diagnostics, next) => { + assert.equal(uri, "uri:/test.ts") + assert.ok(Array.isArray(diagnostics)) + assert.equal(diagnostics.length, 0) + next(uri, diagnostics) + } + } + } + let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions) + client.start() + + assert.equal(client.initializeResult, undefined) + + client.onReady().then(_ => { + try { + let expected = { + capabilities: { + textDocumentSync: 1, + completionProvider: { resolveProvider: true, triggerCharacters: ['"', ':'] }, + hoverProvider: true, + renameProvider: { + prepareProvider: true + } + }, + customResults: { + "hello": "world" + } + } + assert.deepEqual(client.initializeResult, expected) + setTimeout(async () => { + await client.stop() + done() + }, 50) + } catch (e) { + done(e) + } + }, e => { + done(e) + }) + }) + + it('should initialize use stdio', async () => { + let serverModule = path.join(__dirname, './server/testInitializeResult.js') + let serverOptions: lsclient.ServerOptions = { + module: serverModule, + transport: lsclient.TransportKind.stdio + } + let client = await testLanguageServer(serverOptions) + await client.stop() + }) + + it('should initialize use pipe', async () => { + let serverModule = path.join(__dirname, './server/testInitializeResult.js') + let serverOptions: lsclient.ServerOptions = { + module: serverModule, + transport: lsclient.TransportKind.pipe + } + let client = await testLanguageServer(serverOptions) + await client.stop() + }) + + it('should initialize use socket', async () => { + let serverModule = path.join(__dirname, './server/testInitializeResult.js') + let serverOptions: lsclient.ServerOptions = { + module: serverModule, + transport: { + kind: lsclient.TransportKind.socket, + port: 8088 + } + } + let client = await testLanguageServer(serverOptions) + await client.stop() + }) + + it('should initialize as command', async () => { + let serverModule = path.join(__dirname, './server/testInitializeResult.js') + let serverOptions: lsclient.ServerOptions = { + command: 'node', + args: [serverModule, '--stdio'] + } + let client = await testLanguageServer(serverOptions) + await client.stop() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/server/testFileWatcher.js b/sources_non_forked/coc.nvim/src/__tests__/client/server/testFileWatcher.js new file mode 100644 index 00000000..6ac96e6f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/server/testFileWatcher.js @@ -0,0 +1,35 @@ +const languageserver = require('vscode-languageserver') +let connection = languageserver.createConnection() +let documents = new languageserver.TextDocuments() +documents.listen(connection) + +connection.onInitialize(() => { + let capabilities = { + textDocumentSync: documents.syncKind + } + return { capabilities } +}) + +connection.onInitialized(() => { + connection.sendRequest('client/registerCapability', { + registrations: [{ + id: 'didChangeWatchedFiles', + method: 'workspace/didChangeWatchedFiles', + registerOptions: { + watchers: [{ globPattern: "**" }] + } + }] + }) +}) + +let received + +connection.onNotification('workspace/didChangeWatchedFiles', params => { + received = params +}) + +connection.onRequest('custom/received', async () => { + return received +}) + +connection.listen() diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/server/testInitializeResult.js b/sources_non_forked/coc.nvim/src/__tests__/client/server/testInitializeResult.js new file mode 100644 index 00000000..429ac0d2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/server/testInitializeResult.js @@ -0,0 +1,36 @@ +'use strict' +Object.defineProperty(exports, "__esModule", {value: true}) +const tslib_1 = require("tslib") +const assert = tslib_1.__importStar(require("assert")) +const vscode_languageserver_1 = require("vscode-languageserver") +let connection = vscode_languageserver_1.createConnection() + +let documents = new vscode_languageserver_1.TextDocuments() +documents.listen(connection) +connection.onInitialize((params) => { + assert.equal(params.capabilities.workspace.applyEdit, true) + assert.equal(params.capabilities.workspace.workspaceEdit.documentChanges, true) + assert.deepEqual(params.capabilities.workspace.workspaceEdit.resourceOperations, [vscode_languageserver_1.ResourceOperationKind.Create, vscode_languageserver_1.ResourceOperationKind.Rename, vscode_languageserver_1.ResourceOperationKind.Delete]) + assert.equal(params.capabilities.workspace.workspaceEdit.failureHandling, vscode_languageserver_1.FailureHandlingKind.Undo) + assert.equal(params.capabilities.textDocument.completion.completionItem.deprecatedSupport, true) + assert.equal(params.capabilities.textDocument.completion.completionItem.preselectSupport, true) + assert.equal(params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport, true) + assert.equal(params.capabilities.textDocument.rename.prepareSupport, true) + let valueSet = params.capabilities.textDocument.completion.completionItemKind.valueSet + assert.equal(valueSet[0], 1) + assert.equal(valueSet[valueSet.length - 1], vscode_languageserver_1.CompletionItemKind.TypeParameter) + let capabilities = { + textDocumentSync: documents.syncKind, + completionProvider: {resolveProvider: true, triggerCharacters: ['"', ':']}, + hoverProvider: true, + renameProvider: { + prepareProvider: true + } + } + return {capabilities, customResults: {"hello": "world"}} +}) +connection.onInitialized(() => { + connection.sendDiagnostics({uri: "uri:/test.ts", diagnostics: []}) +}) +// Listen on the connection +connection.listen() diff --git a/sources_non_forked/coc.nvim/src/__tests__/client/server/testServer.js b/sources_non_forked/coc.nvim/src/__tests__/client/server/testServer.js new file mode 100644 index 00000000..af289823 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/client/server/testServer.js @@ -0,0 +1,409 @@ +const assert = require('assert') +const {URI} = require('vscode-uri') +const { + createConnection, CompletionItemKind, ResourceOperationKind, FailureHandlingKind, + DiagnosticTag, CompletionItemTag, TextDocumentSyncKind, MarkupKind, SignatureInformation, ParameterInformation, + Location, Range, DocumentHighlight, DocumentHighlightKind, CodeAction, Command, TextEdit, Position, DocumentLink, + ColorInformation, Color, ColorPresentation, FoldingRange, SelectionRange, SymbolKind, ProtocolRequestType, WorkDoneProgress, + WorkDoneProgressCreateRequest} = require('vscode-languageserver') + +const { + DidCreateFilesNotification, + DidRenameFilesNotification, + DidDeleteFilesNotification, + WillCreateFilesRequest, WillRenameFilesRequest, WillDeleteFilesRequest +} = require('vscode-languageserver-protocol') + +let connection = createConnection() + +console.log = connection.console.log.bind(connection.console) +console.error = connection.console.error.bind(connection.console) + +connection.onInitialize(params => { + assert.equal((params.capabilities.workspace).applyEdit, true) + assert.equal(params.capabilities.workspace.workspaceEdit.documentChanges, true) + assert.equal(params.capabilities.workspace.workspaceEdit.failureHandling, FailureHandlingKind.Undo) + assert.equal(params.capabilities.textDocument.completion.completionItem.deprecatedSupport, true) + assert.equal(params.capabilities.textDocument.completion.completionItem.preselectSupport, true) + assert.equal(params.capabilities.textDocument.completion.completionItem.tagSupport.valueSet.length, 1) + assert.equal(params.capabilities.textDocument.completion.completionItem.tagSupport.valueSet[0], CompletionItemTag.Deprecated) + assert.equal(params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport, true) + // assert.equal(params.capabilities.textDocument.definition.linkSupport, true) + // assert.equal(params.capabilities.textDocument.declaration.linkSupport, true) + // assert.equal(params.capabilities.textDocument.implementation.linkSupport, true) + // assert.equal(params.capabilities.textDocument.typeDefinition.linkSupport, true) + assert.equal(params.capabilities.textDocument.rename.prepareSupport, true) + assert.equal(params.capabilities.textDocument.publishDiagnostics.relatedInformation, true) + assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet.length, 2) + assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet[0], DiagnosticTag.Unnecessary) + assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet[1], DiagnosticTag.Deprecated) + assert.equal(params.capabilities.textDocument.documentLink.tooltipSupport, true) + let valueSet = params.capabilities.textDocument.completion.completionItemKind.valueSet + assert.equal(valueSet[0], 1) + assert.equal(valueSet[valueSet.length - 1], CompletionItemKind.TypeParameter) + assert.deepEqual(params.capabilities.workspace.workspaceEdit.resourceOperations, [ResourceOperationKind.Create, ResourceOperationKind.Rename, ResourceOperationKind.Delete]) + assert.equal(params.capabilities.workspace.fileOperations.willCreate, true) + + let capabilities = { + textDocumentSync: TextDocumentSyncKind.Full, + definitionProvider: true, + hoverProvider: true, + completionProvider: {resolveProvider: true, triggerCharacters: ['"', ':']}, + signatureHelpProvider: { + triggerCharacters: [':'], + retriggerCharacters: [':'] + }, + referencesProvider: true, + documentHighlightProvider: true, + codeActionProvider: { + resolveProvider: true + }, + documentFormattingProvider: true, + documentRangeFormattingProvider: true, + documentOnTypeFormattingProvider: { + firstTriggerCharacter: ':' + }, + renameProvider: { + prepareProvider: true + }, + documentLinkProvider: { + resolveProvider: true + }, + colorProvider: true, + declarationProvider: true, + foldingRangeProvider: true, + implementationProvider: true, + selectionRangeProvider: true, + typeDefinitionProvider: true, + callHierarchyProvider: true, + semanticTokensProvider: { + legend: { + tokenTypes: [], + tokenModifiers: [] + }, + range: true, + full: { + delta: true + } + }, + workspace: { + fileOperations: { + // Static reg is folders + .txt files with operation kind in the path + didCreate: { + filters: [{scheme: 'file', pattern: {glob: '**/created-static/**{/,/*.txt}'}}] + }, + didRename: { + filters: [ + {scheme: 'file', pattern: {glob: '**/renamed-static/**/', matches: 'folder'}}, + {scheme: 'file', pattern: {glob: '**/renamed-static/**/*.txt', matches: 'file'}} + ] + }, + didDelete: { + filters: [{scheme: 'file', pattern: {glob: '**/deleted-static/**{/,/*.txt}'}}] + }, + willCreate: { + filters: [{scheme: 'file', pattern: {glob: '**/created-static/**{/,/*.txt}'}}] + }, + willRename: { + filters: [ + {scheme: 'file', pattern: {glob: '**/renamed-static/**/', matches: 'folder'}}, + {scheme: 'file', pattern: {glob: '**/renamed-static/**/*.txt', matches: 'file'}} + ] + }, + willDelete: { + filters: [{scheme: 'file', pattern: {glob: '**/deleted-static/**{/,/*.txt}'}}] + }, + }, + }, + linkedEditingRangeProvider: true + } + return {capabilities, customResults: {hello: 'world'}} +}) + +connection.onInitialized(() => { + // Dynamic reg is folders + .js files with operation kind in the path + connection.client.register(DidCreateFilesNotification.type, { + filters: [{scheme: 'file', pattern: {glob: '**/created-dynamic/**{/,/*.js}'}}] + }) + connection.client.register(DidRenameFilesNotification.type, { + filters: [ + {scheme: 'file', pattern: {glob: '**/renamed-dynamic/**/', matches: 'folder'}}, + {scheme: 'file', pattern: {glob: '**/renamed-dynamic/**/*.js', matches: 'file'}} + ] + }) + connection.client.register(DidDeleteFilesNotification.type, { + filters: [{scheme: 'file', pattern: {glob: '**/deleted-dynamic/**{/,/*.js}'}}] + }) + connection.client.register(WillCreateFilesRequest.type, { + filters: [{scheme: 'file', pattern: {glob: '**/created-dynamic/**{/,/*.js}'}}] + }) + connection.client.register(WillRenameFilesRequest.type, { + filters: [ + {scheme: 'file', pattern: {glob: '**/renamed-dynamic/**/', matches: 'folder'}}, + {scheme: 'file', pattern: {glob: '**/renamed-dynamic/**/*.js', matches: 'file'}} + ] + }) + connection.client.register(WillDeleteFilesRequest.type, { + filters: [{scheme: 'file', pattern: {glob: '**/deleted-dynamic/**{/,/*.js}'}}] + }) +}) + +connection.onDeclaration((params) => { + assert.equal(params.position.line, 1) + assert.equal(params.position.character, 1) + return {uri: params.textDocument.uri, range: {start: {line: 1, character: 1}, end: {line: 1, character: 2}}} +}) + +connection.onDefinition((params) => { + assert.equal(params.position.line, 1) + assert.equal(params.position.character, 1) + return {uri: params.textDocument.uri, range: {start: {line: 0, character: 0}, end: {line: 0, character: 1}}} +}) + +connection.onHover((_params) => { + return { + contents: { + kind: MarkupKind.PlainText, + value: 'foo' + } + } +}) + +connection.onCompletion((_params) => { + return [ + {label: 'item', insertText: 'text'} + ] +}) + +connection.onCompletionResolve((item) => { + item.detail = 'detail' + return item +}) + +connection.onSignatureHelp((_params) => { + const result = { + signatures: [ + SignatureInformation.create('label', 'doc', ParameterInformation.create('label', 'doc')) + ], + activeSignature: 1, + activeParameter: 1 + } + return result +}) + +connection.onReferences((params) => { + return [ + Location.create(params.textDocument.uri, Range.create(0, 0, 0, 0)), + Location.create(params.textDocument.uri, Range.create(1, 1, 1, 1)) + ] +}) + +connection.onDocumentHighlight((_params) => { + return [ + DocumentHighlight.create(Range.create(2, 2, 2, 2), DocumentHighlightKind.Read) + ] +}) + +connection.onCodeAction((_params) => { + return [ + CodeAction.create('title', Command.create('title', 'id')) + ] +}) + +connection.onCodeActionResolve((codeAction) => { + codeAction.title = 'resolved' + return codeAction +}) + +connection.onDocumentFormatting((_params) => { + return [ + TextEdit.insert(Position.create(0, 0), 'insert') + ] +}) + +connection.onDocumentRangeFormatting((_params) => { + return [ + TextEdit.del(Range.create(1, 1, 1, 2)) + ] +}) + +connection.onDocumentOnTypeFormatting((_params) => { + return [ + TextEdit.replace(Range.create(2, 2, 2, 3), 'replace') + ] +}) + +connection.onPrepareRename((_params) => { + return Range.create(1, 1, 1, 2) +}) + +connection.onRenameRequest((_params) => { + return {documentChanges: []} +}) + +connection.onDocumentLinks((_params) => { + return [ + DocumentLink.create(Range.create(1, 1, 1, 2)) + ] +}) + +connection.onDocumentLinkResolve((link) => { + link.target = URI.file('/target.txt').toString() + return link +}) + +connection.onDocumentColor((_params) => { + return [ + ColorInformation.create(Range.create(1, 1, 1, 2), Color.create(1, 1, 1, 1)) + ] +}) + +connection.onColorPresentation((_params) => { + return [ + ColorPresentation.create('label') + ] +}) + +connection.onFoldingRanges((_params) => { + return [ + FoldingRange.create(1, 2) + ] +}) + +connection.onImplementation((params) => { + assert.equal(params.position.line, 1) + assert.equal(params.position.character, 1) + return {uri: params.textDocument.uri, range: {start: {line: 2, character: 2}, end: {line: 3, character: 3}}} +}) + +connection.onSelectionRanges((_params) => { + return [ + SelectionRange.create(Range.create(1, 2, 3, 4)) + ] +}) + +let lastFileOperationRequest +connection.workspace.onDidCreateFiles((params) => {lastFileOperationRequest = {type: 'create', params}}) +connection.workspace.onDidRenameFiles((params) => {lastFileOperationRequest = {type: 'rename', params}}) +connection.workspace.onDidDeleteFiles((params) => {lastFileOperationRequest = {type: 'delete', params}}) + +connection.onRequest( + new ProtocolRequestType('testing/lastFileOperationRequest'), + () => { + return lastFileOperationRequest + }, +) + +connection.workspace.onWillCreateFiles((params) => { + const createdFilenames = params.files.map((f) => `${f.uri}`).join('\n') + return { + documentChanges: [{ + textDocument: {uri: '/dummy-edit', version: null}, + edits: [ + TextEdit.insert(Position.create(0, 0), `WILL CREATE:\n${createdFilenames}`), + ] + }], + } +}) + +connection.workspace.onWillRenameFiles((params) => { + const renamedFilenames = params.files.map((f) => `${f.oldUri} -> ${f.newUri}`).join('\n') + return { + documentChanges: [{ + textDocument: {uri: '/dummy-edit', version: null}, + edits: [ + TextEdit.insert(Position.create(0, 0), `WILL RENAME:\n${renamedFilenames}`), + ] + }], + } +}) + +connection.workspace.onWillDeleteFiles((params) => { + const deletedFilenames = params.files.map((f) => `${f.uri}`).join('\n') + return { + documentChanges: [{ + textDocument: {uri: '/dummy-edit', version: null}, + edits: [ + TextEdit.insert(Position.create(0, 0), `WILL DELETE:\n${deletedFilenames}`), + ] + }], + } +}) + +connection.onTypeDefinition((params) => { + assert.equal(params.position.line, 1) + assert.equal(params.position.character, 1) + return {uri: params.textDocument.uri, range: {start: {line: 2, character: 2}, end: {line: 3, character: 3}}} +}) + +connection.languages.callHierarchy.onPrepare((params) => { + return [ + { + kind: SymbolKind.Function, + name: 'name', + range: Range.create(1, 1, 1, 1), + selectionRange: Range.create(2, 2, 2, 2), + uri: params.textDocument.uri + } + ] +}) + +connection.languages.callHierarchy.onIncomingCalls((params) => { + return [ + { + from: params.item, + fromRanges: [Range.create(1, 1, 1, 1)] + } + ] +}) + +connection.languages.callHierarchy.onOutgoingCalls((params) => { + return [ + { + to: params.item, + fromRanges: [Range.create(1, 1, 1, 1)] + } + ] +}) + +connection.languages.semanticTokens.onRange(() => { + return { + resultId: '1', + data: [] + } +}) + +connection.languages.semanticTokens.on(() => { + return { + resultId: '2', + data: [] + } +}) + +connection.languages.semanticTokens.onDelta(() => { + return { + resultId: '3', + data: [] + } +}) + +connection.languages.onLinkedEditingRange(() => { + return { + ranges: [Range.create(1, 1, 1, 1)], + wordPattern: '\\w' + } +}) + +connection.onRequest( + new ProtocolRequestType('testing/sendSampleProgress'), + async (_, __) => { + const progressToken = 'TEST-PROGRESS-TOKEN' + await connection.sendRequest(WorkDoneProgressCreateRequest.type, {token: progressToken}) + connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'begin', title: 'Test Progress'}) + connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'report', percentage: 50, message: 'Halfway!'}) + connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'end', message: 'Completed!'}) + }, +) + +// Listen on the connection +connection.listen() diff --git a/sources_non_forked/coc.nvim/src/__tests__/coc-settings.json b/sources_non_forked/coc.nvim/src/__tests__/coc-settings.json new file mode 100644 index 00000000..8a31d91c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/coc-settings.json @@ -0,0 +1,4 @@ +{ + "suggest.timeout": 5000, + "tslint.enable": false +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/completion/basic.test.ts b/sources_non_forked/coc.nvim/src/__tests__/completion/basic.test.ts new file mode 100644 index 00000000..de4bf257 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/completion/basic.test.ts @@ -0,0 +1,1154 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import completion from '../../completion' +import events from '../../events' +import sources from '../../sources' +import { CompleteOption, CompleteResult, ISource, SourceType } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +async function triggerCompletion(source: string): Promise { + await nvim.call('coc#start', { source }) +} + +describe('completion', () => { + describe('preferences', () => { + describe('autoTrigger', () => { + it('should not trigger when autoTrigger is none', async () => { + helper.updateConfiguration('suggest.autoTrigger', 'none') + let doc = await workspace.document + await nvim.setLine('foo football') + await doc.synchronize() + await nvim.input('of') + await helper.wait(20) + expect(completion.isActivated).toBe(false) + }) + }) + + describe('disableKind & disableMenu', () => { + it('should hide kind and menu when configured', async () => { + helper.updateConfiguration('suggest.disableKind', true) + helper.updateConfiguration('suggest.disableMenu', true) + let doc = await workspace.document + await nvim.setLine('fball football') + await doc.synchronize() + await nvim.input('of') + await helper.waitPopup() + let items = await helper.getItems() + expect(items[0].kind).toBeUndefined() + expect(items[0].menu).toBeUndefined() + }) + }) + + describe('keepCompleteopt', () => { + it('should show error when keepCompleteopt unable to work', async () => { + let prev = workspace.env.completeOpt + workspace.env.completeOpt = 'menu,preview' + helper.updateConfiguration('suggest.keepCompleteopt', true) + expect(completion.config.keepCompleteopt).toBe(false) + let line = await helper.getCmdline() + expect(line).toMatch('disabled') + workspace.env.completeOpt = prev + }) + }) + + describe('characters only', () => { + beforeEach(() => { + helper.updateConfiguration('suggest.asciiCharactersOnly', true) + }) + + it('should trigger with none ascii characters', async () => { + let doc = await workspace.document + await nvim.setLine('world') + await doc.synchronize() + await nvim.input('o') + await nvim.input('你') + await nvim.input('w') + let visible = await helper.visible('world', 'around') + expect(visible).toBe(true) + }) + + it('should not trigger with none ascii characters', async () => { + let doc = await workspace.document + await nvim.setLine('你好') + await doc.synchronize() + await nvim.input('o') + await nvim.input('你') + await helper.wait(50) + let visible = await helper.pumvisible() + expect(visible).toBe(false) + }) + + it('should consider none word character as input', async () => { + let doc = await helper.createDocument('t.vim') + let res = completion.getInput(doc, 'a#b#') + expect(res).toBe('a#b#') + }) + }) + + describe('ignore by regex', () => { + it('should trigger with number input', async () => { + let doc = await workspace.document + await nvim.setLine('1357') + await doc.synchronize() + await nvim.input('o') + await nvim.input('1') + let visible = await helper.visible('1357', 'around') + expect(visible).toBe(true) + }) + + it('should not trigger with number input', async () => { + helper.updateConfiguration('suggest.ignoreRegexps', ['[0-9]+']) + let doc = await workspace.document + await nvim.setLine('1357') + await doc.synchronize() + await nvim.input('o') + await nvim.input('1') + let visible = await helper.pumvisible() + expect(visible).toBe(false) + }) + }) + + describe('selection', () => { + it('should not select when selection is none', async () => { + helper.updateConfiguration('suggest.enablePreselect', true) + let doc = await workspace.document + await nvim.setLine('around') + await doc.synchronize() + await nvim.input('oa') + await helper.visible('around') + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await nvim.input('') + await nvim.input('') + await nvim.input('oa') + await helper.visible('around') + let context = await nvim.getVar('coc#_context') as any + expect(context.preselect).toBe(-1) + }) + + it('should select recent used item', async () => { + helper.updateConfiguration('suggest.selection', 'recentlyUsed') + helper.updateConfiguration('suggest.enablePreselect', true) + let doc = await workspace.document + await nvim.setLine('result') + await doc.synchronize() + await nvim.input('or') + await helper.visible('result') + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await nvim.input('') + await nvim.input('') + await nvim.input('or') + await helper.visible('result') + }) + + it('should select recent item by prefix', async () => { + helper.updateConfiguration('suggest.selection', 'recentlyUsedByPrefix') + helper.updateConfiguration('suggest.enablePreselect', true) + let doc = await workspace.document + await nvim.setLine('world') + await doc.synchronize() + await nvim.input('owo') + await helper.visible('world') + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await nvim.input('') + await nvim.input('') + await nvim.input('ow') + await helper.visible('world') + let context = await nvim.getVar('coc#_context') as any + expect(context.preselect).toBe(-1) + }) + }) + }) + + describe('doComplete()', () => { + it('should deactivate on doComplete error', async () => { + await helper.createDocument() + await nvim.command(`edit +setl\\ buftype=nofile`) + let option: CompleteOption = await nvim.call('coc#util#get_complete_option') + await completion.startCompletion(option) + expect(completion.isActivated).toBe(false) + }) + + it('should show slow source', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'slow', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (_opt: CompleteOption): Promise => new Promise(resolve => { + setTimeout(() => { + resolve({ items: [{ word: 'foo' }, { word: 'bar' }] }) + }, 50) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + let items = await helper.items() + expect(items.length).toBe(2) + }) + + it('should show items before slow source finished', async () => { + let source: ISource = { + name: 'fast', + enable: true, + doComplete: (_opt: CompleteOption): Promise => new Promise(resolve => { + resolve({ items: [{ word: 'foo' }, { word: 'bar' }] }) + }) + } + disposables.push(sources.addSource(source)) + let finished = false + let slowSource: ISource = { + name: 'slow', + enable: true, + doComplete: (_opt: CompleteOption): Promise => new Promise(resolve => { + setTimeout(() => { + finished = true + resolve({ items: [{ word: 'world' }] }) + }, 100) + }) + } + disposables.push(sources.addSource(slowSource)) + await nvim.input('if') + await helper.waitPopup() + expect(finished).toBe(false) + }) + }) + + describe('resumeCompletion()', () => { + it('should stop if no filtered items', async () => { + await nvim.setLine('foo ') + await nvim.input('Af') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + await nvim.input('d') + await helper.waitValue(() => { + return completion.isActivated + }, false) + }) + + it('should resume with inserted characters', async () => { + let doc = await workspace.document + await nvim.setLine('foo fat') + await doc.synchronize() + await nvim.input('of') + await nvim.setLine('fo') + await doc.synchronize() + await nvim.call('cursor', [2, 3]) + await helper.wait(50) + let items = await helper.getItems() + expect(items.length).toBeGreaterThan(0) + }) + + it('should stop with bad insert on CursorMovedI', async () => { + await nvim.setLine('foo fat') + await nvim.input('of') + await nvim.setLine('f a') + await nvim.call('cursor', [2, 4]) + await helper.wait(30) + let visible = await helper.pumvisible() + expect(visible).toBe(false) + }) + + it('should deactivate without filtered items', async () => { + let doc = await workspace.document + await nvim.setLine('foo fbi ') + await doc.synchronize() + await nvim.input('Af') + await helper.waitPopup() + await nvim.input('c') + await helper.waitFor('pumvisible', [], 0) + let items = await helper.items() + expect(items.length).toBe(0) + expect(completion.isActivated).toBe(false) + }) + + it('should deactivate when insert space', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'empty', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (_opt: CompleteOption): Promise => new Promise(resolve => { + resolve({ items: [{ word: 'foo bar' }] }) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + let items = await helper.items() + expect(items[0].word).toBe('foo bar') + await nvim.input(' ') + await helper.waitFor('pumvisible', [], 0) + }) + + it('should use resume input to filter', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'source', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (): Promise => new Promise(resolve => { + setTimeout(() => { + resolve({ items: [{ word: 'foo' }, { word: 'bar' }] }) + }, 60) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.wait(20) + await nvim.input('f') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + let items = await helper.items() + expect(items.length).toBe(1) + expect(items[0].word).toBe('foo') + }) + + it('should filter slow source', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'slow', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (): Promise => new Promise(resolve => { + setTimeout(() => { + resolve({ items: [{ word: 'foo' }, { word: 'bar' }] }) + }, 100) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.f') + await helper.waitPopup() + await nvim.input('o') + await helper.waitFor('eval', ['len(coc#_context["candidates"])'], 1) + let items = await helper.items() + expect(items.length).toBe(1) + expect(items[0].word).toBe('foo') + }) + + it('should complete inComplete source', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'inComplete', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: async (opt: CompleteOption): Promise => { + if (opt.input.length <= 1) { + return { isIncomplete: true, items: [{ word: 'foo' }, { word: opt.input }] } + } + await helper.wait(10) + return { isIncomplete: false, items: [{ word: 'foo' }, { word: opt.input }] } + } + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + await nvim.input('a') + await helper.wait(20) + await nvim.input('b') + }) + + it('should not complete inComplete source when isIncomplete is false', async () => { + let lastOption: CompleteOption + let source: ISource = { + priority: 0, + enable: true, + name: 'inComplete', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: async (opt: CompleteOption): Promise => { + lastOption = opt + await helper.wait(30) + if (opt.input.length <= 1) { + return { isIncomplete: true, items: [{ word: 'foobar' }] } + } + return { isIncomplete: false, items: [{ word: 'foobar' }] } + } + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + await nvim.input('fo') + await helper.wait(50) + await nvim.input('b') + await helper.wait(50) + expect(completion.isActivated).toBe(true) + }) + + it('should filter when item has selected with noselect', async () => { + helper.updateConfiguration('suggest.noselect', false) + let source: ISource = { + priority: 0, + enable: true, + name: 'filter', + sourceType: SourceType.Service, + doComplete: (): Promise => { + return Promise.resolve({ items: [{ word: 'foo' }, { word: 'fox' }, { word: 'fat' }] }) + } + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('o') + await helper.waitFor('eval', ['len(coc#_context["candidates"])'], 2) + await nvim.input('o') + await helper.waitFor('eval', ['len(coc#_context["candidates"])'], 1) + }) + + it('should filter when type character after item selected without handle complete done', async () => { + let input: string + let fn = jest.fn() + let source: ISource = { + priority: 0, + enable: true, + name: 'filter', + sourceType: SourceType.Service, + doComplete: (opt): Promise => { + input = opt.input + if (input == 'f') return Promise.resolve({ items: [{ word: 'fo' }] }) + if (input == 'foo') return Promise.resolve({ items: [{ word: 'foobar' }, { word: 'foot' }] }) + return Promise.resolve({ items: [] }) + }, + onCompleteDone: () => { + fn() + } + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('') + await helper.wait(20) + await nvim.input('o') + await helper.waitPopup() + expect(fn).toBeCalledTimes(0) + }) + }) + + describe('TextChangedI', () => { + it('should respect commitCharacter on TextChangedI', async () => { + helper.updateConfiguration('suggest.acceptSuggestionOnCommitCharacter', true) + helper.updateConfiguration('suggest.noselect', false) + let source: ISource = { + enable: true, + name: 'commit', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (opt: CompleteOption): Promise => { + if (opt.triggerCharacter == '.') { + return Promise.resolve({ items: [{ word: 'bar' }] }) + } + return Promise.resolve({ items: [{ word: 'foo' }] }) + }, + shouldCommit: (_item, character) => character == '.' + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('.') + await helper.waitFor('getline', ['.'], 'foo.') + }) + }) + + describe('TextChangedP', () => { + it('should stop when input length below option input length', async () => { + let doc = await workspace.document + await nvim.setLine('foo fbi ') + await doc.synchronize() + await nvim.input('Af') + await helper.waitPopup() + await nvim.input('') + await helper.waitFor('getline', ['.'], 'foo fbi ') + expect(completion.isActivated).toBe(false) + }) + + it('should filter on none keyword input', async () => { + let source: ISource = { + priority: 99, + enable: true, + name: 'temp', + sourceType: SourceType.Service, + doComplete: (_opt: CompleteOption): Promise => Promise.resolve({ items: [{ word: 'foo#abc' }] }), + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('#') + await helper.wait(50) + let items = await helper.getItems() + expect(items[0].word).toBe('foo#abc') + }) + + it('should cancel on InsertLeave', async () => { + let source: ISource = { + priority: 99, + enable: true, + name: 'temp', + sourceType: SourceType.Service, + doComplete: (_opt: CompleteOption): Promise => Promise.resolve({ items: [{ word: 'foo#abc' }] }), + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('') + await helper.wait(50) + expect(completion.isActivated).toBe(false) + }) + + it('should cancel on CursorMoved', async () => { + let buf = await nvim.buffer + await buf.setLines(['', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let source: ISource = { + priority: 99, + enable: true, + name: 'temp', + sourceType: SourceType.Service, + doComplete: (_opt: CompleteOption): Promise => Promise.resolve({ items: [{ word: 'foo#abc' }] }), + } + disposables.push(sources.addSource(source)) + await nvim.input('if') + await helper.waitPopup() + void events.fire('CompleteDone', [{}]) + await helper.wait(10) + await events.fire('CursorMovedI', [buf.id, [2, 1]]) + expect(completion.isActivated).toBe(false) + await nvim.input('') + }) + + it('should use source-provided score', async () => { + let source: ISource = { + priority: 0, + enable: true, + name: 'source', + sourceType: SourceType.Service, + doComplete: (_opt: CompleteOption): Promise => Promise.resolve({ + items: [ + { word: 'candidate_a', sourceScore: 0.1 }, + { word: 'candidate_b', sourceScore: 10 }, + { word: 'candidate_c' }, + ] + }), + } + disposables.push(sources.addSource(source)) + await nvim.input('ocand') + await helper.waitPopup() + let items = await helper.getItems() + expect(items[0].word).toBe('candidate_b') + expect(items[1].word).toBe('candidate_c') + expect(items[2].word).toBe('candidate_a') + }) + + it('should do resolve for complete item', async () => { + let resolved = false + let source: ISource = { + priority: 0, + enable: true, + name: 'resolve', + sourceType: SourceType.Service, + triggerCharacters: ['.'], + doComplete: (_opt: CompleteOption): Promise => Promise.resolve({ items: [{ word: 'foo' }] }), + onCompleteResolve: item => { + resolved = true + item.info = 'detail' + } + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], '.foo') + expect(resolved).toBe(true) + }) + }) + + describe('CompleteDone', () => { + it('should fix word on CompleteDone', async () => { + let doc = await workspace.document + await nvim.setLine('fball football') + await doc.synchronize() + await nvim.input('i') + await nvim.call('cursor', [1, 2]) + let option: CompleteOption = await nvim.call('coc#util#get_complete_option') + await completion.startCompletion(option) + await helper.waitPopup() + let items = await helper.items() + expect(items.length).toBe(1) + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 'football football') + }) + }) + + describe('InsertEnter', () => { + beforeEach(() => { + helper.updateConfiguration('suggest.triggerAfterInsertEnter', true) + }) + + it('should trigger completion if triggerAfterInsertEnter is true', async () => { + let doc = await workspace.document + await nvim.setLine('foo fo') + await doc.synchronize() + await nvim.input('A') + await doc.synchronize() + await helper.waitPopup() + expect(completion.isActivated).toBe(true) + }) + + it('should not trigger when input length too small', async () => { + await nvim.setLine('foo ') + await nvim.input('A') + await helper.wait(30) + expect(completion.isActivated).toBe(false) + }) + }) + + describe('trigger completion', () => { + it('should trigger complete on trigger patterns match', async () => { + let source: ISource = { + priority: 99, + enable: true, + name: 'temp', + triggerPatterns: [/EM/], + sourceType: SourceType.Service, + doComplete: (opt: CompleteOption): Promise => { + if (!opt.input.startsWith('EM')) return null + return Promise.resolve({ + items: [ + { word: 'foo', filterText: 'EMfoo' }, + { word: 'bar', filterText: 'EMbar' } + ] + }) + }, + } + disposables.push(sources.addSource(source)) + await nvim.input('i') + await nvim.input('EM') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBe(2) + }) + + it('should cancel on backspace', async () => { + let doc = await workspace.document + await nvim.setLine('foo bar') + await doc.synchronize() + await nvim.input('of') + let res = await helper.visible('foo', 'around') + expect(res).toBe(true) + await nvim.input('') + await helper.waitFor('pumvisible', [], 0) + }) + + it('should trigger on first letter insert', async () => { + await nvim.setLine('foo bar') + await helper.wait(30) + await nvim.input('of') + let res = await helper.visible('foo', 'around') + expect(res).toBe(true) + }) + + it('should trigger on force refresh', async () => { + let doc = await workspace.document + await nvim.setLine('foo f') + await doc.synchronize() + await nvim.input('A') + await nvim.call('coc#start') + let res = await helper.visible('foo', 'around') + expect(res).toBe(true) + }) + + it('should filter and sort on increment search', async () => { + let doc = await workspace.document + await nvim.setLine('forceDocumentSync format fallback') + await doc.synchronize() + await nvim.input('of') + await helper.waitPopup() + let items = await helper.getItems() + await nvim.input('oa') + await helper.waitFor('eval', ['len(coc#_context["candidates"])'], 1) + items = await helper.getItems() + expect(items.findIndex(o => o.word == 'fallback')).toBe(-1) + }) + + it('should not trigger on insert enter', async () => { + let doc = await workspace.document + await nvim.setLine('foo bar') + await doc.synchronize() + await nvim.input('o') + let visible = await nvim.call('pumvisible') + expect(visible).toBe(0) + }) + + it('should filter on fast input', async () => { + let doc = await workspace.document + await nvim.setLine('foo bar') + await doc.synchronize() + await nvim.input('oba') + await helper.waitPopup() + let items = await helper.getItems() + let item = items.find(o => o.word == 'foo') + expect(item).toBeFalsy() + expect(items[0].word).toBe('bar') + }) + + it('should filter completion when type none trigger character', async () => { + let source: ISource = { + name: 'test', + priority: 10, + enable: true, + firstMatch: false, + sourceType: SourceType.Native, + triggerCharacters: [], + doComplete: async (): Promise => { + let result: CompleteResult = { + items: [{ word: 'if(' }] + } + return Promise.resolve(result) + } + } + disposables.push(sources.addSource(source)) + await nvim.setLine('') + await nvim.input('iif') + await helper.waitPopup() + await nvim.input('(') + await helper.wait(50) + let res = await helper.pumvisible() + expect(res).toBe(true) + }) + + it('should trigger on triggerCharacters', async () => { + let source: ISource = { + name: 'trigger', + enable: true, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo' }] + }) + } + disposables.push(sources.addSource(source)) + let source1: ISource = { + name: 'trigger1', + enable: true, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'bar' }] + }) + } + disposables.push(sources.addSource(source1)) + await nvim.input('i.') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBe(2) + }) + + it('should fix start column', async () => { + let source: ISource = { + name: 'test', + priority: 10, + enable: true, + firstMatch: false, + sourceType: SourceType.Native, + triggerCharacters: [], + doComplete: async (): Promise => { + let result: CompleteResult = { + startcol: 0, + items: [{ word: 'foo.bar' }] + } + return Promise.resolve(result) + } + } + let disposable = sources.addSource(source) + await nvim.setLine('foo.') + await nvim.input('Ab') + await helper.waitPopup() + let val = await nvim.getVar('coc#_context') as any + expect(val.start).toBe(0) + disposable.dispose() + }) + + it('should should complete items without input', async () => { + await workspace.document + let source: ISource = { + enable: true, + name: 'trigger', + priority: 10, + sourceType: SourceType.Native, + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo' }, { word: 'bar' }] + }) + } + disposables.push(sources.addSource(source)) + await nvim.command('inoremap coc#refresh()') + await nvim.input('i') + await helper.wait(30) + await nvim.input('') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBeGreaterThan(1) + }) + + it('should show float window', async () => { + let source: ISource = { + name: 'float', + priority: 10, + enable: true, + sourceType: SourceType.Native, + doComplete: (): Promise => Promise.resolve({ + items: [{ word: 'foo', info: 'bar' }] + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i') + await helper.wait(30) + await nvim.input('f') + await helper.waitPopup() + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await helper.wait(100) + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(1) + let res = await helper.visible('foo', 'float') + expect(res).toBe(true) + }) + + it('should trigger on triggerPatterns', async () => { + let source: ISource = { + name: 'pattern', + priority: 10, + enable: true, + sourceType: SourceType.Native, + triggerPatterns: [/\w+\.$/], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo' }] + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i') + await helper.wait(10) + await nvim.input('.') + await helper.wait(30) + let pumvisible = await nvim.call('pumvisible') + expect(pumvisible).toBe(0) + await nvim.input('a') + await helper.wait(30) + await nvim.input('.') + await helper.waitPopup() + let res = await helper.visible('foo', 'pattern') + expect(res).toBe(true) + }) + + it('should not trigger triggerOnly source', async () => { + await nvim.setLine('foo bar') + let source: ISource = { + name: 'pattern', + triggerOnly: true, + priority: 10, + enable: true, + sourceType: SourceType.Native, + triggerPatterns: [/^From:\s*/], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo' }] + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('o') + await helper.wait(10) + await nvim.input('f') + await helper.wait(10) + let res = await helper.visible('foo', 'around') + expect(res).toBe(true) + let items = await helper.items() + expect(items.length).toBe(1) + }) + + it('should not trigger when cursor moved', async () => { + let source: ISource = { + name: 'trigger', + priority: 10, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo' }] + }) + } + disposables.push(sources.addSource(source)) + await nvim.setLine('.a') + await nvim.input('A') + await nvim.eval('feedkeys("\\")') + await helper.wait(10) + await nvim.eval('feedkeys("\\")') + await helper.wait(20) + let visible = await nvim.call('pumvisible') + expect(visible).toBe(0) + }) + + it('should trigger when completion is not completed', async () => { + let token: CancellationToken + let promise = new Promise(resolve => { + let source: ISource = { + name: 'completion', + priority: 10, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (opt, cancellationToken): Promise => { + if (opt.triggerCharacter != '.') { + token = cancellationToken + resolve(undefined) + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + resolve({ items: [{ word: 'foo' }] }) + }, 200) + if (cancellationToken.isCancellationRequested) { + clearTimeout(timer) + reject(new Error('Cancelled')) + } + }) + } + return Promise.resolve({ + items: [{ word: 'bar' }] + }) + } + } + disposables.push(sources.addSource(source)) + }) + await nvim.input('if') + await promise + await nvim.input('.') + await helper.waitPopup() + await helper.visible('bar', 'completion') + expect(token).toBeDefined() + expect(token.isCancellationRequested).toBe(true) + }) + }) + + describe('completion results', () => { + it('should limit results for low priority source', async () => { + let doc = await workspace.document + helper.updateConfiguration('suggest.lowPrioritySourceLimit', 2) + await nvim.setLine('filename filepath find filter findIndex') + await doc.synchronize() + await nvim.input('of') + await helper.waitPopup() + let items = await helper.getItems() + items = items.filter(o => o.menu == '[A]') + expect(items.length).toBe(2) + }) + + it('should limit result for high priority source', async () => { + helper.updateConfiguration('suggest.highPrioritySourceLimit', 2) + let source: ISource = { + name: 'high', + priority: 90, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: ['filename', 'filepath', 'filter', 'file'].map(key => ({ word: key })) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBeGreaterThan(1) + }) + + it('should truncate label of complete items', async () => { + helper.updateConfiguration('suggest.labelMaxLength', 10) + let source: ISource = { + name: 'high', + priority: 90, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: ['a', 'b', 'c', 'd'].map(key => ({ word: key.repeat(20) })) + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i.') + await helper.waitPopup() + let items = await helper.getItems() + for (let item of items) { + if (!item.abbr) continue + expect(item.abbr.length).toBeLessThanOrEqual(10) + } + }) + + it('should delete previous items when complete items is null', async () => { + let source1: ISource = { + name: 'source1', + priority: 90, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (): Promise => Promise.resolve({ + items: [{ word: 'foo', dup: 1 }] + }) + } + let source2: ISource = { + name: 'source2', + priority: 90, + enable: true, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (opt: CompleteOption): Promise => { + let result: CompleteResult = opt.input == 'foo' ? null : { + items: [{ word: 'foo', dup: 1 }], isIncomplete: true + } + return Promise.resolve(result) + } + } + disposables.push(sources.addSource(source1)) + disposables.push(sources.addSource(source2)) + await nvim.input('i') + await nvim.input('.f') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toEqual(2) + await nvim.input('oo') + await helper.waitFor('eval', ['len(coc#_context["candidates"])'], 1) + items = await helper.getItems() + expect(items.length).toEqual(1) + expect(items[0].word).toBe('foo') + }) + }) + + describe('fix indent', () => { + it('should indent lines on TextChangedP #1', async () => { + let doc = await workspace.document as any + doc._indentkeys = '=~end,0=\\item' + let source: ISource = { + name: 'source1', + priority: 90, + enable: true, + sourceType: SourceType.Native, + doComplete: async (): Promise => Promise.resolve({ + items: [ + { word: 'item' }, + { word: 'items' }, + { word: 'END' }, + { word: 'ENDIF' } + ] + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i') + await helper.wait(10) + await nvim.input(' \\ite') + await helper.waitPopup() + await nvim.input('m') + await helper.waitFor('getline', ['.'], '\\item') + await nvim.input('') + await helper.wait(30) + await nvim.input(' END') + await helper.waitFor('getline', ['.'], 'END') + }) + + it('should trigger completion after indent change', async () => { + let doc = await workspace.document as any + doc._indentkeys = '=end' + let source: ISource = { + name: 'source1', + priority: 90, + enable: true, + sourceType: SourceType.Native, + doComplete: async (): Promise => Promise.resolve({ + items: [ + { word: 'endif' }, + { word: 'endfunction' } + ] + }) + } + disposables.push(sources.addSource(source)) + await nvim.input('i') + await helper.wait(10) + await nvim.input(' en') + await helper.waitPopup() + await nvim.input('d') + await helper.waitFor('getline', ['.'], 'end') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBeGreaterThan(0) + }) + }) + + describe('Character insert', () => { + beforeAll(() => { + let source: ISource = { + name: 'insert', + firstMatch: false, + sourceType: SourceType.Native, + triggerCharacters: ['.'], + doComplete: async (opt): Promise => { + if (opt.word === 'f') return { items: [{ word: 'foo' }] } + if (!opt.triggerCharacter) return { items: [] } + let result: CompleteResult = { + items: [{ word: 'one' }, { word: 'two' }] + } + return Promise.resolve(result) + } + } + sources.addSource(source) + }) + + afterAll(() => { + sources.removeSource('insert') + }) + + it('should keep selected text after text change', async () => { + let doc = await workspace.document + await nvim.setLine('f') + await nvim.input('A') + await doc.synchronize() + await triggerCompletion('insert') + await helper.waitPopup() + await nvim.call('nvim_select_popupmenu_item', [0, true, false, {}]) + let line = await nvim.line + expect(line).toBe('foo') + await nvim.exec(` + noa call setline('.', 'foobar') + noa call cursor(1, 7) + `) + await helper.wait(50) + let res = await helper.pumvisible() + expect(res).toBe(false) + line = await nvim.line + expect(line).toBe('foobar') + }) + + it('should trigger specific sources by api', async () => { + let text = 'foo bar f' + await nvim.setLine(text) + await nvim.input('A') + await triggerCompletion('insert') + await helper.waitPopup() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/completion/float.test.ts b/sources_non_forked/coc.nvim/src/__tests__/completion/float.test.ts new file mode 100644 index 00000000..a5ae3ead --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/completion/float.test.ts @@ -0,0 +1,198 @@ +import { Neovim } from '@chemzqm/neovim' +import Floating from '../../completion/floating' +import sources from '../../sources' +import { CompleteResult, FloatConfig, ISource, SourceType } from '../../types' +import helper from '../helper' + +let nvim: Neovim +let source: ISource +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + source = { + name: 'float', + priority: 10, + enable: true, + sourceType: SourceType.Native, + doComplete: (): Promise => Promise.resolve({ + items: [{ + word: 'foo', + info: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' + }, { + word: 'foot', + info: 'foot' + }, { + word: 'football', + }] + }) + } + sources.addSource(source) +}) + +afterAll(async () => { + sources.removeSource(source) + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('completion float', () => { + it('should not show float window when disabled', async () => { + helper.updateConfiguration('suggest.floatEnable', false) + await helper.edit() + await nvim.input('if') + await helper.visible('foo', 'float') + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(0) + }) + + it('should cancel float window', async () => { + await helper.edit() + await nvim.input('if') + await helper.visible('foo', 'float') + let items = await helper.getItems() + expect(items[0].word).toBe('foo') + expect(items[0].info.length > 0).toBeTruthy() + await helper.selectCompleteItem(0) + await helper.wait(30) + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(0) + }) + + it('should adjust float window position', async () => { + await helper.edit() + await nvim.setLine(' '.repeat(70)) + await nvim.input('Af') + await helper.visible('foo', 'float') + await nvim.input('') + await helper.wait(100) + let floatWin = await helper.getFloat() + let config = await floatWin.getConfig() + expect(config.col + config.width).toBeLessThan(180) + }) + + it('should redraw float window on item change', async () => { + await helper.edit() + await nvim.setLine(' '.repeat(70)) + await nvim.input('Af') + await helper.visible('foo', 'float') + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await helper.wait(50) + await nvim.input('') + await helper.wait(100) + let floatWin = await helper.getFloat() + let buf = await floatWin.buffer + let lines = await buf.lines + expect(lines.length).toBeGreaterThan(0) + expect(lines[0]).toMatch('foot') + }) + + it('should hide float window when item info is empty', async () => { + await helper.edit() + await nvim.setLine(' '.repeat(70)) + await nvim.input('Af') + await helper.visible('foo', 'float') + await nvim.call('nvim_select_popupmenu_item', [0, false, false, {}]) + await helper.wait(10) + await nvim.input('') + await helper.wait(10) + await nvim.input('') + await helper.wait(100) + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(0) + }) + + it('should hide float window after completion', async () => { + await helper.edit() + await nvim.setLine(' '.repeat(70)) + await nvim.input('Af') + await helper.visible('foo', 'float') + await nvim.input('') + await helper.wait(100) + await nvim.input('') + await helper.wait(30) + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(0) + }) +}) + +describe('float config', () => { + beforeEach(async () => { + await nvim.setLine('foob foot') + await nvim.input('of') + await nvim.input('') + }) + + async function createFloat(config: Partial, docs = [{ filetype: 'txt', content: 'doc' }], isVim = false): Promise { + let floating = new Floating(nvim, isVim) + let bounding = { col: 6, row: 2, height: 3, width: 16, scrollbar: false } + await floating.show(docs, bounding, Object.assign({ + excludeImages: true, + border: false, + }, config)) + return floating + } + + async function getFloat(): Promise { + let ids = await nvim.call('coc#float#get_float_win_list') + return Array.isArray(ids) ? ids[0] || -1 : -1 + } + + async function getRelated(winid: number, kind: string): Promise { + if (!winid || winid == -1) return -1 + let win = nvim.createWindow(winid) + let related = await win.getVar('related') as number[] + if (!related || !related.length) return -1 + for (let id of related) { + let w = nvim.createWindow(id) + let v = await w.getVar('kind') + if (v == kind) { + return id + } + } + return -1 + } + + it('should not shown with empty lines', async () => { + await createFloat({}, [{ filetype: 'txt', content: '' }]) + let winid = await nvim.call('GetFloatWin') + expect(winid).toBe(0) + }) + + it('should shown on vim', async () => { + let float = await createFloat({}, [{ filetype: 'txt', content: 'ff' }], true) + let winid = await nvim.call('GetFloatWin') + expect(winid).toBeGreaterThan(0) + float.close() + }) + + it('should show window with border', async () => { + await createFloat({ border: true }) + let winid = await getFloat() + expect(winid).toBeGreaterThan(0) + let id = await getRelated(winid, 'border') + expect(id).toBeGreaterThan(0) + }) + + it('should change window highlights', async () => { + await createFloat({ border: true, highlight: 'WarningMsg', borderhighlight: 'MoreMsg' }) + let winid = await getFloat() + expect(winid).toBeGreaterThan(0) + let win = nvim.createWindow(winid) + let res = await win.getOption('winhl') as string + expect(res).toMatch('WarningMsg') + let id = await getRelated(winid, 'border') + expect(id).toBeGreaterThan(0) + win = nvim.createWindow(id) + res = await win.getOption('winhl') as string + expect(res).toMatch('MoreMsg') + }) + + it('should add shadow and winblend', async () => { + await createFloat({ shadow: true, winblend: 30 }) + let winid = await getFloat() + expect(winid).toBeGreaterThan(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/completion/language.test.ts b/sources_non_forked/coc.nvim/src/__tests__/completion/language.test.ts new file mode 100644 index 00000000..5184b992 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/completion/language.test.ts @@ -0,0 +1,317 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import { CompletionItem, CompletionList, InsertTextFormat, Position, Range, TextEdit } from 'vscode-languageserver-types' +import languages from '../../languages' +import { CompletionItemProvider } from '../../provider' +import snippetManager from '../../snippets/manager' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('language source', () => { + describe('additionalTextEdits', () => { + it('should fix cursor position with plain text on additionalTextEdits', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'foo', + filterText: 'foo', + additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'a\nbar')] + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('if') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 'barfoo') + }) + + it('should fix cursor position with snippet on additionalTextEdits', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'if', + insertTextFormat: InsertTextFormat.Snippet, + textEdit: { range: Range.create(0, 0, 0, 1), newText: 'if($1)' }, + additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')], + preselect: true + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('ii') + await helper.waitPopup() + let res = await helper.getItems() + let idx = res.findIndex(o => o.menu == '[edit]') + await helper.selectCompleteItem(idx) + await helper.waitFor('col', ['.'], 8) + }) + + it('should fix cursor position with plain text snippet on additionalTextEdits', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'if', + insertTextFormat: InsertTextFormat.Snippet, + textEdit: { range: Range.create(0, 0, 0, 2), newText: 'do$0' }, + additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')], + preselect: true + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('iif') + await helper.waitPopup() + let items = await helper.getItems() + let idx = items.findIndex(o => o.word == 'do' && o.menu == '[edit]') + await helper.selectCompleteItem(idx) + await helper.waitFor('getline', ['.'], 'bar do') + await helper.waitFor('col', ['.'], 7) + }) + + it('should fix cursor position with nested snippet on additionalTextEdits', async () => { + let res = await snippetManager.insertSnippet('func($1)$0') + expect(res).toBe(true) + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'if', + insertTextFormat: InsertTextFormat.Snippet, + insertText: 'do$0', + additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')], + preselect: true + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('if') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 'bar func(do)') + let [, lnum, col] = await nvim.call('getcurpos') + expect(lnum).toBe(1) + expect(col).toBe(12) + }) + + it('should fix cursor position and keep placeholder with snippet on additionalTextEdits', async () => { + let text = 'foo0bar1' + await nvim.setLine(text) + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'var', + insertTextFormat: InsertTextFormat.Snippet, + textEdit: { range: Range.create(0, text.length + 1, 0, text.length + 1), newText: '${1:foo} = foo0bar1' }, + additionalTextEdits: [TextEdit.del(Range.create(0, 0, 0, text.length + 1))], + preselect: true + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.'])) + await nvim.input('A.') + await helper.waitPopup() + let res = await helper.getItems() + let idx = res.findIndex(o => o.menu == '[edit]') + await helper.selectCompleteItem(idx) + await helper.waitFor('getline', ['.'], 'foo = foo0bar1') + await helper.wait(50) + expect(snippetManager.session).toBeDefined() + let [, lnum, col] = await nvim.call('getcurpos') + expect(lnum).toBe(1) + expect(col).toBe(3) + }) + + it('should cancel current snippet session when additionalTextEdits inside snippet', async () => { + await nvim.input('i') + await snippetManager.insertSnippet('foo($1, $2)$0', true) + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'bar', + insertTextFormat: InsertTextFormat.Snippet, + textEdit: { range: Range.create(0, 4, 0, 5), newText: 'bar($1)' }, + additionalTextEdits: [TextEdit.del(Range.create(0, 0, 0, 3))] + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.'])) + await nvim.input('b') + await helper.waitPopup() + let res = await helper.getItems() + let idx = res.findIndex(o => o.menu == '[edit]') + await helper.selectCompleteItem(idx) + await helper.waitFor('getline', ['.'], '(bar(), )') + let col = await nvim.call('col', ['.']) + expect(col).toBe(6) + }) + }) + + describe('filterText', () => { + it('should fix input for snippet item', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'foo', + filterText: 'foo', + insertText: '${1:foo}($2)', + insertTextFormat: InsertTextFormat.Snippet, + }] + } + disposables.push(languages.registerCompletionItemProvider('snippets-test', 'st', null, provider)) + await nvim.input('if') + await helper.waitPopup() + await nvim.input('') + await helper.waitFor('getline', ['.'], 'foo') + }) + + it('should fix filterText of complete item', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'name', + sortText: '11', + textEdit: { + range: Range.create(0, 1, 0, 2), + newText: '?.name' + } + }] + } + disposables.push(languages.registerCompletionItemProvider('name', 'N', null, provider, ['.'])) + await nvim.setLine('t') + await nvim.input('A.') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 't?.name') + }) + }) + + describe('inComplete result', () => { + it('should filter in complete request', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (doc, pos, token, context): Promise => { + let option = (context as any).option + if (context.triggerCharacter == '.') { + return { + isIncomplete: true, + items: [ + { + label: 'foo' + }, { + label: 'bar' + } + ] + } + } + if (option.input == 'f') { + if (token.isCancellationRequested) return + return { + isIncomplete: true, + items: [ + { + label: 'foo' + } + ] + } + } + if (option.input == 'fo') { + if (token.isCancellationRequested) return + return { + isIncomplete: false, + items: [ + { + label: 'foo' + } + ] + } + } + } + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.'])) + await nvim.input('i.') + await helper.waitPopup() + await nvim.input('fo') + await helper.wait(50) + let res = await helper.getItems() + expect(res.length).toBe(1) + }) + }) + + describe('textEdit', () => { + it('should fix bad range', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: 'foo', + filterText: 'foo', + textEdit: { range: Range.create(0, 0, 0, 0), newText: 'foo' }, + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('if') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 'foo') + }) + + it('should applyEdits for empty word', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (): Promise => [{ + label: '', + filterText: '!', + textEdit: { range: Range.create(0, 0, 0, 1), newText: 'foo' }, + data: { word: '' } + }] + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['!'])) + await nvim.input('i!') + await helper.waitPopup() + await helper.selectCompleteItem(0) + await helper.waitFor('getline', ['.'], 'foo') + }) + + it('should provide word when textEdit after startcol', async () => { + // some LS would send textEdit after first character, + // need fix the word from newText + let provider: CompletionItemProvider = { + provideCompletionItems: async (_, position): Promise => { + if (position.line != 0) return null + return [{ + label: 'bar', + filterText: 'ar', + textEdit: { + range: Range.create(0, 1, 0, 1), + newText: 'ar' + } + }] + } + } + disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider)) + await nvim.input('ib') + await helper.waitPopup() + let context = await nvim.getVar('coc#_context') as any + expect(context.start).toBe(1) + expect(context.candidates[0].word).toBe('ar') + }) + + it('should adjust completion position by textEdit start position', async () => { + let provider: CompletionItemProvider = { + provideCompletionItems: async (_document, _position, _token, context): Promise => { + if (!context.triggerCharacter) return + return [{ + label: 'foo', + textEdit: { + range: Range.create(0, 0, 0, 1), + newText: '?foo' + } + }] + } + } + disposables.push(languages.registerCompletionItemProvider('fix', 'f', null, provider, ['?'])) + await nvim.input('i?') + await helper.waitPopup() + await nvim.eval('feedkeys("\\", "in")') + await helper.waitFor('getline', ['.'], '?foo') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/completion/sources.test.ts b/sources_non_forked/coc.nvim/src/__tests__/completion/sources.test.ts new file mode 100644 index 00000000..38f69988 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/completion/sources.test.ts @@ -0,0 +1,65 @@ +import { Neovim } from '@chemzqm/neovim' +import helper from '../helper' +import { ISource, SourceType, CompleteResult } from '../../types' +import sources from '../../sources' +import workspace from '../../workspace' + +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('native sources', () => { + + it('should works for around source', async () => { + let doc = await workspace.document + await nvim.setLine('foo ') + await doc.synchronize() + let { mode } = await nvim.mode + expect(mode).toBe('n') + await nvim.input('Af') + await helper.waitPopup() + let res = await helper.visible('foo', 'around') + expect(res).toBe(true) + await nvim.input('') + }) + + it('should works for buffer source', async () => { + await helper.createDocument() + await nvim.command('set hidden') + let doc = await helper.createDocument() + await nvim.setLine('other') + await nvim.command('bp') + await doc.synchronize() + let { mode } = await nvim.mode + expect(mode).toBe('n') + await nvim.input('io') + let res = await helper.visible('other', 'buffer') + expect(res).toBe(true) + }) + + it('should works with file source', async () => { + await helper.edit() + await nvim.input('i/') + await helper.waitPopup() + let items = await helper.getItems() + expect(items.length).toBeGreaterThan(0) + let res = await helper.visible(items[0].word, 'file') + expect(res).toBe(true) + await nvim.input('') + await nvim.input('o./') + await helper.waitPopup() + items = await helper.getItems() + let item = items.find(o => o.word == 'vimrc') + expect(item).toBeTruthy() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/completion/util.test.ts b/sources_non_forked/coc.nvim/src/__tests__/completion/util.test.ts new file mode 100644 index 00000000..3a8639d1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/completion/util.test.ts @@ -0,0 +1,144 @@ +import { CompletionItemKind, TextEdit, Position } from 'vscode-languageserver-types' +import { matchScore, matchScoreWithPositions } from '../../completion/match' +import { shouldStop } from '../../completion/util' +import { getCharCodes } from '../../util/fuzzy' +import { getStartColumn, getKindString } from '../../sources/source-language' +import { CompleteOption } from '../../types' + +describe('getKindString()', () => { + it('should get kind text', async () => { + let map = new Map() + map.set(CompletionItemKind.Enum, 'E') + let res = getKindString(CompletionItemKind.Enum, map, '') + expect(res).toBe('E') + }) + + it('should get default value', async () => { + let map = new Map() + let res = getKindString(CompletionItemKind.Enum, map, 'D') + expect(res).toBe('D') + }) +}) + +describe('shouldStop', () => { + function createOption(bufnr: number, linenr: number, line: string, colnr: number): Pick { + return { bufnr, linenr, line, colnr } + } + + it('should check stop', async () => { + let opt = createOption(1, 1, 'a', 2) + expect(shouldStop(1, 'foo', { line: '', col: 2, lnum: 1, changedtick: 1, pre: '' }, opt)).toBe(true) + expect(shouldStop(1, 'foo', { line: '', col: 2, lnum: 1, changedtick: 1, pre: ' ' }, opt)).toBe(true) + expect(shouldStop(1, 'foo', { line: '', col: 2, lnum: 1, changedtick: 1, pre: 'fo' }, opt)).toBe(true) + expect(shouldStop(2, 'foo', { line: '', col: 2, lnum: 1, changedtick: 1, pre: 'foob' }, opt)).toBe(true) + expect(shouldStop(1, 'foo', { line: '', col: 2, lnum: 2, changedtick: 1, pre: 'foob' }, opt)).toBe(true) + expect(shouldStop(1, 'foo', { line: '', col: 2, lnum: 1, changedtick: 1, pre: 'barb' }, opt)).toBe(true) + }) +}) + +describe('getStartColumn()', () => { + it('should get start col', async () => { + expect(getStartColumn('', [{ label: 'foo' }])).toBe(undefined) + expect(getStartColumn('', [ + { label: 'foo', textEdit: TextEdit.insert(Position.create(0, 0), 'a') }, + { label: 'bar' }])).toBe(undefined) + expect(getStartColumn('foo', [ + { label: 'foo', textEdit: TextEdit.insert(Position.create(0, 0), 'a') }, + { label: 'bar', textEdit: TextEdit.insert(Position.create(0, 1), 'b') }])).toBe(undefined) + expect(getStartColumn('foo', [ + { label: 'foo', textEdit: TextEdit.insert(Position.create(0, 2), 'a') }, + { label: 'bar', textEdit: TextEdit.insert(Position.create(0, 2), 'b') }])).toBe(2) + }) +}) + +describe('matchScore', () => { + function score(word: string, input: string): number { + return matchScore(word, getCharCodes(input)) + } + + it('should match score for last letter', () => { + expect(score('#!3', '3')).toBe(1) + expect(score('bar', 'f')).toBe(0) + }) + + it('should match first letter', () => { + expect(score('abc', 'a')).toBe(5) + expect(score('Abc', 'a')).toBe(2.5) + expect(score('__abc', 'a')).toBe(2) + expect(score('$Abc', 'a')).toBe(1) + expect(score('$Abc', 'A')).toBe(2) + expect(score('$Abc', '$A')).toBe(6) + expect(score('$Abc', '$a')).toBe(5.5) + expect(score('foo_bar', 'b')).toBe(2) + expect(score('foo_Bar', 'b')).toBe(1) + expect(score('_foo_Bar', 'b')).toBe(0.5) + expect(score('_foo_Bar', 'f')).toBe(2) + expect(score('bar', 'a')).toBe(1) + expect(score('fooBar', 'B')).toBe(2) + expect(score('fooBar', 'b')).toBe(1) + }) + + it('should match follow letters', () => { + expect(score('abc', 'ab')).toBe(6) + expect(score('adB', 'ab')).toBe(5.75) + expect(score('adb', 'ab')).toBe(5.1) + expect(score('adCB', 'ab')).toBe(5.05) + expect(score('a_b_c', 'ab')).toBe(6) + expect(score('FooBar', 'fb')).toBe(3.25) + expect(score('FBar', 'fb')).toBe(3) + expect(score('FooBar', 'FB')).toBe(6) + expect(score('FBar', 'FB')).toBe(6) + expect(score('a__b', 'a__b')).toBe(8) + expect(score('aBc', 'ab')).toBe(5.5) + expect(score('a_B_c', 'ab')).toBe(5.75) + expect(score('abc', 'abc')).toBe(7) + expect(score('abc', 'aC')).toBe(0) + expect(score('abc', 'ac')).toBe(5.1) + expect(score('abC', 'ac')).toBe(5.75) + expect(score('abC', 'aC')).toBe(6) + }) + + it('should only allow search once', () => { + expect(score('foobar', 'fbr')).toBe(5.2) + expect(score('foobaRow', 'fbr')).toBe(5.85) + expect(score('foobaRow', 'fbR')).toBe(6.1) + expect(score('foobar', 'fa')).toBe(5.1) + }) + + it('should have higher score for strict match', () => { + expect(score('language-client-protocol', 'lct')).toBe(6.1) + expect(score('language-client-types', 'lct')).toBe(7) + }) + + it('should find highest score', () => { + expect(score('ArrayRotateTail', 'art')).toBe(3.6) + }) +}) + +describe('matchScoreWithPositions', () => { + function assertMatch(word: string, input: string, res: [number, ReadonlyArray] | undefined): void { + let result = matchScoreWithPositions(word, getCharCodes(input)) + if (!res) { + expect(result).toBeUndefined() + } else { + expect(result).toEqual(res) + } + } + + it('should return undefined when not match found', async () => { + assertMatch('a', 'abc', undefined) + assertMatch('a', '', undefined) + assertMatch('ab', 'ac', undefined) + }) + + it('should find matches by position fix', async () => { + assertMatch('this', 'tih', [5.6, [0, 1, 2]]) + assertMatch('globalThis', 'tihs', [2.6, [6, 7, 8, 9]]) + }) + + it('should find matched positions', async () => { + assertMatch('this', 'th', [6, [0, 1]]) + assertMatch('foo_bar', 'fb', [6, [0, 4]]) + assertMatch('assertMatch', 'am', [5.75, [0, 6]]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/autocmds.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/autocmds.test.ts new file mode 100644 index 00000000..73b8e335 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/autocmds.test.ts @@ -0,0 +1,68 @@ +import { Neovim } from '@chemzqm/neovim' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('setupDynamicAutocmd()', () => { + it('should setup autocmd on vim', async () => { + await nvim.setLine('foo') + let fn = nvim.hasFunction + nvim.hasFunction = () => { + return false + } + let called = false + workspace.registerAutocmd({ + event: 'CursorMoved', + request: true, + callback: () => { + called = true + } + }) + await helper.wait(50) + await nvim.command('normal! $') + await helper.wait(100) + nvim.hasFunction = fn + expect(called).toBe(true) + nvim.command(`augroup coc_dynamic_autocmd| autocmd!|augroup end`, true) + }) + + it('should setup user autocmd', async () => { + let called = false + workspace.registerAutocmd({ + event: 'User CocJumpPlaceholder', + request: true, + callback: () => { + called = true + } + }) + workspace.autocmds.setupDynamicAutocmd(true) + await helper.wait(50) + await nvim.command('doautocmd User CocJumpPlaceholder') + await helper.wait(100) + expect(called).toBe(true) + }) +}) + +describe('doAutocmd()', () => { + it('should not throw when command id does not exist', async () => { + await workspace.autocmds.doAutocmd(999, []) + }) + + it('should dispose', async () => { + workspace.autocmds.dispose() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/documents.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/documents.test.ts new file mode 100644 index 00000000..31e10da9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/documents.test.ts @@ -0,0 +1,85 @@ +import { Neovim } from '@chemzqm/neovim' +import os from 'os' +import path from 'path' +import fs from 'fs' +import { v4 as uuid } from 'uuid' +import Documents from '../../core/documents' +import events from '../../events' +import workspace from '../../workspace' +import helper from '../helper' + +let documents: Documents +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + documents = workspace.documentsManager +}) + +afterEach(async () => { + await helper.reset() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('documents', () => { + it('should get document', async () => { + await helper.createDocument('bar') + let doc = await helper.createDocument('foo') + let res = documents.getDocument(doc.uri) + expect(res.uri).toBe(doc.uri) + }) + + it('should create document', async () => { + await helper.createDocument() + let bufnrs = await nvim.call('coc#ui#open_files', [[__filename]]) as number[] + let bufnr = bufnrs[0] + let doc = workspace.getDocument(bufnr) + expect(doc).toBeUndefined() + doc = await documents.createDocument(bufnr) + expect(doc).toBeDefined() + }) + + it('should check buffer rename on save', async () => { + let doc = await workspace.document + let bufnr = doc.bufnr + let name = `${uuid()}.vim` + let tmpfile = path.join(os.tmpdir(), name) + await nvim.command(`write ${tmpfile}`) + doc = workspace.getDocument(bufnr) + expect(doc).toBeDefined() + expect(doc.filetype).toBe('vim') + expect(doc.bufname).toMatch(name) + fs.unlinkSync(tmpfile) + }) + + it('should get current document', async () => { + let p1 = workspace.document + let p2 = workspace.document + let arr = await Promise.all([p1, p2]) + expect(arr[0]).toBe(arr[1]) + }) + + it('should get bufnrs', async () => { + await workspace.document + let bufnrs = documents.bufnrs + expect(bufnrs.length).toBe(1) + }) + + it('should get uri', async () => { + let doc = await workspace.document + expect(documents.uri).toBe(doc.uri) + }) + + it('should attach events on vim', async () => { + await documents.attach(nvim, workspace.env) + let env = Object.assign(workspace.env, { isVim: true }) + documents.detach() + await documents.attach(nvim, env) + documents.detach() + await events.fire('CursorMoved', [1, [1, 1]]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/editors.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/editors.test.ts new file mode 100644 index 00000000..1b4b670c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/editors.test.ts @@ -0,0 +1,169 @@ +import { Neovim } from '@chemzqm/neovim' +import Editors, { TextEditor } from '../../core/editors' +import workspace from '../../workspace' +import window from '../../window' +import events from '../../events' +import helper from '../helper' +import { disposeAll } from '../../util' +import { Disposable } from 'vscode-languageserver-protocol' + +let editors: Editors +let nvim: Neovim +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + editors = workspace.editors +}) + +afterEach(async () => { + await helper.reset() +}) + +afterAll(async () => { + disposeAll(disposables) + await helper.shutdown() +}) + +describe('editors', () => { + + function assertEditor(editor: TextEditor, tabpagenr: number, winid: number) { + expect(editor).toBeDefined() + expect(editor.tabpagenr).toBe(tabpagenr) + expect(editor.winid).toBe(winid) + } + + it('should have active editor', async () => { + let winid = await nvim.call('win_getid') + let editor = window.activeTextEditor + assertEditor(editor, 1, winid) + let editors = window.visibleTextEditors + expect(editors.length).toBe(1) + }) + + it('should change active editor on split', async () => { + let promise = new Promise(resolve => { + editors.onDidChangeActiveTextEditor(e => { + resolve(e) + }, null, disposables) + }) + await nvim.command('vnew') + let editor = await promise + let winid = await nvim.call('win_getid') + expect(editor.winid).toBe(winid) + }) + + it('should change active editor on tabe', async () => { + let promise = new Promise(resolve => { + editors.onDidChangeActiveTextEditor(e => { + if (e.document.uri.includes('foo')) { + resolve(e) + } + }, null, disposables) + }) + await nvim.command('tabe a | tabe b | tabe foo') + let editor = await promise + let winid = await nvim.call('win_getid') + expect(editor.winid).toBe(winid) + }) + + it('should change active editor on edit', async () => { + await nvim.call('win_getid') + let fn = jest.fn() + window.onDidChangeVisibleTextEditors(() => { + fn() + }, null, disposables) + let promise = new Promise(resolve => { + editors.onDidChangeActiveTextEditor(e => { + resolve(e) + }) + }) + await nvim.command('edit foo') + let editor = await promise + expect(editor.document.uri).toMatch('foo') + expect(fn).toBeCalled() + }) + + it('should change active editor on window switch', async () => { + let winid = await nvim.call('win_getid') + await nvim.command('vs foo') + await nvim.command('wincmd p') + let curr = editors.activeTextEditor + expect(curr.winid).toBe(winid) + expect(editors.visibleTextEditors.length).toBe(2) + }) + + it('should not create editor for float window', async () => { + let fn = jest.fn() + await nvim.call('win_getid') + editors.onDidChangeActiveTextEditor(e => { + fn() + }) + let res = await nvim.call('coc#float#create_float_win', [0, 0, { + relative: 'editor', + row: 1, + col: 1, + width: 10, + height: 1, + lines: ['foo'] + }]) + await nvim.call('win_gotoid', [res[0]]) + await events.fire('CursorHold', [res[1]]) + await nvim.command('wincmd p') + expect(fn).toBeCalledTimes(0) + expect(editors.visibleTextEditors.length).toBe(1) + }) + + it('should cleanup on CursorHold', async () => { + let winid = await nvim.call('win_getid') + let promise = new Promise(resolve => { + editors.onDidChangeActiveTextEditor(e => { + if (e.document.uri.includes('foo')) { + resolve(e) + } + }, null, disposables) + }) + await nvim.command('tabe foo') + await promise + await nvim.call('win_execute', [winid, 'noa close']) + let bufnr = await nvim.eval("bufnr('%')") + await events.fire('CursorHold', [bufnr]) + expect(editors.visibleTextEditors.length).toBe(1) + }) + + it('should cleanup on create', async () => { + let winid = await nvim.call('win_getid') + let promise = new Promise(resolve => { + editors.onDidChangeActiveTextEditor(e => { + if (e.document.uri.includes('foo')) { + resolve(e) + } + }, null, disposables) + }) + await nvim.command('tabe foo') + await promise + await nvim.call('win_execute', [winid, 'noa close']) + await nvim.command('edit bar') + expect(editors.visibleTextEditors.length).toBe(2) + }) + + it('should have corrent tabnr after tab changed', async () => { + await nvim.command('tabe') + await helper.waitValue(() => { + return editors.visibleTextEditors.length + }, 2) + let editor = editors.visibleTextEditors.find(o => o.tabpagenr == 2) + await nvim.command('normal! 1gt') + await nvim.command('tabe') + await helper.waitValue(() => { + return editors.visibleTextEditors.length + }, 3) + expect(editor.tabpagenr).toBe(3) + await nvim.command('tabc') + await helper.waitValue(() => { + return editors.visibleTextEditors.length + }, 2) + expect(editor.tabpagenr).toBe(2) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/fileSystemWatcher.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/fileSystemWatcher.test.ts new file mode 100644 index 00000000..1f2c8ab5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/fileSystemWatcher.test.ts @@ -0,0 +1,380 @@ +import bser from 'bser' +import fs from 'fs' +import net from 'net' +import os from 'os' +import path from 'path' +import Watchman, { FileChangeItem, isValidWatchRoot } from '../../core/watchman' +import helper from '../helper' +import { Disposable } from 'vscode-languageserver-protocol' +import Configurations from '../../configuration/index' +import WorkspaceFolderController from '../../core/workspaceFolder' +import { FileSystemWatcherManager, FileSystemWatcher } from '../../core/fileSystemWatcher' +import { disposeAll } from '../../util' +import { URI } from 'vscode-uri' + +let server: net.Server +let client: net.Socket +const cwd = process.cwd() +const sockPath = path.join(os.tmpdir(), `watchman-fake-${process.pid}`) +process.env.WATCHMAN_SOCK = sockPath + +let workspaceFolder: WorkspaceFolderController +let watcherManager: FileSystemWatcherManager +let configurations: Configurations +let disposables: Disposable[] = [] + +function wait(ms: number): Promise { + return new Promise(resolve => { + setTimeout(() => { + resolve(undefined) + }, ms) + }) +} + +function createFileChange(file: string, isNew = true, exists = true): FileChangeItem { + return { + size: 1, + name: file, + exists, + new: isNew, + type: 'f', + mtime_ms: Date.now() + } +} + +function sendResponse(data: any): void { + client.write(bser.dumpToBuffer(data)) +} + +function sendSubscription(uid: string, root: string, files: FileChangeItem[]): void { + client.write(bser.dumpToBuffer({ + subscription: uid, + root, + files + })) +} + +let capabilities: any +let watchResponse: any +beforeAll(done => { + let userConfigFile = path.join(process.env.COC_VIMCONFIG, 'coc-settings.json') + configurations = new Configurations(userConfigFile, { + $removeConfigurationOption: () => {}, + $updateConfigurationOption: () => {} + }) + workspaceFolder = new WorkspaceFolderController(configurations) + watcherManager = new FileSystemWatcherManager(workspaceFolder, '') + watcherManager.attach(helper.createNullChannel()) + // create a mock sever for watchman + server = net.createServer(c => { + client = c + c.on('data', data => { + let obj = bser.loadFromBuffer(data) + if (obj[0] == 'watch-project') { + sendResponse(watchResponse || { watch: obj[1], warning: 'warning' }) + } else if (obj[0] == 'unsubscribe') { + sendResponse({ path: obj[1] }) + } else if (obj[0] == 'clock') { + sendResponse({ clock: 'clock' }) + } else if (obj[0] == 'version') { + let { optional, required } = obj[1] + let res = {} + for (let key of optional) { + res[key] = true + } + for (let key of required) { + res[key] = true + } + sendResponse({ capabilities: capabilities || res }) + } else if (obj[0] == 'subscribe') { + sendResponse({ subscribe: obj[2] }) + } else { + sendResponse({}) + } + }) + }) + server.on('error', err => { + throw err + }) + server.listen(sockPath, () => { + done() + }) +}) + +afterEach(async () => { + disposeAll(disposables) + capabilities = undefined + watchResponse = undefined +}) + +afterAll(async () => { + watcherManager.dispose() + server.removeAllListeners() + server.close() + if (fs.existsSync(sockPath)) { + fs.unlinkSync(sockPath) + } +}) + +describe('watchman', () => { + it('should throw error when not watching', async () => { + let client = new Watchman(null) + disposables.push(client) + let fn = async () => { + await client.subscribe('**/*', () => {}) + } + await expect(fn()).rejects.toThrow(/not watching/) + }) + + it('should checkCapability', async () => { + let client = new Watchman(null) + let res = await client.checkCapability() + expect(res).toBe(true) + capabilities = { relative_root: false } + res = await client.checkCapability() + expect(res).toBe(false) + client.dispose() + }) + + it('should watchProject', async () => { + let client = new Watchman(null) + disposables.push(client) + let res = await client.watchProject(__dirname) + expect(res).toBe(true) + client.dispose() + }) + + it('should unsubscribe', async () => { + let client = new Watchman(null) + disposables.push(client) + await client.watchProject(cwd) + let fn = jest.fn() + let disposable = await client.subscribe(`${cwd}/*`, fn) + disposable.dispose() + client.dispose() + }) +}) + +describe('Watchman#subscribe', () => { + + it('should subscribe file change', async () => { + let client = new Watchman(null, helper.createNullChannel()) + disposables.push(client) + await client.watchProject(cwd) + let fn = jest.fn() + let disposable = await client.subscribe(`${cwd}/*`, fn) + let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)] + sendSubscription(disposable.subscribe, cwd, changes) + await wait(30) + expect(fn).toBeCalled() + let call = fn.mock.calls[0][0] + disposable.dispose() + expect(call.root).toBe(cwd) + client.dispose() + }) + + it('should subscribe with relative_path', async () => { + let client = new Watchman(null, helper.createNullChannel()) + watchResponse = { watch: cwd, relative_path: 'foo' } + await client.watchProject(cwd) + let fn = jest.fn() + let disposable = await client.subscribe(`${cwd}/*`, fn) + let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)] + sendSubscription(disposable.subscribe, cwd, changes) + await wait(30) + expect(fn).toBeCalled() + let call = fn.mock.calls[0][0] + disposable.dispose() + expect(call.root).toBe(path.join(cwd, 'foo')) + client.dispose() + }) + + it('should not subscribe invalid response', async () => { + let c = new Watchman(null, helper.createNullChannel()) + disposables.push(c) + watchResponse = { watch: cwd, relative_path: 'foo' } + await c.watchProject(cwd) + let fn = jest.fn() + let disposable = await c.subscribe(`${cwd}/*`, fn) + let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)] + sendSubscription('uuid', cwd, changes) + await wait(10) + sendSubscription(disposable.subscribe, cwd, []) + await wait(10) + client.write(bser.dumpToBuffer({ + subscription: disposable.subscribe, + root: cwd + })) + await wait(10) + expect(fn).toBeCalledTimes(0) + }) +}) + +describe('Watchman#createClient', () => { + it('should not create client when capabilities not match', async () => { + capabilities = { relative_root: false } + let client = await Watchman.createClient(null, cwd) + expect(client).toBe(null) + }) + + it('should not create when watch failed', async () => { + watchResponse = {} + let client = await Watchman.createClient(null, cwd) + expect(client).toBe(null) + }) + + it('should create client', async () => { + let client = await Watchman.createClient(null, cwd) + disposables.push(client) + expect(client).toBeDefined() + }) + + it('should not create client for root', async () => { + let client = await Watchman.createClient(null, '/') + expect(client).toBeNull() + }) +}) + +describe('isValidWatchRoot()', () => { + it('should check valid root', async () => { + expect(isValidWatchRoot('/')).toBe(false) + expect(isValidWatchRoot(os.homedir())).toBe(false) + expect(isValidWatchRoot('/tmp/a/b/c')).toBe(false) + expect(isValidWatchRoot(os.tmpdir())).toBe(false) + }) +}) + +describe('fileSystemWatcher', () => { + + function createWatcher(pattern: string, ignoreCreateEvents = false, ignoreChangeEvents = false, ignoreDeleteEvents = false): FileSystemWatcher { + let watcher = watcherManager.createFileSystemWatcher( + pattern, + ignoreCreateEvents, + ignoreChangeEvents, + ignoreDeleteEvents + ) + disposables.push(watcher) + return watcher + } + + beforeAll(async () => { + workspaceFolder.addWorkspaceFolder(cwd, true) + await watcherManager.waitClient(cwd) + }) + + it('should watch for file create', async () => { + let watcher = createWatcher('**/*', false, true, true) + let fn = jest.fn() + watcher.onDidCreate(fn) + await helper.wait(50) + let changes: FileChangeItem[] = [createFileChange(`a`)] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.wait(50) + expect(fn).toBeCalled() + }) + + it('should watch for file delete', async () => { + let watcher = createWatcher('**/*', true, true, false) + let fn = jest.fn() + watcher.onDidDelete(fn) + await helper.wait(50) + let changes: FileChangeItem[] = [createFileChange(`a`, false, false)] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.wait(50) + expect(fn).toBeCalled() + }) + + it('should watch for file change', async () => { + let watcher = createWatcher('**/*', false, false, false) + let fn = jest.fn() + watcher.onDidChange(fn) + await helper.wait(50) + let changes: FileChangeItem[] = [createFileChange(`a`, false, true)] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.wait(50) + expect(fn).toBeCalled() + }) + + it('should watch for file rename', async () => { + let watcher = createWatcher('**/*', false, false, false) + let fn = jest.fn() + watcher.onDidRename(fn) + await helper.wait(50) + let changes: FileChangeItem[] = [ + createFileChange(`a`, false, false), + createFileChange(`b`, true, true), + ] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.wait(50) + expect(fn).toBeCalled() + }) + + it('should not watch for events', async () => { + let watcher = createWatcher('**/*', true, true, true) + let called = false + let onChange = () => { called = true } + watcher.onDidCreate(onChange) + watcher.onDidChange(onChange) + watcher.onDidDelete(onChange) + await helper.wait(50) + let changes: FileChangeItem[] = [ + createFileChange(`a`, false, false), + createFileChange(`b`, true, true), + createFileChange(`c`, false, true), + ] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.wait(50) + expect(called).toBe(false) + }) + + it('should watch for folder rename', async () => { + let watcher = createWatcher('**/*') + let newFiles: string[] = [] + let count = 0 + watcher.onDidRename(e => { + count++ + newFiles.push(e.newUri.fsPath) + }) + await helper.wait(50) + let changes: FileChangeItem[] = [ + createFileChange(`a/1`, false, false), + createFileChange(`a/2`, false, false), + createFileChange(`b/1`, true, true), + createFileChange(`b/2`, true, true), + ] + sendSubscription(watcher.subscribe, cwd, changes) + await helper.waitValue(() => { + return count + }, 2) + }) + + it('should watch for new folder', async () => { + let watcher = createWatcher('**/*') + expect(watcher).toBeDefined() + workspaceFolder.renameWorkspaceFolder(cwd, __dirname) + await helper.wait(50) + let uri: URI + watcher.onDidCreate(e => { + uri = e + }) + await helper.wait(50) + let changes: FileChangeItem[] = [createFileChange(`a`)] + sendSubscription(watcher.subscribe, __dirname, changes) + await helper.wait(50) + expect(uri.fsPath).toEqual(path.join(__dirname, 'a')) + }) +}) + +describe('create FileSystemWatcherManager', () => { + it('should attach to existing workspace folder', async () => { + let workspaceFolder = new WorkspaceFolderController(configurations) + workspaceFolder.addWorkspaceFolder(cwd, false) + let watcherManager = new FileSystemWatcherManager(workspaceFolder, '') + watcherManager.attach(helper.createNullChannel()) + await helper.wait(100) + await watcherManager.createClient(os.tmpdir()) + await watcherManager.createClient(cwd) + await watcherManager.waitClient(cwd) + watcherManager.dispose() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/files.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/files.test.ts new file mode 100644 index 00000000..8947b8ae --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/files.test.ts @@ -0,0 +1,813 @@ +import { Buffer, Neovim } from '@chemzqm/neovim' +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { v4 as uuid } from 'uuid' +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import { CreateFile, DeleteFile, Position, Range, RenameFile, TextDocumentEdit, TextEdit, VersionedTextDocumentIdentifier, WorkspaceEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import { RecoverFunc } from '../../model/editInspect' +import RelativePattern from '../../model/relativePattern' +import { disposeAll } from '../../util' +import { readFile } from '../../util/fs' +import window from '../../window' +import workspace from '../../workspace' +import events from '../../events' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('RelativePattern', () => { + function testThrow(fn: () => void) { + let err + try { + fn() + } catch (e) { + err = e + } + expect(err).toBeDefined() + } + + it('should throw for invalid arguments', async () => { + testThrow(() => { + new RelativePattern('', undefined) + }) + testThrow(() => { + new RelativePattern({ uri: undefined } as any, '') + }) + }) + + it('should create relativePattern', async () => { + for (let base of [__filename, URI.file(__filename), { uri: URI.file(__dirname).toString(), name: 'test' }]) { + let p = new RelativePattern(base, '**/*') + expect(URI.isUri(p.baseUri)).toBe(true) + expect(p.toJSON()).toBeDefined() + } + }) +}) + +describe('findFiles()', () => { + beforeEach(() => { + workspace.workspaceFolderControl.setWorkspaceFolders([__dirname]) + }) + + it('should use glob pattern', async () => { + let res = await workspace.findFiles('**/*.ts') + expect(res.length).toBeGreaterThan(0) + }) + + it('should use relativePattern', async () => { + let relativePattern = new RelativePattern(URI.file(__dirname), '**/*.ts') + let res = await workspace.findFiles(relativePattern) + expect(res.length).toBeGreaterThan(0) + }) + + it('should respect exclude as glob pattern', async () => { + let arr = await workspace.findFiles('**/*.ts', 'files*') + let res = arr.find(o => path.relative(__dirname, o.fsPath).startsWith('files')) + expect(res).toBeUndefined() + }) + + it('should respect exclude as relativePattern', async () => { + let relativePattern = new RelativePattern(URI.file(__dirname), 'files*') + let arr = await workspace.findFiles('**/*.ts', relativePattern) + let res = arr.find(o => path.relative(__dirname, o.fsPath).startsWith('files')) + expect(res).toBeUndefined() + }) + + it('should respect maxResults', async () => { + let arr = await workspace.findFiles('**/*.ts', undefined, 1) + expect(arr.length).toBe(1) + }) + + it('should respect token', async () => { + let source = new CancellationTokenSource() + source.cancel() + let arr = await workspace.findFiles('**/*.ts', undefined, 1, source.token) + expect(arr.length).toBe(0) + }) + + it('should cancel findFiles', async () => { + let source = new CancellationTokenSource() + let p = workspace.findFiles('**/*.ts', undefined, 1, source.token) + source.cancel() + let arr = await p + expect(arr.length).toBe(0) + }) +}) + +describe('applyEdits()', () => { + it('should not throw when unable to undo & redo', async () => { + await workspace.files.undoWorkspaceEdit() + await workspace.files.redoWorkspaceEdit() + }) + + it('should apply TextEdit of documentChanges', async () => { + let doc = await helper.createDocument() + let versioned = VersionedTextDocumentIdentifier.create(doc.uri, doc.version) + let edit = TextEdit.insert(Position.create(0, 0), 'bar') + let change = TextDocumentEdit.create(versioned, [edit]) + let workspaceEdit: WorkspaceEdit = { + documentChanges: [change] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + let line = await nvim.getLine() + expect(line).toBe('bar') + }) + + it('should apply edit with out change buffers', async () => { + let doc = await helper.createDocument() + await nvim.setLine('bar') + await doc.synchronize() + let version = doc.version + let versioned = VersionedTextDocumentIdentifier.create(doc.uri, doc.version) + let edit = TextEdit.replace(Range.create(0, 0, 0, 3), 'bar') + let change = TextDocumentEdit.create(versioned, [edit]) + let workspaceEdit: WorkspaceEdit = { + documentChanges: [change] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + expect(doc.version).toBe(version) + }) + + it('should not apply TextEdit if version miss match', async () => { + let doc = await helper.createDocument() + let versioned = VersionedTextDocumentIdentifier.create(doc.uri, 10) + let edit = TextEdit.insert(Position.create(0, 0), 'bar') + let change = TextDocumentEdit.create(versioned, [edit]) + let workspaceEdit: WorkspaceEdit = { + documentChanges: [change] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(false) + }) + + it('should apply edits with changes to buffer', async () => { + let doc = await helper.createDocument() + let changes = { + [doc.uri]: [TextEdit.insert(Position.create(0, 0), 'bar')] + } + let workspaceEdit: WorkspaceEdit = { changes } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + let line = await nvim.getLine() + expect(line).toBe('bar') + }) + + it('should apply edits with changes to file not in buffer list', async () => { + let filepath = await createTmpFile('bar') + let uri = URI.file(filepath).toString() + let changes = { + [uri]: [TextEdit.insert(Position.create(0, 0), 'foo')] + } + let res = await workspace.applyEdit({ changes }) + expect(res).toBe(true) + let doc = workspace.getDocument(uri) + let content = doc.getDocumentContent() + expect(content).toMatch(/^foobar/) + await nvim.command('silent! %bwipeout!') + }) + + it('should apply edits when file does not exist', async () => { + let filepath = path.join(__dirname, 'not_exists') + disposables.push({ + dispose: () => { + if (fs.existsSync(filepath)) { + fs.unlinkSync(filepath) + } + } + }) + let uri = URI.file(filepath).toString() + let changes = { + [uri]: [TextEdit.insert(Position.create(0, 0), 'foo')] + } + let res = await workspace.applyEdit({ changes }) + expect(res).toBe(true) + }) + + it('should adjust cursor position after applyEdits', async () => { + let doc = await helper.createDocument() + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 0 }) + let edit = TextEdit.insert(Position.create(0, 0), 'foo\n') + let versioned = VersionedTextDocumentIdentifier.create(doc.uri, null) + let documentChanges = [TextDocumentEdit.create(versioned, [edit])] + let res = await workspace.applyEdit({ documentChanges }) + expect(res).toBe(true) + pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 1, character: 0 }) + }) + + it('should support null version of documentChanges', async () => { + let file = path.join(__dirname, 'foo') + await workspace.createFile(file, { ignoreIfExists: true, overwrite: true }) + let uri = URI.file(file).toString() + let versioned = VersionedTextDocumentIdentifier.create(uri, null) + let edit = TextEdit.insert(Position.create(0, 0), 'bar') + let change = TextDocumentEdit.create(versioned, [edit]) + let workspaceEdit: WorkspaceEdit = { + documentChanges: [change] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + await nvim.command('wa') + let content = await readFile(file, 'utf8') + expect(content).toMatch(/^bar/) + await workspace.deleteFile(file, { ignoreIfNotExists: true }) + }) + + it('should support CreateFile edit', async () => { + let file = path.join(__dirname, 'foo') + let uri = URI.file(file).toString() + let workspaceEdit: WorkspaceEdit = { + documentChanges: [CreateFile.create(uri, { overwrite: true })] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + await workspace.deleteFile(file, { ignoreIfNotExists: true }) + }) + + it('should support DeleteFile edit', async () => { + let file = path.join(__dirname, 'foo') + await workspace.createFile(file, { ignoreIfExists: true, overwrite: true }) + let uri = URI.file(file).toString() + let workspaceEdit: WorkspaceEdit = { + documentChanges: [DeleteFile.create(uri)] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + }) + + it('should check uri for CreateFile edit', async () => { + let workspaceEdit: WorkspaceEdit = { + documentChanges: [CreateFile.create('term://.', { overwrite: true })] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(false) + }) + + it('should support RenameFile edit', async () => { + let file = path.join(__dirname, 'foo') + await workspace.createFile(file, { ignoreIfExists: true, overwrite: true }) + let newFile = path.join(__dirname, 'bar') + let uri = URI.file(file).toString() + let workspaceEdit: WorkspaceEdit = { + documentChanges: [RenameFile.create(uri, URI.file(newFile).toString())] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + await workspace.deleteFile(newFile, { ignoreIfNotExists: true }) + }) + + it('should support changes with edit and rename', async () => { + let fsPath = await createTmpFile('test') + let doc = await helper.createDocument(fsPath) + let newFile = path.join(os.tmpdir(), `coc-${process.pid}/new-${uuid()}`) + let newUri = URI.file(newFile).toString() + let edit: WorkspaceEdit = { + documentChanges: [ + { + textDocument: { + version: null, + uri: doc.uri, + }, + edits: [ + { + range: { + start: { + line: 0, + character: 0 + }, + end: { + line: 0, + character: 4 + } + }, + newText: 'bar' + } + ] + }, + { + oldUri: doc.uri, + newUri, + kind: 'rename' + } + ] + } + let res = await workspace.applyEdit(edit) + expect(res).toBe(true) + let curr = await workspace.document + expect(curr.uri).toBe(newUri) + expect(curr.getline(0)).toBe('bar') + let line = await nvim.line + expect(line).toBe('bar') + }) + + it('should support edit new file with CreateFile', async () => { + let file = path.join(os.tmpdir(), 'foo') + let uri = URI.file(file).toString() + let workspaceEdit: WorkspaceEdit = { + documentChanges: [ + CreateFile.create(uri, { overwrite: true }), + TextDocumentEdit.create({ uri, version: 0 }, [ + TextEdit.insert(Position.create(0, 0), 'foo bar') + ]) + ] + } + let res = await workspace.applyEdit(workspaceEdit) + expect(res).toBe(true) + let doc = workspace.getDocument(uri) + expect(doc).toBeDefined() + let line = doc.getline(0) + expect(line).toBe('foo bar') + await workspace.deleteFile(file, { ignoreIfNotExists: true }) + }) + + it('should undo and redo workspace edit', async () => { + const folder = path.join(os.tmpdir(), uuid()) + const pathone = path.join(folder, 'a') + const pathtwo = path.join(folder, 'b') + await workspace.files.createFile(pathone, { overwrite: true }) + await workspace.files.createFile(pathtwo, { overwrite: true }) + let uris = [URI.file(pathone).toString(), URI.file(pathtwo).toString()] + const assertContent = (one: string, two: string) => { + let doc = workspace.getDocument(uris[0]) + expect(doc.getDocumentContent()).toBe(one) + doc = workspace.getDocument(uris[1]) + expect(doc.getDocumentContent()).toBe(two) + } + let edits: TextDocumentEdit[] = [] + edits.push(TextDocumentEdit.create({ uri: uris[0], version: null }, [ + TextEdit.insert(Position.create(0, 0), 'foo') + ])) + edits.push(TextDocumentEdit.create({ uri: uris[1], version: null }, [ + TextEdit.insert(Position.create(0, 0), 'bar') + ])) + await workspace.applyEdit({ documentChanges: edits }) + assertContent('foo\n', 'bar\n') + await workspace.files.undoWorkspaceEdit() + assertContent('\n', '\n') + await workspace.files.redoWorkspaceEdit() + assertContent('foo\n', 'bar\n') + }) + + it('should should support annotations', async () => { + async function assertEdit(confirm: boolean): Promise { + let doc = await helper.createDocument(uuid()) + let edit: WorkspaceEdit = { + documentChanges: [ + { + textDocument: { version: doc.version, uri: doc.uri }, + edits: [ + { + range: Range.create(0, 0, 0, 0), + newText: 'bar', + annotationId: '85bc78e2-5ef0-4949-b10c-13f476faf430' + } + ] + }, + ], + changeAnnotations: { + '85bc78e2-5ef0-4949-b10c-13f476faf430': { + needsConfirmation: true, + label: 'Text changes', + description: 'description' + } + } + } + let p = workspace.files.applyEdit(edit) + await helper.waitPrompt() + if (confirm) { + await nvim.input('') + } else { + await nvim.input('') + } + await p + let content = doc.getDocumentContent() + if (confirm) { + expect(content).toBe('bar\n') + } else { + expect(content).toBe('\n') + } + } + await assertEdit(true) + await assertEdit(false) + }) +}) + +describe('inspectEdit', () => { + async function inspect(edit: WorkspaceEdit): Promise { + await workspace.applyEdit(edit) + await workspace.files.inspectEdit() + let buf = await nvim.buffer + return buf + } + + it('should show wanring when edit not exists', async () => { + (workspace.files as any).editState = undefined + await workspace.files.inspectEdit() + }) + + it('should render with changes', async () => { + let fsPath = await createTmpFile('foo\n1\n2\nbar') + let doc = await helper.createDocument(fsPath) + let newFile = path.join(os.tmpdir(), `coc-${process.pid}/new-${uuid()}`) + let newUri = URI.file(newFile).toString() + let createFile = path.join(os.tmpdir(), `coc-${process.pid}/create-${uuid()}`) + let deleteFile = await createTmpFile('delete') + disposables.push(Disposable.create(() => { + if (fs.existsSync(newFile)) fs.unlinkSync(newFile) + if (fs.existsSync(createFile)) fs.unlinkSync(createFile) + if (fs.existsSync(deleteFile)) fs.unlinkSync(deleteFile) + })) + let edit: WorkspaceEdit = { + documentChanges: [ + { + textDocument: { version: null, uri: doc.uri, }, + edits: [ + TextEdit.del(Range.create(0, 0, 1, 0)), + TextEdit.replace(Range.create(3, 0, 3, 3), 'xyz'), + ] + }, + { + kind: 'rename', + oldUri: doc.uri, + newUri + }, { + kind: 'create', + uri: URI.file(createFile).toString() + }, { + kind: 'delete', + uri: URI.file(deleteFile).toString() + } + ] + } + let buf = await inspect(edit) + let lines = await buf.lines + let content = lines.join('\n') + expect(content).toMatch('Change') + expect(content).toMatch('Rename') + expect(content).toMatch('Create') + expect(content).toMatch('Delete') + await nvim.command('exe 5') + await nvim.input('') + await helper.waitFor('expand', ['%:p'], newFile) + let line = await nvim.call('line', ['.']) + expect(line).toBe(3) + }) + + it('should render annotation label', async () => { + let doc = await helper.createDocument(uuid()) + let edit: WorkspaceEdit = { + documentChanges: [ + { + textDocument: { version: doc.version, uri: doc.uri }, + edits: [ + { + range: Range.create(0, 0, 0, 0), + newText: 'bar', + annotationId: 'dd866f37-a24c-4503-9c35-c139fb28e25b' + } + ] + }, + ], + changeAnnotations: { + 'dd866f37-a24c-4503-9c35-c139fb28e25b': { + needsConfirmation: false, + label: 'Text changes' + } + } + } + let buf = await inspect(edit) + await events.fire('BufUnload', [buf.id + 1]) + let winid = await nvim.call('win_getid') + let lines = await buf.lines + expect(lines[0]).toBe('Text changes') + await nvim.command('exe 1') + await nvim.input('') + let bufnr = await nvim.call('bufnr', ['%']) + expect(bufnr).toBe(buf.id) + await nvim.command('exe 3') + await nvim.input('') + let fsPath = URI.parse(doc.uri).fsPath + await helper.waitFor('expand', ['%:p'], fsPath) + await nvim.call('win_gotoid', [winid]) + await nvim.input('') + await helper.wait(10) + }) +}) + +describe('createFile()', () => { + it('should create and revert parent folder', async () => { + const folder = path.join(os.tmpdir(), uuid()) + const filepath = path.join(folder, 'bar') + disposables.push(Disposable.create(() => { + if (fs.existsSync(folder)) fs.removeSync(folder) + })) + let fns: RecoverFunc[] = [] + expect(fs.existsSync(folder)).toBe(false) + await workspace.files.createFile(filepath, {}, fns) + expect(fs.existsSync(filepath)).toBe(true) + for (let i = fns.length - 1; i >= 0; i--) { + await fns[i]() + } + expect(fs.existsSync(folder)).toBe(false) + }) + + it('should throw when file already exists', async () => { + let filepath = await createTmpFile('foo', disposables) + let fn = async () => { + await workspace.createFile(filepath, {}) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should not create file if file exists with ignoreIfExists', async () => { + let file = await createTmpFile('foo') + await workspace.createFile(file, { ignoreIfExists: true }) + let content = fs.readFileSync(file, 'utf8') + expect(content).toBe('foo') + }) + + it('should create file if does not exist', async () => { + await helper.edit() + let filepath = path.join(__dirname, 'foo') + await workspace.createFile(filepath, { ignoreIfExists: true }) + let exists = fs.existsSync(filepath) + expect(exists).toBe(true) + fs.unlinkSync(filepath) + }) + + it('should revert file create', async () => { + let filepath = path.join(os.tmpdir(), uuid()) + disposables.push(Disposable.create(() => { + if (fs.existsSync(filepath)) fs.unlinkSync(filepath) + })) + let fns: RecoverFunc[] = [] + await workspace.files.createFile(filepath, { overwrite: true }, fns) + expect(fs.existsSync(filepath)).toBe(true) + let bufnr = await nvim.call('bufnr', [filepath]) + expect(bufnr).toBeGreaterThan(0) + let doc = workspace.getDocument(bufnr) + expect(doc).toBeDefined() + for (let fn of fns) { + await fn() + } + expect(fs.existsSync(filepath)).toBe(false) + let loaded = await nvim.call('bufloaded', [filepath]) + expect(loaded).toBe(0) + }) +}) + +describe('renameFile', () => { + it('should throw when oldPath not exists', async () => { + let filepath = path.join(__dirname, 'not_exists_file') + let newPath = path.join(__dirname, 'bar') + let fn = async () => { + await workspace.renameFile(filepath, newPath) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should rename file on disk', async () => { + let filepath = await createTmpFile('test') + let newPath = path.join(path.dirname(filepath), 'new_file') + disposables.push(Disposable.create(() => { + if (fs.existsSync(newPath)) fs.unlinkSync(newPath) + if (fs.existsSync(filepath)) fs.unlinkSync(filepath) + })) + let fns: RecoverFunc[] = [] + await workspace.files.renameFile(filepath, newPath, { overwrite: true }, fns) + expect(fs.existsSync(newPath)).toBe(true) + for (let fn of fns) { + await fn() + } + expect(fs.existsSync(newPath)).toBe(false) + expect(fs.existsSync(filepath)).toBe(true) + }) + + it('should rename if file does not exist', async () => { + let filepath = path.join(__dirname, 'foo') + let newPath = path.join(__dirname, 'bar') + await workspace.createFile(filepath) + await workspace.renameFile(filepath, newPath) + expect(fs.existsSync(newPath)).toBe(true) + expect(fs.existsSync(filepath)).toBe(false) + fs.unlinkSync(newPath) + }) + + it('should rename current buffer with same bufnr', async () => { + let file = await createTmpFile('test') + let doc = await helper.createDocument(file) + await nvim.setLine('bar') + await doc.patchChange() + let newFile = path.join(os.tmpdir(), `coc-${process.pid}/new-${uuid()}`) + disposables.push(Disposable.create(() => { + if (fs.existsSync(newFile)) fs.unlinkSync(newFile) + })) + await workspace.renameFile(file, newFile) + let bufnr = await nvim.call('bufnr', ['%']) + expect(bufnr).toBe(doc.bufnr) + let line = await nvim.line + expect(line).toBe('bar') + let exists = fs.existsSync(newFile) + expect(exists).toBe(true) + }) + + it('should overwrite if file exists', async () => { + let filepath = path.join(os.tmpdir(), uuid()) + let newPath = path.join(os.tmpdir(), uuid()) + await workspace.createFile(filepath) + await workspace.createFile(newPath) + await workspace.renameFile(filepath, newPath, { overwrite: true }) + expect(fs.existsSync(newPath)).toBe(true) + expect(fs.existsSync(filepath)).toBe(false) + fs.unlinkSync(newPath) + }) + + it('should rename buffer in directory and revert', async () => { + let folder = path.join(os.tmpdir(), uuid()) + let newFolder = path.join(os.tmpdir(), uuid()) + fs.mkdirSync(folder) + disposables.push(Disposable.create(() => { + if (fs.existsSync(folder)) fs.removeSync(folder) + if (fs.existsSync(newFolder)) fs.removeSync(newFolder) + })) + let filepath = path.join(folder, 'new_file') + await workspace.createFile(filepath) + let bufnr = await nvim.call('bufnr', [filepath]) + expect(bufnr).toBeGreaterThan(0) + let fns: RecoverFunc[] = [] + await workspace.files.renameFile(folder, newFolder, { overwrite: true }, fns) + bufnr = await nvim.call('bufnr', [path.join(newFolder, 'new_file')]) + expect(bufnr).toBeGreaterThan(0) + for (let i = fns.length - 1; i >= 0; i--) { + await fns[i]() + } + bufnr = await nvim.call('bufnr', [filepath]) + expect(bufnr).toBeGreaterThan(0) + }) +}) + +describe('loadResource()', () => { + it('should load file as hidden buffer', async () => { + helper.updateConfiguration('workspace.openResourceCommand', '') + let filepath = await createTmpFile('foo') + let uri = URI.file(filepath).toString() + let doc = await workspace.files.loadResource(uri) + let bufnrs = await nvim.call('coc#window#bufnrs') as number[] + expect(bufnrs.indexOf(doc.bufnr)).toBe(-1) + }) +}) + +describe('deleteFile()', () => { + it('should throw when file not exists', async () => { + let filepath = path.join(__dirname, 'not_exists') + let fn = async () => { + await workspace.deleteFile(filepath) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should ignore when ignoreIfNotExists set', async () => { + let filepath = path.join(__dirname, 'not_exists') + let fns: RecoverFunc[] = [] + await workspace.files.deleteFile(filepath, { ignoreIfNotExists: true }, fns) + expect(fns.length).toBe(0) + }) + + it('should unload loaded buffer', async () => { + let filepath = await createTmpFile('file to delete') + disposables.push(Disposable.create(() => { + if (fs.existsSync(filepath)) fs.unlinkSync(filepath) + })) + await workspace.files.loadResource(URI.file(filepath).toString()) + let fns: RecoverFunc[] = [] + await workspace.files.deleteFile(filepath, {}, fns) + let loaded = await nvim.call('bufloaded', [filepath]) + expect(loaded).toBe(0) + for (let i = fns.length - 1; i >= 0; i--) { + await fns[i]() + } + expect(fs.existsSync(filepath)).toBe(true) + loaded = await nvim.call('bufloaded', [filepath]) + expect(loaded).toBe(1) + }) + + it('should delete and recover folder', async () => { + let folder = path.join(os.tmpdir(), uuid()) + disposables.push(Disposable.create(() => { + if (fs.existsSync(folder)) fs.rmdirSync(folder) + })) + fs.mkdirSync(folder) + expect(fs.existsSync(folder)).toBe(true) + let fns: RecoverFunc[] = [] + await workspace.files.deleteFile(folder, {}, fns) + expect(fs.existsSync(folder)).toBe(false) + for (let i = fns.length - 1; i >= 0; i--) { + await fns[i]() + } + expect(fs.existsSync(folder)).toBe(true) + await workspace.files.deleteFile(folder, {}) + }) + + it('should delete and recover folder recursive', async () => { + let folder = path.join(os.tmpdir(), uuid()) + disposables.push(Disposable.create(() => { + if (fs.existsSync(folder)) fs.removeSync(folder) + })) + fs.mkdirSync(folder) + await fs.writeFile(path.join(folder, 'new_file'), '', 'utf8') + let fns: RecoverFunc[] = [] + await workspace.files.deleteFile(folder, { recursive: true }, fns) + expect(fs.existsSync(folder)).toBe(false) + for (let i = fns.length - 1; i >= 0; i--) { + await fns[i]() + } + expect(fs.existsSync(folder)).toBe(true) + expect(fs.existsSync(path.join(folder, 'new_file'))).toBe(true) + await workspace.files.deleteFile(folder, { recursive: true }) + }) + + it('should delete file if exists', async () => { + let filepath = path.join(__dirname, 'foo') + await workspace.createFile(filepath) + expect(fs.existsSync(filepath)).toBe(true) + await workspace.deleteFile(filepath) + expect(fs.existsSync(filepath)).toBe(false) + }) +}) + +describe('loadFile()', () => { + it('should single loadFile', async () => { + let doc = await helper.createDocument() + let newFile = URI.file(path.join(__dirname, 'abc')).toString() + let document = await workspace.loadFile(newFile) + let bufnr = await nvim.call('bufnr', '%') + expect(document.uri.endsWith('abc')).toBe(true) + expect(bufnr).toBe(doc.bufnr) + }) +}) + +describe('loadFiles', () => { + it('should loadFiles', async () => { + let files = ['a', 'b', 'c'].map(key => URI.file(path.join(__dirname, key)).toString()) + let docs = await workspace.loadFiles(files) + let uris = docs.map(o => o.uri) + expect(uris).toEqual(files) + }) + + it('should load empty files array', async () => { + await workspace.loadFiles([]) + }) +}) + +describe('openTextDocument()', () => { + it('should open document already exists', async () => { + let doc = await helper.createDocument('a') + await nvim.command('enew') + await workspace.openTextDocument(URI.parse(doc.uri)) + let curr = await workspace.document + expect(curr.uri).toBe(doc.uri) + }) + + it('should throw when file does not exist', async () => { + let err + try { + await workspace.openTextDocument('/a/b/c') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should open untitled document', async () => { + let doc = await workspace.openTextDocument(URI.parse(`untitled:///a/b.js`)) + expect(doc.uri).toBe('file:///a/b.js') + }) + + it('should load file that exists', async () => { + let doc = await workspace.openTextDocument(URI.file(__filename)) + expect(URI.parse(doc.uri).fsPath).toBe(__filename) + let curr = await workspace.document + expect(curr.uri).toBe(doc.uri) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/funcs.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/funcs.test.ts new file mode 100644 index 00000000..084bdbab --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/funcs.test.ts @@ -0,0 +1,94 @@ +import os from 'os' +import path from 'path' +import Configurations from '../../configuration/index' +import * as funcs from '../../core/funcs' +let configurations: Configurations + +beforeAll(async () => { + let userConfigFile = path.join(process.env.COC_VIMCONFIG, 'coc-settings.json') + configurations = new Configurations(userConfigFile, { + $removeConfigurationOption: () => {}, + $updateConfigurationOption: () => {} + }) +}) + +describe('has()', () => { + it('should throw for invalid argument', async () => { + let env = { + isVim: true, + version: '8023956' + } + let err + try { + expect(funcs.has(env, '0.5.0')).toBe(true) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should detect version on vim8', async () => { + let env = { + isVim: true, + version: '8023956' + } + expect(funcs.has(env, 'patch-7.4.248')).toBe(true) + expect(funcs.has(env, 'patch-8.5.1')).toBe(false) + }) + + it('should delete version on neovim', async () => { + let env = { + isVim: false, + version: '0.6.1' + } + expect(funcs.has(env, 'nvim-0.5.0')).toBe(true) + expect(funcs.has(env, 'nvim-0.7.0')).toBe(false) + }) +}) + +describe('createNameSpace()', () => { + it('should create namespace', async () => { + let nr = funcs.createNameSpace('ns') + expect(nr).toBeDefined() + expect(nr).toBe(funcs.createNameSpace('ns')) + }) +}) + +describe('getWatchmanPath()', () => { + it('should get watchman path', async () => { + let res = funcs.getWatchmanPath(configurations) + expect(typeof res === 'string' || res == null).toBe(true) + }) +}) + +describe('findUp()', () => { + it('should return null when can not find ', async () => { + let nvim: any = { + call: () => { + return __filename + } + } + let res = await funcs.findUp(nvim, os.homedir(), ['file_not_exists']) + expect(res).toBeNull() + }) + + it('should return null when unable find cwd in cwd', async () => { + let nvim: any = { + call: () => { + return '' + } + } + let res = await funcs.findUp(nvim, os.homedir(), ['file_not_exists']) + expect(res).toBeNull() + }) +}) + +describe('score()', () => { + it('should return score', async () => { + expect(funcs.score(undefined, 'untitled:///1', '')).toBe(0) + expect(funcs.score({ scheme: '*' }, 'untitled:///1', '')).toBe(3) + expect(funcs.score('vim', 'untitled:///1', 'vim')).toBe(10) + expect(funcs.score('*', 'untitled:///1', '')).toBe(5) + expect(funcs.score('', 'untitled:///1', 'vim')).toBe(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/keymaps.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/keymaps.test.ts new file mode 100644 index 00000000..3dfa43be --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/keymaps.test.ts @@ -0,0 +1,79 @@ +import { Neovim } from '@chemzqm/neovim' +import workspace from '../../workspace' +import Keymaps from '../../core/keymaps' +import helper from '../helper' +import { Disposable } from 'vscode-languageserver-protocol' +import { disposeAll } from '../../util' + +let nvim: Neovim +let keymaps: Keymaps +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + keymaps = workspace.keymaps +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('doKeymap()', () => { + it('should not throw when key not mapped', async () => { + await keymaps.doKeymap('', '', '{C-a}') + }) +}) + +describe('registerKeymap()', () => { + it('should throw for invalid key', async () => { + let err + try { + keymaps.registerKeymap(['i'], '', jest.fn()) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should throw for duplicated key', async () => { + keymaps.registerKeymap(['i'], 'tmp', jest.fn()) + let err + try { + keymaps.registerKeymap(['i'], 'tmp', jest.fn()) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should register insert key mapping', async () => { + let fn = jest.fn() + disposables.push(keymaps.registerKeymap(['i'], 'test', fn)) + await helper.wait(10) + let res = await nvim.call('execute', ['verbose imap (coc-test)']) + expect(res).toMatch('coc#_insert_key') + }) +}) + +describe('registerExprKeymap()', () => { + it('should visual key mapping', async () => { + await nvim.setLine('foo') + let called = false + let fn = () => { + called = true + return '' + } + disposables.push(keymaps.registerExprKeymap('x', 'x', fn, true)) + await helper.wait(50) + await nvim.command('normal! viw') + await nvim.input('x') + await helper.wait(50) + expect(called).toBe(true) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/locations.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/locations.test.ts new file mode 100644 index 00000000..6fc733e8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/locations.test.ts @@ -0,0 +1,148 @@ +import { Neovim } from '@chemzqm/neovim' +import os from 'os' +import path from 'path' +import { Location, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + await nvim.command(`source ${path.join(process.cwd(), 'autoload/coc/ui.vim')}`) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +function createLocations(): Location[] { + let uri = URI.file(__filename).toString() + return [Location.create(uri, Range.create(0, 0, 1, 0)), Location.create(uri, Range.create(2, 0, 3, 0))] +} + +describe('showLocations()', () => { + it('should show location list by default', async () => { + let locations = createLocations() + await workspace.showLocations(locations) + await helper.waitFor('bufname', ['%'], 'list:///location') + }) + + it('should fire autocmd when location list disabled', async () => { + Object.assign(workspace.env, { + locationlist: false + }) + await nvim.exec(` +function OnLocationsChange() + let g:called = 1 +endfunction +autocmd User CocLocationsChange :call OnLocationsChange()`) + let locations = createLocations() + await workspace.showLocations(locations) + await helper.waitFor('eval', [`get(g:,'called',0)`], 1) + }) + + it('should show quickfix when quickfix enabled', async () => { + helper.updateConfiguration('coc.preferences.useQuickfixForLocations', true) + let locations = createLocations() + await workspace.showLocations(locations) + await helper.waitFor('eval', [`&buftype`], 'quickfix') + }) + + it('should use customized quickfix open command', async () => { + await nvim.setVar('coc_quickfix_open_command', 'copen 1') + helper.updateConfiguration('coc.preferences.useQuickfixForLocations', true) + let locations = createLocations() + await workspace.showLocations(locations) + await helper.waitFor('eval', [`&buftype`], 'quickfix') + let win = await nvim.window + let height = await win.height + expect(height).toBe(1) + }) +}) + +describe('jumpTo()', () => { + it('should jumpTo position', async () => { + let uri = URI.file('/tmp/foo').toString() + await workspace.jumpTo(uri, { line: 1, character: 1 }) + await nvim.command('setl buftype=nofile') + let buf = await nvim.buffer + let name = await buf.name + expect(name).toMatch('/foo') + await buf.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + await workspace.jumpTo(uri, { line: 1, character: 1 }) + let pos = await nvim.call('getcurpos') + expect(pos.slice(1, 3)).toEqual([2, 2]) + }) + + it('should jumpTo uri without normalize', async () => { + let uri = 'zipfile:///tmp/clojure-1.9.0.jar::clojure/core.clj' + await workspace.jumpTo(uri) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toBe(uri) + }) + + it('should jump without position', async () => { + let uri = URI.file('/tmp/foo').toString() + await workspace.jumpTo(uri) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toMatch('/foo') + }) + + it('should jumpTo custom uri scheme', async () => { + let uri = 'jdt://foo' + await workspace.jumpTo(uri, { line: 1, character: 1 }) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toBe(uri) + }) + +}) + +describe('openResource()', () => { + it('should open resource', async () => { + let uri = URI.file(path.join(os.tmpdir(), 'bar')).toString() + await workspace.openResource(uri) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toMatch('bar') + }) + + it('should open none file uri', async () => { + workspace.registerTextDocumentContentProvider('jd', { + provideTextDocumentContent: () => 'jd' + }) + let uri = 'jd://abc' + await workspace.openResource(uri) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toBe('jd://abc') + }) + + it('should open opened buffer', async () => { + let buf = await helper.edit() + let doc = workspace.getDocument(buf.id) + await workspace.openResource(doc.uri) + await helper.wait(30) + let bufnr = await nvim.call('bufnr', '%') + expect(bufnr).toBe(buf.id) + }) + + it('should open url', async () => { + await helper.mockFunction('coc#ui#open_url', 0) + let buf = await helper.edit() + let uri = 'http://example.com' + await workspace.openResource(uri) + await helper.wait(30) + let bufnr = await nvim.call('bufnr', '%') + expect(bufnr).toBe(buf.id) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/terminals.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/terminals.test.ts new file mode 100644 index 00000000..119acf87 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/terminals.test.ts @@ -0,0 +1,136 @@ +import { Neovim } from '@chemzqm/neovim' +import os from 'os' +import path from 'path' +import which from 'which' +import Terminals from '../../core/terminals' +import window from '../../window' +import helper from '../helper' + +let nvim: Neovim +let terminals: Terminals + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + terminals = new Terminals() +}) + +afterEach(() => { + terminals.reset() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('create terminal', () => { + it('should use cleaned env', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash'), + strictEnv: true + }) + await helper.wait(50) + terminal.sendText(`echo $NODE_ENV`, true) + await helper.wait(50) + let buf = nvim.createBuffer(terminal.bufnr) + let lines = await buf.lines + expect(lines.includes('test')).toBe(false) + }) + + it('should use custom shell command', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash') + }) + let bufnr = terminal.bufnr + let bufname = await nvim.call('bufname', [bufnr]) as string + expect(bufname.includes('bash')).toBe(true) + }) + + it('should use custom cwd', async () => { + let basename = path.basename(os.tmpdir()) + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + cwd: os.tmpdir() + }) + let bufnr = terminal.bufnr + let bufname = await nvim.call('bufname', [bufnr]) as string + expect(bufname.includes(basename)).toBe(true) + }) + + it('should have exit code', async () => { + let exitStatus + terminals.onDidCloseTerminal(terminal => { + exitStatus = terminal.exitStatus + }) + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash'), + strictEnv: true + }) + await helper.wait(50) + terminal.sendText('exit', true) + await helper.waitFor('bufloaded', [terminal.bufnr], 0) + await helper.wait(50) + expect(exitStatus).toBeDefined() + expect(exitStatus.code).toBeDefined() + }) + + it('should not throw when show & hide disposed terminal', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash') + }) + terminal.dispose() + await terminal.show() + await terminal.hide() + }) + + it('should show terminal on current window', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash') + }) + let winid = await nvim.call('bufwinid', [terminal.bufnr]) + expect(winid).toBeGreaterThan(0) + await nvim.call('win_gotoid', [winid]) + await terminal.show() + }) + + it('should show terminal that shown', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash') + }) + let res = await terminal.show(true) + expect(res).toBe(true) + expect(terminal.bufnr).toBeDefined() + let winid = await nvim.call('bufwinid', [terminal.bufnr]) + let curr = await nvim.call('win_getid', []) + expect(winid != curr).toBe(true) + }) + + it('should show hidden terminal', async () => { + let terminal = await terminals.createTerminal(nvim, { + name: 'test', + shellPath: which.sync('bash') + }) + await terminal.hide() + await helper.wait(30) + let res = await terminal.show() + expect(res).toBe(true) + }) + + it('should create terminal', async () => { + let terminal = await window.createTerminal({ + name: 'test', + }) + expect(terminal).toBeDefined() + expect(terminal.processId).toBeDefined() + expect(terminal.name).toBeDefined() + terminal.dispose() + await helper.wait(30) + expect(terminal.exitStatus).toEqual({ code: undefined }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/ui.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/ui.test.ts new file mode 100644 index 00000000..b3904549 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/ui.test.ts @@ -0,0 +1,92 @@ +import { Neovim } from '@chemzqm/neovim' +import { Position, Range } from 'vscode-languageserver-types' +import * as ui from '../../core/ui' +import helper from '../helper' + +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('getCursorPosition()', () => { + it('should get cursor position', async () => { + await nvim.call('cursor', [1, 1]) + let res = await ui.getCursorPosition(nvim) + expect(res).toEqual({ + line: 0, + character: 0 + }) + }) +}) + +describe('moveTo()', () => { + it('should moveTo position', async () => { + await nvim.setLine('foo') + await ui.moveTo(nvim, Position.create(0, 1), true) + let res = await ui.getCursorPosition(nvim) + expect(res).toEqual({ line: 0, character: 1 }) + }) +}) + +describe('getCursorScreenPosition()', () => { + it('should get cursor screen position', async () => { + let res = await ui.getCursorScreenPosition(nvim) + expect(res).toBeDefined() + expect(typeof res.row).toBe('number') + expect(typeof res.col).toBe('number') + }) +}) + +describe('showMessage()', () => { + it('should showMessage on vim', async () => { + ui.showMessage(nvim, 'my message', 'MoreMsg', true) + await helper.wait(100) + let cmdline = await helper.getCmdline() + expect(cmdline).toMatch(/my message/) + }) +}) + +describe('getSelection()', () => { + it('should return null when no selection exists', async () => { + let res = await ui.getSelection(nvim, 'v') + expect(res).toBeNull() + }) + + it('should return range for line selection', async () => { + await nvim.setLine('foo') + await nvim.input('V') + await nvim.input('') + let res = await ui.getSelection(nvim, 'V') + expect(res).toEqual({ start: { line: 0, character: 0 }, end: { line: 1, character: 0 } }) + }) +}) + +describe('selectRange()', () => { + it('should select range #1', async () => { + await nvim.call('setline', [1, ['foo', 'b']]) + await nvim.command('set selection=inclusive') + await nvim.command('set virtualedit=onemore') + await ui.selectRange(nvim, Range.create(0, 0, 1, 1), true) + await nvim.input('') + let res = await ui.getSelection(nvim, 'v') + expect(res).toEqual(Range.create(0, 0, 1, 1)) + }) + + it('should select range #2', async () => { + await nvim.call('setline', [1, ['foo', 'b']]) + await ui.selectRange(nvim, Range.create(0, 0, 1, 0), true) + await nvim.input('') + let res = await ui.getSelection(nvim, 'v') + expect(res).toEqual(Range.create(0, 0, 0, 3)) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/core/workspaceFolder.test.ts b/sources_non_forked/coc.nvim/src/__tests__/core/workspaceFolder.test.ts new file mode 100644 index 00000000..6d7e2854 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/core/workspaceFolder.test.ts @@ -0,0 +1,290 @@ +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { Disposable, WorkspaceFoldersChangeEvent } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import Configurations from '../../configuration/index' +import WorkspaceFolderController from '../../core/workspaceFolder' +import { PatternType } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +let workspaceFolder: WorkspaceFolderController +let configurations: Configurations +let disposables: Disposable[] = [] +let nvim: Neovim + +function updateConfiguration(key: string, value: any, defaults: any): void { + configurations.updateUserConfig({ [key]: value }) + disposables.push({ + dispose: () => { + configurations.updateUserConfig({ [key]: defaults }) + } + }) +} + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + let userConfigFile = path.join(process.env.COC_VIMCONFIG, 'coc-settings.json') + configurations = new Configurations(userConfigFile, { + $removeConfigurationOption: () => {}, + $updateConfigurationOption: () => {} + }) + workspaceFolder = new WorkspaceFolderController(configurations) +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + workspaceFolder.reset() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('WorkspaceFolderController', () => { + describe('asRelativePath()', () => { + function assertAsRelativePath(input: string, expected: string, includeWorkspace?: boolean) { + const actual = workspaceFolder.getRelativePath(input, includeWorkspace) + expect(actual).toBe(expected) + } + + it('should get relative path', async () => { + workspaceFolder.addWorkspaceFolder(`/Coding/Applications/NewsWoWBot`, false) + assertAsRelativePath('/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot') + assertAsRelativePath('/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart', + '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart') + assertAsRelativePath('', '') + assertAsRelativePath('/foo/bar', '/foo/bar') + assertAsRelativePath('in/out', 'in/out') + }) + + it('should asRelativePath, same paths, #11402', async () => { + const root = '/home/aeschli/workspaces/samples/docker' + const input = '/home/aeschli/workspaces/samples/docker' + workspaceFolder.addWorkspaceFolder(root, false) + assertAsRelativePath(input, input) + const input2 = '/home/aeschli/workspaces/samples/docker/a.file' + assertAsRelativePath(input2, 'a.file') + }) + + it('should asRelativePath, not workspaceFolder', async () => { + expect(workspace.getRelativePath('')).toBe('') + assertAsRelativePath('/foo/bar', '/foo/bar') + }) + + it('should asRelativePath, multiple folders', () => { + workspaceFolder.addWorkspaceFolder(`/Coding/One`, false) + workspaceFolder.addWorkspaceFolder(`/Coding/Two`, false) + assertAsRelativePath('/Coding/One/file.txt', 'One/file.txt') + assertAsRelativePath('/Coding/Two/files/out.txt', 'Two/files/out.txt') + assertAsRelativePath('/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt') + }) + + it('should slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', async () => { + workspaceFolder.addWorkspaceFolder(`/Coding/One`, false) + workspaceFolder.addWorkspaceFolder(`/Coding/Two`, false) + + assertAsRelativePath('/Coding/One/file.txt', 'One/file.txt') + assertAsRelativePath('/Coding/One/file.txt', 'One/file.txt', true) + assertAsRelativePath('/Coding/One/file.txt', 'file.txt', false) + assertAsRelativePath('/Coding/Two/files/out.txt', 'Two/files/out.txt') + assertAsRelativePath('/Coding/Two/files/out.txt', 'Two/files/out.txt', true) + assertAsRelativePath('/Coding/Two/files/out.txt', 'files/out.txt', false) + assertAsRelativePath('/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt') + assertAsRelativePath('/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true) + assertAsRelativePath('/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false) + }) + }) + + describe('setWorkspaceFolders()', () => { + it('should set valid folders', async () => { + workspaceFolder.setWorkspaceFolders([os.tmpdir(), '/a/not_exists']) + let folders = workspaceFolder.workspaceFolders + expect(folders.length).toBe(2) + }) + }) + + describe('getWorkspaceFolder()', () => { + it('should get workspaceFolder by uri', async () => { + let res = workspaceFolder.getWorkspaceFolder(URI.parse('untitled://1')) + expect(res).toBeUndefined() + res = workspaceFolder.getWorkspaceFolder(URI.file('/a/b')) + expect(res).toBeUndefined() + let filepath = path.join(process.cwd(), 'a/b') + workspaceFolder.setWorkspaceFolders([process.cwd()]) + res = workspaceFolder.getWorkspaceFolder(URI.file(filepath)) + expect(URI.parse(res.uri).fsPath).toBe(process.cwd()) + }) + }) + + describe('getRootPatterns()', () => { + it('should get patterns from b:coc_root_patterns', async () => { + await nvim.command('edit t.vim | let b:coc_root_patterns=["foo"]') + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.getRootPatterns(doc, PatternType.Buffer) + expect(res).toEqual(['foo']) + }) + + it('should get patterns from languageserver', async () => { + updateConfiguration('languageserver', { + test: { + filetypes: ['vim'], + rootPatterns: ['bar'] + } + }, {}) + workspaceFolder.addRootPattern('vim', ['foo']) + await nvim.command('edit t.vim') + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.getRootPatterns(doc, PatternType.LanguageServer) + expect(res).toEqual(['bar', 'foo']) + }) + + it('should get patterns from user configuration', async () => { + let doc = await workspace.document + let res = workspaceFolder.getRootPatterns(doc, PatternType.Global) + expect(res.includes('.git')).toBe(true) + }) + }) + + describe('resolveRoot()', () => { + const cwd = process.cwd() + const expand = (input: string) => { + return workspace.expand(input) + } + + it('should resolve to cwd for file in cwd', async () => { + updateConfiguration('coc.preferences.rootPatterns', [], ['.git', '.hg', '.projections.json']) + let file = path.join(os.tmpdir(), 'foo') + await nvim.command(`edit ${file}`) + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, os.tmpdir(), false, expand) + expect(res).toBe(os.tmpdir()) + }) + + it('should not fallback to cwd as workspace folder', async () => { + updateConfiguration('coc.preferences.rootPatterns', [], ['.git', '.hg', '.projections.json']) + updateConfiguration('workspace.workspaceFolderFallbackCwd', false, true) + let file = path.join(os.tmpdir(), 'foo') + await nvim.command(`edit ${file}`) + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, os.tmpdir(), false, expand) + expect(res).toBe(null) + }) + + it('should return null for untitled buffer', async () => { + await nvim.command('enew') + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, cwd, false, expand) + expect(res).toBe(null) + }) + + it('should respect ignored filetypes', async () => { + updateConfiguration('workspace.ignoredFiletypes', ['vim'], []) + await nvim.command('edit t.vim') + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, cwd, false, expand) + expect(res).toBe(null) + }) + + it('should respect workspaceFolderCheckCwd', async () => { + let called = 0 + disposables.push(workspaceFolder.onDidChangeWorkspaceFolders(() => { + called++ + })) + workspaceFolder.addRootPattern('vim', ['.vim']) + await nvim.command('edit a/.vim/t.vim') + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, cwd, true, expand) + expect(res).toBe(process.cwd()) + await nvim.command('edit a/foo') + doc = await workspace.document + res = workspaceFolder.resolveRoot(doc, cwd, true, expand) + expect(res).toBe(process.cwd()) + expect(called).toBe(1) + }) + + it('should respect ignored folders', async () => { + updateConfiguration('workspace.ignoredFolders', ['$HOME/foo', '$HOME'], []) + let file = path.join(os.homedir(), '.vim/bar') + workspaceFolder.addRootPattern('vim', ['.vim']) + await nvim.command(`edit ${file}`) + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, path.join(os.homedir(), 'foo'), true, expand) + expect(res).toBe(null) + }) + + describe('bottomUpFileTypes', () => { + it('should respect specific filetype', async () => { + updateConfiguration('coc.preferences.rootPatterns', ['.vim'], ['.git', '.hg', '.projections.json']) + updateConfiguration('workspace.bottomUpFiletypes', ['vim'], []) + let root = path.join(os.tmpdir(), 'a') + let dir = path.join(root, '.vim') + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }) + } + let file = path.join(dir, 'foo') + await nvim.command(`edit ${file}`) + await nvim.command('setf vim') + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, file, true, expand) + expect(res).toBe(root) + }) + + it('should respect wildcard', async () => { + updateConfiguration('coc.preferences.rootPatterns', ['.vim'], ['.git', '.hg', '.projections.json']) + updateConfiguration('workspace.bottomUpFiletypes', ['*'], []) + let root = path.join(os.tmpdir(), 'a') + let dir = path.join(root, '.vim') + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }) + await helper.wait(30) + } + let file = path.join(dir, 'foo') + await nvim.command(`edit ${file}`) + let doc = await workspace.document + let res = workspaceFolder.resolveRoot(doc, file, true, expand) + expect(res).toBe(root) + }) + }) + }) + + describe('renameWorkspaceFolder()', () => { + it('should rename workspaceFolder', async () => { + let e: WorkspaceFoldersChangeEvent + disposables.push(workspaceFolder.onDidChangeWorkspaceFolders(ev => { + e = ev + })) + let cwd = process.cwd() + workspaceFolder.addWorkspaceFolder(cwd, false) + workspaceFolder.addWorkspaceFolder(cwd, false) + workspaceFolder.renameWorkspaceFolder(cwd, path.join(cwd, '.vim')) + expect(e.removed.length).toBe(1) + expect(e.added.length).toBe(1) + }) + }) + + describe('removeWorkspaceFolder()', () => { + it('should remote workspaceFolder', async () => { + let e: WorkspaceFoldersChangeEvent + disposables.push(workspaceFolder.onDidChangeWorkspaceFolders(ev => { + e = ev + })) + let cwd = process.cwd() + workspaceFolder.addWorkspaceFolder(cwd, false) + workspaceFolder.removeWorkspaceFolder(cwd) + workspaceFolder.removeWorkspaceFolder('/a/b') + expect(e.removed.length).toBe(1) + expect(e.added.length).toBe(0) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/global/index.js b/sources_non_forked/coc.nvim/src/__tests__/extensions/global/index.js new file mode 100644 index 00000000..e48cb515 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/global/index.js @@ -0,0 +1,7 @@ +exports.activate = async context => { + return { + getContext: () => { + return context + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/global/package.json b/sources_non_forked/coc.nvim/src/__tests__/extensions/global/package.json new file mode 100644 index 00000000..784d43bd --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/global/package.json @@ -0,0 +1,7 @@ +{ + "name": "global", + "version": "1.0.0", + "engines": { + "coc": "^0.0.46" + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/package.json b/sources_non_forked/coc.nvim/src/__tests__/extensions/package.json new file mode 100644 index 00000000..cc903b48 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "global": ">=1.0.0", + "test": ">=1.0.0" + } +} \ No newline at end of file diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/root.js b/sources_non_forked/coc.nvim/src/__tests__/extensions/root.js new file mode 100644 index 00000000..0e76809f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/root.js @@ -0,0 +1,7 @@ +exports.activate = context => { + return { + root: () => { + return context.extensionPath + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/test/index.js b/sources_non_forked/coc.nvim/src/__tests__/extensions/test/index.js new file mode 100644 index 00000000..f8d2f71a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/test/index.js @@ -0,0 +1,13 @@ +exports.activate = async context => { + return { + asAbsolutePath: p => { + return context.asAbsolutePath(p) + }, + getContext: () => { + return context + }, + echo: x => { + return x + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/test/package.json b/sources_non_forked/coc.nvim/src/__tests__/extensions/test/package.json new file mode 100644 index 00000000..4993d0aa --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/test/package.json @@ -0,0 +1,33 @@ +{ + "name": "test", + "version": "1.0.0", + "engines": { + "coc": "^0.0.46" + }, + "contributes": { + "rootPatterns": [ + { + "filetype": "javascript", + "patterns": [ + "package.json", + "jsconfig.json" + ] + } + ], + "commands": [ + { + "title": "Test", + "command": "test.run" + } + ], + "configuration": { + "properties": { + "test.enable": { + "type": "boolean", + "default": true, + "description": "Enable test" + } + } + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/index.js b/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/index.js new file mode 100644 index 00000000..e48cb515 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/index.js @@ -0,0 +1,7 @@ +exports.activate = async context => { + return { + getContext: () => { + return context + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/package.json b/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/package.json new file mode 100644 index 00000000..95a64e73 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/extensions/vim/local/package.json @@ -0,0 +1,7 @@ +{ + "name": "local", + "version": "1.0.0", + "engines": { + "coc": "^0.0.46" + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/callHierarchy.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/callHierarchy.test.ts new file mode 100644 index 00000000..7f1f7ce8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/callHierarchy.test.ts @@ -0,0 +1,390 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, CallHierarchyItem, SymbolKind, Range, SymbolTag } from 'vscode-languageserver-protocol' +import CallHierarchyHandler from '../../handler/callHierarchy' +import languages from '../../languages' +import workspace from '../../workspace' +import { disposeAll } from '../../util' +import { URI } from 'vscode-uri' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let callHierarchy: CallHierarchyHandler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + callHierarchy = helper.plugin.getHandler().callHierarchy +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +function createCallItem(name: string, kind: SymbolKind, uri: string, range: Range): CallHierarchyItem { + return { + name, + kind, + uri, + range, + selectionRange: range + } +} + +describe('CallHierarchy', () => { + it('should throw for when provider does not exist', async () => { + let err + try { + await callHierarchy.getIncoming() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should get undefined when prepare failed', async () => { + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return undefined + }, + provideCallHierarchyIncomingCalls() { + return [] + }, + provideCallHierarchyOutgoingCalls() { + return [] + } + })) + let res = await callHierarchy.getOutgoing() + expect(res).toBeUndefined() + }) + + it('should get incoming & outgoing callHierarchy items', async () => { + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, 'test:///foo', Range.create(0, 0, 0, 5)) + }, + provideCallHierarchyIncomingCalls() { + return [{ + from: createCallItem('bar', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)), + fromRanges: [Range.create(0, 0, 0, 5)] + }] + }, + provideCallHierarchyOutgoingCalls() { + return [{ + to: createCallItem('bar', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)), + fromRanges: [Range.create(1, 0, 1, 5)] + }] + } + })) + let res = await callHierarchy.getIncoming() + expect(res.length).toBe(1) + expect(res[0].from.name).toBe('bar') + let outgoing = await callHierarchy.getOutgoing() + expect(outgoing.length).toBe(1) + res = await callHierarchy.getIncoming(outgoing[0].to) + expect(res.length).toBe(1) + }) + + it('should show message when provider does not exist', async () => { + await callHierarchy.showCallHierarchyTree('incoming') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines[0]).toMatch('callHierarchy provider not found') + await nvim.command('wincmd p') + }) + + it('should no results when no result returned.', async () => { + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return [] + }, + provideCallHierarchyIncomingCalls() { + return [] + }, + provideCallHierarchyOutgoingCalls() { + return [] + } + })) + await callHierarchy.showCallHierarchyTree('incoming') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines[0]).toBe('No results') + await nvim.command('wincmd p') + }) + + it('should render description and support default action', async () => { + let doc = await workspace.document + let bufnr = doc.bufnr + await doc.buffer.setLines(['foo'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(1, 0, 1, 3)) + item.detail = 'Detail' + item.tags = [SymbolTag.Deprecated] + return [{ + from: item, + fromRanges: [Range.create(2, 0, 2, 5)] + }] + }, + provideCallHierarchyOutgoingCalls() { + return [] + } + })) + await callHierarchy.showCallHierarchyTree('incoming') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'INCOMING CALLS', + '- c foo', + ' + c bar Detail' + ]) + await nvim.command('exe 3') + await nvim.input('t') + await helper.waitFor('getline', ['.'], ' - c bar Detail') + await nvim.input('') + await helper.waitFor('expand', ['%:p'], fsPath) + let res = await nvim.call('coc#cursor#position') + expect(res).toEqual([1, 0]) + let matches = await nvim.call('getmatches') as any[] + expect(matches.length).toBe(2) + await nvim.command(`b ${bufnr}`) + await helper.wait(50) + matches = await nvim.call('getmatches') + expect(matches.length).toBe(0) + await nvim.command(`wincmd o`) + await helper.wait(50) + }) + + it('should invoke open in new tab action', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + return [] + }, + provideCallHierarchyOutgoingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1)) + item.detail = 'Detail' + return [{ + to: item, + fromRanges: [Range.create(1, 0, 1, 3)] + }] + } + })) + let win = await nvim.window + let tab = await nvim.call('tabpagenr') + await callHierarchy.showCallHierarchyTree('outgoing') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo', + ' + c bar Detail' + ]) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(100) + await nvim.input('') + await helper.wait(200) + let newTab = await nvim.call('tabpagenr') + expect(newTab != tab).toBe(true) + doc = await workspace.document + expect(doc.uri).toBe(uri) + let res = await nvim.call('getmatches', [win.id]) + expect(res.length).toBe(1) + }) + + it('should invoke show incoming calls action', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + return [{ + from: createCallItem('test', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)), + fromRanges: [Range.create(0, 0, 0, 5)] + }] + }, + provideCallHierarchyOutgoingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1)) + item.detail = 'Detail' + return [{ + to: item, + fromRanges: [Range.create(1, 0, 1, 3)] + }] + } + })) + await callHierarchy.showCallHierarchyTree('outgoing') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo', + ' + c bar Detail' + ]) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + await nvim.input('2') + await helper.wait(200) + lines = await buf.lines + expect(lines).toEqual([ + 'INCOMING CALLS', + '- c bar Detail', + ' + c test' + ]) + await nvim.command('bd!') + }) + + it('should invoke show outgoing calls action', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + return [{ + from: createCallItem('test', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)), + fromRanges: [Range.create(0, 0, 0, 5)] + }] + }, + provideCallHierarchyOutgoingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1)) + item.detail = 'Detail' + return [{ + to: item, + fromRanges: [Range.create(1, 0, 1, 3)] + }] + } + })) + await callHierarchy.showCallHierarchyTree('incoming') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'INCOMING CALLS', + '- c foo', + ' + c test' + ]) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + await nvim.input('3') + await helper.wait(200) + lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c test', + ' + c bar Detail' + ]) + await nvim.command('bd!') + }) + + it('should invoke dismiss action #1', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + return [] + }, + provideCallHierarchyOutgoingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1)) + item.detail = 'Detail' + return [{ + to: item, + fromRanges: [Range.create(1, 0, 1, 3)] + }] + } + })) + await callHierarchy.showCallHierarchyTree('outgoing') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo', + ' + c bar Detail' + ]) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + await nvim.input('4') + await helper.wait(200) + lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo' + ]) + await nvim.command('wincmd c') + }) + + it('should invoke dismiss action #2', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let fsPath = await createTmpFile('foo\nbar\ncontent\n') + let uri = URI.file(fsPath).toString() + disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], { + prepareCallHierarchy() { + return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3)) + }, + provideCallHierarchyIncomingCalls() { + return [] + }, + provideCallHierarchyOutgoingCalls() { + let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1)) + item.detail = 'Detail' + return [{ + to: item, + fromRanges: [Range.create(1, 0, 1, 3)] + }] + } + })) + await callHierarchy.showCallHierarchyTree('outgoing') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo', + ' + c bar Detail' + ]) + await nvim.command('exe 3') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 4') + await nvim.input('') + await helper.wait(50) + await nvim.input('4') + await helper.wait(200) + lines = await buf.lines + expect(lines).toEqual([ + 'OUTGOING CALLS', + '- c foo', + ' - c bar Detail' + ]) + await nvim.command('wincmd c') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/codeActions.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/codeActions.test.ts new file mode 100644 index 00000000..628aaaa9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/codeActions.test.ts @@ -0,0 +1,414 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, CodeAction, Command, CodeActionContext, CodeActionKind, TextEdit, Disposable, Range, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import commands from '../../commands' +import ActionsHandler from '../../handler/codeActions' +import languages from '../../languages' +import { ProviderResult } from '../../provider' +import { disposeAll } from '../../util' +import { rangeInRange } from '../../util/position' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let codeActions: ActionsHandler +let currActions: CodeAction[] +let resolvedAction: CodeAction +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + codeActions = helper.plugin.getHandler().codeActions +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: ( + _document: TextDocument, + _range: Range, + _context: CodeActionContext, + _token: CancellationToken + ) => currActions, + resolveCodeAction: ( + _action: CodeAction, + _token: CancellationToken + ): ProviderResult => resolvedAction + }, undefined)) +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('handler codeActions', () => { + describe('organizeImport', () => { + it('should throw error when organize import action not found', async () => { + currActions = [] + await helper.createDocument() + let err + try { + await codeActions.organizeImport() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should perform organize import action', async () => { + let doc = await helper.createDocument() + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let edits: TextEdit[] = [] + edits.push(TextEdit.replace(Range.create(0, 0, 0, 3), 'bar')) + edits.push(TextEdit.replace(Range.create(1, 0, 1, 3), 'foo')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('organize import', edit, CodeActionKind.SourceOrganizeImports) + currActions = [action, CodeAction.create('another action')] + await codeActions.organizeImport() + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar', 'foo']) + }) + + it('should register editor.action.organizeImport command', async () => { + let doc = await helper.createDocument() + await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + let edits: TextEdit[] = [] + edits.push(TextEdit.replace(Range.create(0, 0, 0, 3), 'bar')) + edits.push(TextEdit.replace(Range.create(1, 0, 1, 3), 'foo')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('organize import', edit, CodeActionKind.SourceOrganizeImports) + currActions = [action, CodeAction.create('another action')] + await commands.executeCommand('editor.action.organizeImport') + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar', 'foo']) + }) + }) + + describe('codeActionRange', () => { + it('should show warning when no action available', async () => { + await helper.createDocument() + currActions = [] + await codeActions.codeActionRange(1, 2, CodeActionKind.QuickFix) + let line = await helper.getCmdline() + expect(line).toMatch(/No quickfix code action/) + }) + + it('should apply chosen action', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + currActions = [action] + let p = codeActions.codeActionRange(1, 2, CodeActionKind.QuickFix) + await helper.wait(100) + await nvim.input('') + await p + let buf = nvim.createBuffer(doc.bufnr) + let lines = await buf.lines + expect(lines[0]).toBe('bar') + }) + }) + + describe('getCodeActions', () => { + it('should get empty actions', async () => { + currActions = [] + let doc = await helper.createDocument() + let res = await codeActions.getCodeActions(doc) + expect(res.length).toBe(0) + }) + + it('should not filter disabled actions', async () => { + currActions = [] + let action = CodeAction.create('foo', CodeActionKind.QuickFix) + action.disabled = { reason: 'disabled' } + currActions.push(action) + action = CodeAction.create('foo', CodeActionKind.QuickFix) + action.disabled = { reason: 'disabled' } + currActions.push(action) + let doc = await helper.createDocument() + let res = await codeActions.getCodeActions(doc) + expect(res.length).toBe(1) + }) + + it('should get all actions', async () => { + let doc = await helper.createDocument() + await doc.buffer.setLines(['', '', ''], { start: 0, end: -1, strictIndexing: false }) + let action = CodeAction.create('curr action', CodeActionKind.Empty) + currActions = [action] + let range: Range + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: ( + _document: TextDocument, + r: Range, + _context: CodeActionContext, _token: CancellationToken + ) => { + range = r + return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')] + }, + }, undefined)) + let res = await codeActions.getCodeActions(doc) + expect(range).toEqual(Range.create(0, 0, 3, 0)) + expect(res.length).toBe(4) + }) + + it('should filter actions by range', async () => { + let doc = await helper.createDocument() + await doc.buffer.setLines(['', '', ''], { start: 0, end: -1, strictIndexing: false }) + currActions = [] + let range: Range + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: ( + _document: TextDocument, + r: Range, + _context: CodeActionContext, _token: CancellationToken + ) => { + range = r + if (rangeInRange(r, Range.create(0, 0, 1, 0))) return [CodeAction.create('a')] + return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')] + }, + }, undefined)) + let res = await codeActions.getCodeActions(doc, Range.create(0, 0, 0, 0)) + expect(range).toEqual(Range.create(0, 0, 0, 0)) + expect(res.length).toBe(1) + }) + + it('should filter actions by kind prefix', async () => { + let doc = await helper.createDocument() + let action = CodeAction.create('my action', CodeActionKind.SourceFixAll) + currActions = [action] + let res = await codeActions.getCodeActions(doc, undefined, [CodeActionKind.Source]) + expect(res.length).toBe(1) + expect(res[0].kind).toBe(CodeActionKind.SourceFixAll) + }) + }) + + describe('getCurrentCodeActions', () => { + let range: Range + beforeEach(() => { + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: ( + _document: TextDocument, + r: Range, + _context: CodeActionContext, _token: CancellationToken + ) => { + range = r + return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')] + }, + }, undefined)) + }) + + it('should get codeActions by line', async () => { + currActions = [] + await helper.createDocument() + let res = await codeActions.getCurrentCodeActions('line') + expect(range).toEqual(Range.create(0, 0, 1, 0)) + expect(res.length).toBe(3) + }) + + it('should get codeActions by cursor', async () => { + currActions = [] + await helper.createDocument() + let res = await codeActions.getCurrentCodeActions('cursor') + expect(range).toEqual(Range.create(0, 0, 0, 0)) + expect(res.length).toBe(3) + }) + + it('should get codeActions by visual mode', async () => { + currActions = [] + await helper.createDocument() + await nvim.setLine('foo') + await nvim.command('normal! 0v$') + await nvim.input('') + let res = await codeActions.getCurrentCodeActions('v') + expect(range).toEqual(Range.create(0, 0, 0, 3)) + expect(res.length).toBe(3) + }) + }) + + describe('doCodeAction', () => { + it('should not throw when no action exists', async () => { + currActions = [] + await helper.createDocument() + let err + try { + await codeActions.doCodeAction(undefined) + } catch (e) { + err = e + } + expect(err).toBeUndefined() + }) + + it('should apply single code action when only is title', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + currActions = [action] + await codeActions.doCodeAction(undefined, 'code fix') + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + }) + + it('should apply single code action when only is codeAction array', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + currActions = [action] + await codeActions.doCodeAction(undefined, [CodeActionKind.QuickFix]) + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + }) + + it('should show disabled code action', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let refactorAction = CodeAction.create('code refactor', edit, CodeActionKind.Refactor) + refactorAction.disabled = { reason: 'invalid position' } + let fixAction = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + currActions = [refactorAction, fixAction] + let p = codeActions.doCodeAction(undefined) + let winid = await helper.waitFloat() + let win = nvim.createWindow(winid) + let buf = await win.buffer + let lines = await buf.lines + expect(lines.length).toBe(2) + expect(lines[1]).toMatch(/code refactor/) + await nvim.input('2') + await helper.wait(50) + await nvim.input('j') + await nvim.input('') + await helper.wait(50) + let valid = await win.valid + expect(valid).toBe(true) + let cmdline = await helper.getCmdline() + expect(cmdline).toMatch(/invalid position/) + await nvim.input('') + }) + + it('should action dialog to choose action', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + currActions = [action, CodeAction.create('foo')] + let promise = codeActions.doCodeAction(null) + await helper.wait(50) + let ids = await nvim.call('coc#float#get_float_win_list') as number[] + expect(ids.length).toBeGreaterThan(0) + await nvim.input('') + await promise + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + }) + + it('should choose code actions by range', async () => { + let range: Range + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: ( + _document: TextDocument, + r: Range, + _context: CodeActionContext, _token: CancellationToken + ) => { + range = r + return [CodeAction.create('my title'), CodeAction.create('b'), CodeAction.create('c')] + }, + }, undefined)) + await helper.createDocument() + await nvim.setLine('abc') + await nvim.command('normal! 0v$') + await nvim.input('') + await codeActions.doCodeAction('v', 'my title') + expect(range).toEqual({ start: { line: 0, character: 0 }, end: { line: 0, character: 3 } }) + }) + }) + + describe('doQuickfix', () => { + it('should throw when quickfix action does not exist', async () => { + let err + currActions = [] + await helper.createDocument() + try { + await codeActions.doQuickfix() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should do preferred quickfix action', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix) + action.isPreferred = true + currActions = [CodeAction.create('foo', CodeActionKind.QuickFix), action, CodeAction.create('bar')] + await codeActions.doQuickfix() + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + }) + }) + + describe('applyCodeAction', () => { + it('should resolve codeAction', async () => { + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', CodeActionKind.QuickFix) + action.isPreferred = true + currActions = [action] + resolvedAction = Object.assign({ edit }, action) + let arr = await codeActions.getCurrentCodeActions('line', [CodeActionKind.QuickFix]) + await codeActions.applyCodeAction(arr[0]) + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + }) + + it('should throw for disabled action', async () => { + let action: any = CodeAction.create('my action', CodeActionKind.Empty) + action.disabled = { reason: 'disabled', providerId: 'x' } + let err + try { + await codeActions.applyCodeAction(action) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should invoke registered command after apply edit', async () => { + let called + disposables.push(commands.registerCommand('test.execute', async (s: string) => { + called = s + await nvim.command(s) + })) + let doc = await helper.createDocument() + let edits: TextEdit[] = [] + edits.push(TextEdit.insert(Position.create(0, 0), 'bar')) + let edit = { changes: { [doc.uri]: edits } } + let action = CodeAction.create('code fix', CodeActionKind.QuickFix) + action.isPreferred = true + currActions = [action] + resolvedAction = Object.assign({ + edit, + command: Command.create('run vim command', 'test.execute', 'normal! $') + }, action) + let arr = await codeActions.getCurrentCodeActions('line', [CodeActionKind.QuickFix]) + await codeActions.applyCodeAction(arr[0]) + let lines = await doc.buffer.lines + expect(lines).toEqual(['bar']) + expect(called).toBe('normal! $') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/codelens.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/codelens.test.ts new file mode 100644 index 00000000..2d7066bd --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/codelens.test.ts @@ -0,0 +1,316 @@ +import { Neovim } from '@chemzqm/neovim' +import { Command, CodeLens, Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import commands from '../../commands' +import events from '../../events' +import CodeLensHandler from '../../handler/codelens/index' +import CodeLensBuffer, { getCommands } from '../../handler/codelens/buffer' +import languages from '../../languages' +import { disposeAll } from '../../util' +import helper from '../helper' +import workspace from '../../workspace' + +let nvim: Neovim +let codeLens: CodeLensHandler +let disposables: Disposable[] = [] +let srcId: number + +jest.setTimeout(10000) +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + srcId = await nvim.createNamespace('coc-codelens') + codeLens = helper.plugin.getHandler().codeLens +}) + +beforeEach(() => { + helper.updateConfiguration('codeLens.enable', true) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) +}) + +async function createBufferWithCodeLens(): Promise { + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(0, 0, 0, 1) + }] + }, + resolveCodeLens: codeLens => { + codeLens.command = Command.create('save', '__save', 1, 2, 3) + return codeLens + } + })) + let doc = await helper.createDocument('e.js') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + await codeLens.checkProvider() + return codeLens.buffers.getItem(doc.bufnr) +} + +describe('codeLenes featrue', () => { + it('should do codeLenes request and resolve codeLenes', async () => { + let buf = await createBufferWithCodeLens() + let doc = await workspace.document + let codelens = buf.currentCodeLens + expect(codelens).toBeDefined() + expect(codelens[0].command).toBeDefined() + let markers = await helper.getMarkers(doc.bufnr, srcId) + expect(markers.length).toBe(1) + }) + + it('should refresh on empty changes', async () => { + await createBufferWithCodeLens() + let doc = await workspace.document + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + let markers = await helper.getMarkers(doc.bufnr, srcId) + expect(markers.length).toBe(1) + }) + + it('should work with empty codeLens', async () => { + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: () => { + return [] + } + })) + let doc = await helper.createDocument('t.js') + let buf = codeLens.buffers.getItem(doc.bufnr) + let codelens = buf.currentCodeLens + expect(codelens).toBeUndefined() + }) + + it('should change codeLenes position', async () => { + let fn = jest.fn() + helper.updateConfiguration('codeLens.position', 'eol') + disposables.push(commands.registerCommand('__save', (...args) => { + fn(...args) + })) + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(0, 0, 0, 1) + }] + }, + resolveCodeLens: codeLens => { + codeLens.command = Command.create('save', '__save', 1, 2, 3) + return codeLens + } + })) + let doc = await helper.createDocument('example.js') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await codeLens.checkProvider() + let res = await doc.buffer.getExtMarks(srcId, 0, -1, { details: true }) + expect(res.length).toBeGreaterThan(0) + let arr = res[0][3]['virt_text'] + expect(arr[0][0]).toBe('save') + }) + + it('should refresh codeLens on CursorHold', async () => { + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: document => { + let n = document.lineCount + let arr: any[] = [] + for (let i = 0; i <= n - 2; i++) { + arr.push({ + range: Range.create(i, 0, i, 1), + command: Command.create('save', '__save', i) + }) + } + return arr + } + })) + let doc = await helper.createDocument('example.js') + await helper.wait(100) + let markers = await helper.getMarkers(doc.bufnr, srcId) + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + await events.fire('CursorHold', [doc.bufnr]) + await helper.wait(200) + markers = await helper.getMarkers(doc.bufnr, srcId) + expect(markers.length).toBe(3) + }) + + it('should cancel codeLenes request on document change', async () => { + let cancelled = false + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: (_, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + cancelled = true + clearTimeout(timer) + resolve(null) + }) + let timer = setTimeout(() => { + resolve([{ + range: Range.create(0, 0, 0, 1) + }, { + range: Range.create(1, 0, 1, 1) + }]) + }, 2000) + disposables.push({ + dispose: () => { + clearTimeout(timer) + } + }) + }) + }, + resolveCodeLens: codeLens => { + codeLens.command = Command.create('save', '__save') + return codeLens + } + })) + let doc = await helper.createDocument('codelens.js') + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'a\nb\nc')]) + expect(cancelled).toBe(true) + }) + + it('should resolve on CursorMoved', async () => { + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(90, 0, 90, 1) + }, { + range: Range.create(91, 0, 91, 1) + }] + }, + resolveCodeLens: async codeLens => { + codeLens.command = Command.create('save', '__save') + return codeLens + } + })) + let doc = await helper.createDocument('example.js') + let arr = new Array(100) + arr.fill('') + await nvim.call('setline', [1, arr]) + await doc.synchronize() + await codeLens.checkProvider() + await nvim.command('normal! gg') + await nvim.command('normal! G') + await helper.wait(100) + let buf = codeLens.buffers.getItem(doc.bufnr) + let codelens = buf.currentCodeLens + expect(codelens).toBeDefined() + expect(codelens[0].command).toBeDefined() + expect(codelens[1].command).toBeDefined() + }) + + it('should invoke codeLenes action', async () => { + let fn = jest.fn() + disposables.push(commands.registerCommand('__save', (...args) => { + fn(...args) + })) + await createBufferWithCodeLens() + await helper.doAction('codeLensAction') + expect(fn).toBeCalledWith(1, 2, 3) + await nvim.command('normal! G') + await helper.doAction('codeLensAction') + }) + + it('should use picker for multiple codeLenses', async () => { + let fn = jest.fn() + disposables.push(commands.registerCommand('__save', (...args) => { + fn(...args) + })) + disposables.push(commands.registerCommand('__delete', (...args) => { + fn(...args) + })) + disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(0, 0, 0, 1), + command: Command.create('save', '__save', 1, 2, 3) + }, { + range: Range.create(0, 1, 0, 2), + command: Command.create('save', '__delete', 4, 5, 6) + }] + } + })) + let doc = await helper.createDocument('example.js') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + await codeLens.checkProvider() + let p = helper.doAction('codeLensAction') + await helper.waitFloat() + await nvim.input('') + await p + expect(fn).toBeCalledWith(1, 2, 3) + }) + + it('should refresh for failed codeLens request', async () => { + let called = 0 + let fn = jest.fn() + disposables.push(commands.registerCommand('__save', (...args) => { + fn(...args) + })) + disposables.push(commands.registerCommand('__foo', (...args) => { + fn(...args) + })) + disposables.push(languages.registerCodeLensProvider([{ language: '*' }], { + provideCodeLenses: () => { + called++ + if (called == 1) { + return null + } + return [{ + range: Range.create(0, 0, 0, 1), + command: Command.create('foo', '__foo') + }] + } + })) + disposables.push(languages.registerCodeLensProvider([{ language: '*' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(0, 0, 0, 1), + command: Command.create('save', '__save') + }] + } + })) + let doc = await helper.createDocument('example.js') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await codeLens.checkProvider() + let markers = await helper.getMarkers(doc.buffer.id, srcId) + expect(markers.length).toBeGreaterThan(0) + let codeLensBuffer = codeLens.buffers.getItem(doc.buffer.id) + await codeLensBuffer.forceFetch() + let curr = codeLensBuffer.currentCodeLens + expect(curr.length).toBeGreaterThan(1) + }) + + it('should use custom separator & position', async () => { + helper.updateConfiguration('codeLens.separator', '|') + helper.updateConfiguration('codeLens.position', 'eol') + let doc = await helper.createDocument('example.js') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + disposables.push(languages.registerCodeLensProvider([{ language: '*' }], { + provideCodeLenses: () => { + return [{ + range: Range.create(0, 0, 1, 0), + command: Command.create('save', '__save') + }, { + range: Range.create(0, 0, 1, 0), + command: Command.create('save', '__save') + }] + } + })) + await codeLens.checkProvider() + let res = await doc.buffer.getExtMarks(srcId, 0, -1, { details: true }) + expect(res.length).toBe(1) + }) + + it('should get commands from codeLenses', async () => { + expect(getCommands(1, undefined)).toEqual([]) + let codeLenses = [CodeLens.create(Range.create(0, 0, 0, 0))] + expect(getCommands(0, codeLenses)).toEqual([]) + codeLenses = [CodeLens.create(Range.create(0, 0, 1, 0)), CodeLens.create(Range.create(2, 0, 3, 0))] + codeLenses[0].command = Command.create('save', '__save') + expect(getCommands(0, codeLenses).length).toEqual(1) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/colors.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/colors.test.ts new file mode 100644 index 00000000..6de644e2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/colors.test.ts @@ -0,0 +1,264 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, Color, ColorInformation, ColorPresentation, Disposable, Position, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import commands from '../../commands' +import { toHexString } from '../../util/color' +import Colors from '../../handler/colors/index' +import languages from '../../languages' +import { ProviderResult } from '../../provider' +import { disposeAll } from '../../util' +import path from 'path' +import helper from '../helper' + +let nvim: Neovim +let state = 'normal' +let colors: Colors +let disposables: Disposable[] = [] +let colorPresentations: ColorPresentation[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + await nvim.command(`source ${path.join(process.cwd(), 'autoload/coc/color.vim')}`) + colors = helper.plugin.getHandler().colors + disposables.push(languages.registerDocumentColorProvider([{ language: '*' }], { + provideColorPresentations: ( + _color: Color, + _context: { document: TextDocument; range: Range }, + _token: CancellationToken + ): ColorPresentation[] => colorPresentations, + provideDocumentColors: ( + document: TextDocument, + _token: CancellationToken + ): ProviderResult => { + if (state == 'empty') return [] + if (state == 'error') return Promise.reject(new Error('no color')) + let matches = Array.from((document.getText() as any).matchAll(/#\w{6}/g)) as any + return matches.map(o => { + let start = document.positionAt(o.index) + let end = document.positionAt(o.index + o[0].length) + return { + range: Range.create(start, end), + color: getColor(255, 255, 255) + } + }) + } + })) +}) + +beforeEach(() => { + helper.updateConfiguration('colors.filetypes', ['*']) +}) + +afterAll(async () => { + disposeAll(disposables) + await helper.shutdown() +}) + +afterEach(async () => { + colorPresentations = [] + await helper.reset() +}) + +function getColor(r: number, g: number, b: number): Color { + return { red: r / 255, green: g / 255, blue: b / 255, alpha: 1 } +} + +describe('Colors', () => { + describe('utils', () => { + it('should get hex string', () => { + let color = getColor(255, 255, 255) + let hex = toHexString(color) + expect(hex).toBe('ffffff') + }) + }) + + describe('configuration', () => { + it('should toggle enable state on configuration change', async () => { + let doc = await helper.createDocument() + helper.updateConfiguration('colors.filetypes', []) + let enabled = colors.isEnabled(doc.bufnr) + helper.updateConfiguration('colors.filetypes', ['*']) + expect(enabled).toBe(false) + }) + }) + + describe('commands', () => { + it('should register editor.action.pickColor command', async () => { + await helper.mockFunction('coc#color#pick_color', [0, 0, 0]) + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + await commands.executeCommand('editor.action.pickColor') + let line = await nvim.getLine() + expect(line).toBe('#000000') + }) + + it('should register editor.action.colorPresentation command', async () => { + colorPresentations = [ColorPresentation.create('red'), ColorPresentation.create('#ff0000')] + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + let p = commands.executeCommand('editor.action.colorPresentation') + await helper.wait(100) + await nvim.input('1') + await p + let line = await nvim.getLine() + expect(line).toBe('red') + }) + }) + + describe('doHighlight', () => { + it('should clearHighlight on empty result', async () => { + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + state = 'empty' + await colors.doHighlight(doc.bufnr) + let res = colors.hasColor(doc.bufnr) + expect(res).toBe(false) + state = 'normal' + }) + + it('should not highlight on error result', async () => { + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + state = 'error' + let err + try { + await colors.doHighlight(doc.bufnr) + } catch (e) { + err = e + } + expect(err).toBeDefined() + state = 'normal' + }) + + it('should highlight after document changed', async () => { + let doc = await helper.createDocument() + doc.forceSync() + await colors.doHighlight(doc.bufnr) + expect(colors.hasColor(doc.bufnr)).toBe(false) + expect(colors.hasColorAtPosition(doc.bufnr, Position.create(0, 1))).toBe(false) + await nvim.setLine('#ffffff #ff0000') + await doc.synchronize() + await helper.wait(100) + expect(colors.hasColorAtPosition(doc.bufnr, Position.create(0, 1))).toBe(true) + expect(colors.hasColor(doc.bufnr)).toBe(true) + }) + + it('should clearHighlight on clearHighlight', async () => { + let doc = await helper.createDocument() + await nvim.setLine('#ffffff #ff0000') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + expect(colors.hasColor(doc.bufnr)).toBe(true) + colors.clearHighlight(doc.bufnr) + expect(colors.hasColor(doc.bufnr)).toBe(false) + }) + + it('should highlight colors', async () => { + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + await colors.doHighlight(doc.bufnr) + let exists = await nvim.call('hlexists', 'BGffffff') + expect(exists).toBe(1) + }) + }) + + describe('hasColor()', () => { + it('should return false when bufnr does not exist', async () => { + let res = colors.hasColor(99) + colors.clearHighlight(99) + expect(res).toBe(false) + }) + }) + + describe('getColorInformation()', () => { + it('should return null when highlighter does not exist', async () => { + let res = await colors.getColorInformation(99) + expect(res).toBe(null) + }) + + it('should return null when color not found', async () => { + let doc = await helper.createDocument() + await nvim.setLine('#ffffff foo ') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + await nvim.call('cursor', [1, 12]) + let res = await colors.getColorInformation(doc.bufnr) + expect(res).toBe(null) + }) + }) + + describe('hasColorAtPosition()', () => { + it('should return false when bufnr does not exist', async () => { + let res = colors.hasColorAtPosition(99, Position.create(0, 0)) + expect(res).toBe(false) + }) + }) + + describe('pickPresentation()', () => { + it('should show warning when color does not exist', async () => { + await helper.createDocument() + await colors.pickPresentation() + let msg = await helper.getCmdline() + expect(msg).toMatch('Color not found') + }) + + it('should not throw when presentations do not exist', async () => { + colorPresentations = [] + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(99) + await colors.doHighlight(doc.bufnr) + await helper.doAction('colorPresentation') + }) + + it('should pick presentations', async () => { + colorPresentations = [ColorPresentation.create('red'), ColorPresentation.create('#ff0000')] + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + let p = helper.doAction('colorPresentation') + await helper.wait(100) + await nvim.input('1') + await p + let line = await nvim.getLine() + expect(line).toBe('red') + }) + }) + + describe('pickColor()', () => { + it('should show warning when color does not exist', async () => { + await helper.createDocument() + await colors.pickColor() + let msg = await helper.getCmdline() + expect(msg).toMatch('not found') + }) + + it('should pickColor', async () => { + await helper.mockFunction('coc#color#pick_color', [0, 0, 0]) + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + await helper.doAction('pickColor') + let line = await nvim.getLine() + expect(line).toBe('#000000') + }) + + it('should not throw when pick color return 0', async () => { + await helper.mockFunction('coc#color#pick_color', 0) + let doc = await helper.createDocument() + await nvim.setLine('#ffffff') + doc.forceSync() + await colors.doHighlight(doc.bufnr) + await helper.doAction('pickColor') + let line = await nvim.getLine() + expect(line).toBe('#ffffff') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/commands.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/commands.test.ts new file mode 100644 index 00000000..f9026edf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/commands.test.ts @@ -0,0 +1,82 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import CommandsHandler from '../../handler/commands' +import commandManager from '../../commands' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let commands: CommandsHandler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + commands = (helper.plugin as any).handler.commands +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('Commands', () => { + describe('addVimCommand', () => { + it('should register global vim commands', async () => { + await commandManager.executeCommand('vim.config') + await helper.wait(50) + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch('coc-settings.json') + let list = commands.getCommandList() + expect(list.includes('vim.config')).toBe(true) + }) + + it('should add vim command with title', async () => { + commands.addVimCommand({ id: 'list', cmd: 'CocList', title: 'list of coc.nvim' }) + let res = commandManager.titles.get('vim.list') + expect(res).toBe('list of coc.nvim') + commandManager.unregister('vim.list') + }) + }) + + describe('getCommands', () => { + it('should get command items', async () => { + let res = commands.getCommands() + let idx = res.findIndex(o => o.id == 'workspace.showOutput') + expect(idx != -1).toBe(true) + }) + }) + + describe('repeat', () => { + it('should repeat command', async () => { + // let buf = await nvim.buffer + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await nvim.call('cursor', [1, 1]) + commands.addVimCommand({ id: 'remove', cmd: 'normal! dd' }) + await commands.runCommand('vim.remove') + await helper.wait(50) + let res = await nvim.call('getline', [1, '$']) + expect(res).toEqual(['b', 'c']) + await commands.repeat() + await helper.wait(50) + res = await nvim.call('getline', [1, '$']) + expect(res).toEqual(['c']) + }) + }) + + describe('runCommand', () => { + it('should open command list without id', async () => { + await commands.runCommand() + await helper.wait(100) + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toBe('list:///commands') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/fold.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/fold.test.ts new file mode 100644 index 00000000..95fd524b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/fold.test.ts @@ -0,0 +1,77 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, FoldingRange, Range } from 'vscode-languageserver-protocol' +import FoldHandler from '../../handler/fold' +import languages from '../../languages' +import workspace from '../../workspace' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let folds: FoldHandler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + folds = (helper.plugin as any).handler.fold +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('Folds', () => { + it('should return null when provider does not exist', async () => { + let doc = await workspace.document + let token = (new CancellationTokenSource()).token + expect(await languages.provideFoldingRanges(doc.textDocument, {}, token)).toBe(null) + }) + + it('should return false when no fold ranges found', async () => { + disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], { + provideFoldingRanges(_doc) { + return [] + } + })) + let res = await folds.fold() + expect(res).toBe(false) + }) + + it('should fold all fold ranges', async () => { + disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], { + provideFoldingRanges(_doc) { + return [FoldingRange.create(1, 3), FoldingRange.create(4, 6, 0, 0, 'comment')] + } + })) + await nvim.call('setline', [1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']]) + let res = await folds.fold() + expect(res).toBe(true) + let closed = await nvim.call('foldclosed', [2]) + expect(closed).toBe(2) + closed = await nvim.call('foldclosed', [5]) + expect(closed).toBe(5) + }) + + it('should fold comment ranges', async () => { + disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], { + provideFoldingRanges(_doc) { + return [FoldingRange.create(1, 3), FoldingRange.create(4, 6, 0, 0, 'comment')] + } + })) + await nvim.call('setline', [1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']]) + let res = await folds.fold('comment') + expect(res).toBe(true) + let closed = await nvim.call('foldclosed', [2]) + expect(closed).toBe(-1) + closed = await nvim.call('foldclosed', [5]) + expect(closed).toBe(5) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/format.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/format.test.ts new file mode 100644 index 00000000..e0374111 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/format.test.ts @@ -0,0 +1,252 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import Format from '../../handler/format' +import languages from '../../languages' +import { disposeAll } from '../../util' +import window from '../../window' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let format: Format + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + format = helper.plugin.getHandler().format +}) + +beforeEach(() => { + helper.updateConfiguration('coc.preferences.formatOnType', true) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) +}) + +describe('format handler', () => { + describe('documentFormat', () => { + it('should throw when provider not found', async () => { + let doc = await helper.createDocument() + let err + try { + await format.documentFormat(doc) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should return false when get empty edits ', async () => { + disposables.push(languages.registerDocumentFormatProvider(['*'], { + provideDocumentFormattingEdits: () => { + return [] + } + })) + let doc = await helper.createDocument() + let res = await format.documentFormat(doc) + expect(res).toBe(false) + }) + }) + + describe('formatOnSave', () => { + it('should not throw when provider not found', async () => { + helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['javascript']) + let filepath = await createTmpFile('') + await helper.edit(filepath) + await nvim.command('setf javascript') + await nvim.setLine('foo') + await nvim.command('silent w') + await helper.wait(100) + }) + + it('should invoke format on save', async () => { + helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['text']) + disposables.push(languages.registerDocumentFormatProvider(['text'], { + provideDocumentFormattingEdits: document => { + let lines = document.getText().replace(/\n$/, '').split(/\n/) + let edits: TextEdit[] = [] + for (let i = 0; i < lines.length; i++) { + let text = lines[i] + if (!text.startsWith(' ')) { + edits.push(TextEdit.insert(Position.create(i, 0), ' ')) + } + } + return edits + } + })) + let filepath = await createTmpFile('a\nb\nc\n') + let buf = await helper.edit(filepath) + await nvim.command('setf text') + await nvim.command('w') + let lines = await buf.lines + expect(lines).toEqual([' a', ' b', ' c']) + }) + + it('should cancel when timeout', async () => { + helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['*']) + disposables.push(languages.registerDocumentFormatProvider(['*'], { + provideDocumentFormattingEdits: () => { + return new Promise(resolve => { + setTimeout(() => { + resolve(undefined) + }, 2000) + }) + } + })) + let filepath = await createTmpFile('a\nb\nc\n') + await helper.edit(filepath) + let n = Date.now() + await nvim.command('w') + expect(Date.now() - n).toBeLessThan(1000) + }) + }) + + describe('rangeFormat', () => { + it('should return null when provider does not exist', async () => { + let doc = (await workspace.document).textDocument + let range = Range.create(0, 0, 1, 0) + let options = await workspace.getFormatOptions() + let token = (new CancellationTokenSource()).token + expect(await languages.provideDocumentRangeFormattingEdits(doc, range, options, token)).toBe(null) + expect(languages.hasProvider('onTypeEdit', doc)).toBe(false) + let edits = await languages.provideDocumentFormattingEdits(doc, options, token) + expect(edits).toBe(null) + }) + + it('should invoke range format', async () => { + disposables.push(languages.registerDocumentRangeFormatProvider(['text'], { + provideDocumentRangeFormattingEdits: (_document, range) => { + let lines: number[] = [] + for (let i = range.start.line; i <= range.end.line; i++) { + lines.push(i) + } + return lines.map(i => { + return TextEdit.insert(Position.create(i, 0), ' ') + }) + } + })) + let doc = await helper.createDocument() + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await nvim.command('setf text') + await nvim.command('normal! ggvG') + await nvim.input('') + expect(languages.hasFormatProvider(doc.textDocument)).toBe(true) + expect(languages.hasProvider('format', doc.textDocument)).toBe(true) + await helper.doAction('formatSelected', 'v') + let buf = nvim.createBuffer(doc.bufnr) + let lines = await buf.lines + expect(lines).toEqual([' a', ' b', ' c']) + let options = await workspace.getFormatOptions(doc.uri) + let token = (new CancellationTokenSource()).token + let edits = await languages.provideDocumentFormattingEdits(doc.textDocument, options, token) + expect(edits.length).toBeGreaterThan(0) + }) + + it('should format range by formatexpr option', async () => { + let range: Range + disposables.push(languages.registerDocumentRangeFormatProvider(['text'], { + provideDocumentRangeFormattingEdits: (_document, r) => { + range = r + return [] + } + })) + await helper.createDocument() + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await nvim.command('setf text') + await nvim.command(`setl formatexpr=CocAction('formatSelected')`) + await nvim.command('normal! ggvGgq') + expect(range).toEqual({ + start: { line: 0, character: 0 }, end: { line: 3, character: 0 } + }) + }) + }) + + describe('formatOnType', () => { + it('should invoke format', async () => { + disposables.push(languages.registerDocumentFormatProvider(['text'], { + provideDocumentFormattingEdits: () => { + return [TextEdit.insert(Position.create(0, 0), ' ')] + } + })) + await helper.createDocument() + await nvim.setLine('foo') + await nvim.command('setf text') + await helper.doAction('format') + let line = await nvim.line + expect(line).toEqual(' foo') + }) + + it('should does format on type', async () => { + disposables.push(languages.registerOnTypeFormattingEditProvider(['text'], { + provideOnTypeFormattingEdits: () => { + return [TextEdit.insert(Position.create(0, 0), ' ')] + } + }, ['|'])) + await helper.edit() + await nvim.command('setf text') + await nvim.input('i|') + await helper.wait(200) + let line = await nvim.line + expect(line).toBe(' |') + let cursor = await window.getCursorPosition() + expect(cursor).toEqual({ line: 0, character: 3 }) + }) + + it('should adjust cursor after format on type', async () => { + disposables.push(languages.registerOnTypeFormattingEditProvider(['text'], { + provideOnTypeFormattingEdits: () => { + return [ + TextEdit.insert(Position.create(0, 0), ' '), + TextEdit.insert(Position.create(0, 2), 'end') + ] + } + }, ['|'])) + await helper.edit() + await nvim.command('setf text') + await nvim.setLine('"') + await nvim.input('i|') + await helper.wait(100) + let line = await nvim.line + expect(line).toBe(' |"end') + let cursor = await window.getCursorPosition() + expect(cursor).toEqual({ line: 0, character: 3 }) + }) + }) + + describe('bracketEnterImprove', () => { + afterEach(() => { + nvim.command('iunmap ', true) + }) + + it('should format vim file on enter', async () => { + let buf = await helper.edit('foo.vim') + await nvim.command(`inoremap pumvisible() ? coc#_select_confirm() : "\\u\\\\=coc#on_enter()\\"`) + await nvim.setLine('let foo={}') + await nvim.command(`normal! gg$`) + await nvim.input('i') + await nvim.eval(`feedkeys("\\", 'im')`) + await helper.wait(100) + let lines = await buf.lines + expect(lines).toEqual(['let foo={', ' \\ ', ' \\ }']) + }) + + it('should add new line between bracket', async () => { + let buf = await helper.edit() + await nvim.command(`inoremap pumvisible() ? coc#_select_confirm() : "\\u\\\\=coc#on_enter()\\"`) + await nvim.setLine(' {}') + await nvim.command(`normal! gg$`) + await nvim.input('i') + await nvim.eval(`feedkeys("\\", 'im')`) + await helper.wait(100) + let lines = await buf.lines + expect(lines).toEqual([' {', ' ', ' }']) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/highlights.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/highlights.test.ts new file mode 100644 index 00000000..5ecb90ef --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/highlights.test.ts @@ -0,0 +1,140 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, DocumentHighlightKind, Position, Range } from 'vscode-languageserver-protocol' +import Highlights from '../../handler/highlights' +import languages from '../../languages' +import workspace from '../../workspace' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let highlights: Highlights + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + highlights = helper.plugin.getHandler().documentHighlighter +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +function registProvider(): void { + disposables.push(languages.registerDocumentHighlightProvider([{ language: '*' }], { + provideDocumentHighlights: async document => { + let word = await nvim.eval('expand("")') + // let word = document.get + let matches = Array.from((document.getText() as any).matchAll(/\w+/g)) as any[] + let filtered = matches.filter(o => o[0] == word) + return filtered.map((o, i) => { + let start = document.positionAt(o.index) + let end = document.positionAt(o.index + o[0].length) + return { + range: Range.create(start, end), + kind: i % 2 == 0 ? DocumentHighlightKind.Read : DocumentHighlightKind.Write + } + }) + } + })) +} + +describe('document highlights', () => { + + function registerTimerProvider(fn: Function, timeout: number): void { + disposables.push(languages.registerDocumentHighlightProvider([{ language: '*' }], { + provideDocumentHighlights: (_document, _position, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timer) + fn() + resolve([]) + }) + let timer = setTimeout(() => { + resolve([{ range: Range.create(0, 0, 0, 3) }]) + }, timeout) + }) + } + })) + } + + it('should return null when highlights provide does not exist', async () => { + let doc = await helper.createDocument() + let res = await highlights.getHighlights(doc, Position.create(0, 0)) + expect(res).toBeNull() + }) + + it('should cancel request on CursorMoved', async () => { + let fn = jest.fn() + registerTimerProvider(fn, 3000) + await helper.edit() + await nvim.setLine('foo') + let p = highlights.highlight() + await helper.wait(50) + await nvim.call('cursor', [1, 2]) + await p + expect(fn).toBeCalled() + }) + + it('should cancel on timeout', async () => { + helper.updateConfiguration('documentHighlight.timeout', 10) + let fn = jest.fn() + registerTimerProvider(fn, 3000) + await helper.edit() + await nvim.setLine('foo') + await highlights.highlight() + expect(fn).toBeCalled() + }) + + it('should add highlights to symbols', async () => { + registProvider() + await helper.createDocument() + await nvim.setLine('foo bar foo') + await helper.doAction('highlight') + let winid = await nvim.call('win_getid') as number + expect(highlights.hasHighlights(winid)).toBe(true) + }) + + it('should return highlight ranges', async () => { + registProvider() + await helper.createDocument() + await nvim.setLine('foo bar foo') + let res = await helper.doAction('symbolRanges') + expect(res.length).toBe(2) + }) + + it('should return null when cursor not in word range', async () => { + disposables.push(languages.registerDocumentHighlightProvider([{ language: '*' }], { + provideDocumentHighlights: () => { + return [{ range: Range.create(0, 0, 0, 3) }] + } + })) + let doc = await helper.createDocument() + await nvim.setLine(' oo') + await nvim.call('cursor', [1, 2]) + let res = await highlights.getHighlights(doc, Position.create(0, 0)) + expect(res).toBeNull() + }) + + it('should not throw when document is command line', async () => { + await nvim.call('feedkeys', ['q:', 'in']) + let doc = await workspace.document + expect(doc.isCommandLine).toBe(true) + await highlights.highlight() + await nvim.input('') + }) + + it('should not throw when provider not found', async () => { + disposeAll(disposables) + await helper.createDocument() + await nvim.setLine(' oo') + await nvim.call('cursor', [1, 2]) + await highlights.highlight() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/hover.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/hover.test.ts new file mode 100644 index 00000000..545d2a20 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/hover.test.ts @@ -0,0 +1,178 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, MarkedString, Hover, Range, TextEdit, Position } from 'vscode-languageserver-protocol' +import HoverHandler from '../../handler/hover' +import { URI } from 'vscode-uri' +import languages from '../../languages' +import { disposeAll } from '../../util' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let hover: HoverHandler +let disposables: Disposable[] = [] +let hoverResult: Hover +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + hover = helper.plugin.getHandler().hover +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() + disposables.push(languages.registerHoverProvider([{ language: '*' }], { + provideHover: (_doc, _pos, _token) => { + return hoverResult + } + })) +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +async function getDocumentText(): Promise { + let lines = await nvim.call('getbufline', ['coc://document', 1, '$']) as string[] + return lines.join('\n') +} + +describe('Hover', () => { + describe('onHover', () => { + it('should return false when hover not found', async () => { + hoverResult = null + let res = await hover.onHover('preview') + expect(res).toBe(false) + }) + + it('should show MarkupContent hover', async () => { + hoverResult = { contents: { kind: 'plaintext', value: 'my hover' } } + await hover.onHover('preview') + let res = await getDocumentText() + expect(res).toMatch('my hover') + }) + + it('should show MarkedString hover', async () => { + hoverResult = { contents: 'string hover' } + disposables.push(languages.registerHoverProvider([{ language: '*' }], { + provideHover: (_doc, _pos, _token) => { + return { contents: { language: 'typescript', value: 'language hover' } } + } + })) + await hover.onHover('preview') + let res = await getDocumentText() + expect(res).toMatch('string hover') + expect(res).toMatch('language hover') + }) + + it('should show MarkedString hover array', async () => { + hoverResult = { contents: ['foo', { language: 'typescript', value: 'bar' }] } + await hover.onHover('preview') + let res = await getDocumentText() + expect(res).toMatch('foo') + expect(res).toMatch('bar') + }) + + it('should highlight hover range', async () => { + await nvim.setLine('var') + await nvim.command('normal! 0') + hoverResult = { contents: ['foo'], range: Range.create(0, 0, 0, 3) } + await hover.onHover('preview') + let res = await nvim.call('getmatches') as any[] + expect(res.length).toBe(1) + expect(res[0].group).toBe('CocHoverRange') + await helper.wait(600) + res = await nvim.call('getmatches') + expect(res.length).toBe(0) + }) + }) + + describe('previewHover', () => { + it('should echo hover message', async () => { + hoverResult = { contents: ['foo'] } + let res = await hover.onHover('echo') + expect(res).toBe(true) + let msg = await helper.getCmdline() + expect(msg).toMatch('foo') + }) + + it('should show hover in float window', async () => { + hoverResult = { contents: { kind: 'markdown', value: '```typescript\nconst foo:number\n```' } } + await hover.onHover('float') + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await nvim.eval(`getbufline(winbufnr(${win.id}),1,'$')`) + expect(lines).toEqual(['const foo:number']) + }) + }) + + describe('getHover', () => { + it('should get hover from MarkedString array', async () => { + hoverResult = { contents: ['foo', { language: 'typescript', value: 'bar' }] } + disposables.push(languages.registerHoverProvider([{ language: '*' }], { + provideHover: (_doc, _pos, _token) => { + return { contents: { language: 'typescript', value: 'MarkupContent hover' } } + } + })) + disposables.push(languages.registerHoverProvider([{ language: '*' }], { + provideHover: (_doc, _pos, _token) => { + return { contents: MarkedString.fromPlainText('MarkedString hover') } + } + })) + let res = await hover.getHover() + expect(res.includes('foo')).toBe(true) + expect(res.includes('bar')).toBe(true) + expect(res.includes('MarkupContent hover')).toBe(true) + expect(res.includes('MarkedString hover')).toBe(true) + }) + + it('should filter empty hover message', async () => { + hoverResult = { contents: [''] } + let res = await hover.getHover() + expect(res.length).toBe(0) + }) + }) + + describe('definitionHover', () => { + it('should load definition from buffer', async () => { + hoverResult = { contents: 'string hover' } + let doc = await helper.createDocument() + await nvim.call('cursor', [1, 1]) + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar')]) + disposables.push(languages.registerDefinitionProvider([{ language: '*' }], { + provideDefinition() { + return [{ + targetUri: doc.uri, + targetRange: Range.create(0, 0, 1, 3), + targetSelectionRange: Range.create(0, 0, 0, 3), + }] + } + })) + await hover.definitionHover('preview') + let res = await getDocumentText() + expect(res).toBe('string hover\n\nfoo\nbar') + }) + + it('should load definition link from file', async () => { + let fsPath = await createTmpFile('foo\nbar\n') + hoverResult = { contents: 'string hover' } + let doc = await helper.createDocument() + await nvim.call('cursor', [1, 1]) + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar')]) + disposables.push(languages.registerDefinitionProvider([{ language: '*' }], { + provideDefinition() { + return [{ + targetUri: URI.file(fsPath).toString(), + targetRange: Range.create(0, 0, 1, 3), + targetSelectionRange: Range.create(0, 0, 0, 3), + }] + } + })) + await hover.definitionHover('preview') + let res = await getDocumentText() + expect(res).toBe('string hover\n\nfoo\nbar') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/index.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/index.test.ts new file mode 100644 index 00000000..a66ddc46 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/index.test.ts @@ -0,0 +1,93 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import Handler from '../../handler/index' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let handler: Handler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + handler = (helper.plugin as any).handler +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('Handler', () => { + describe('hasProvider', () => { + it('should check provider for document', async () => { + let res = await handler.hasProvider('definition') + expect(res).toBe(false) + }) + }) + + describe('checkProvier', () => { + it('should throw error when provider not found', async () => { + let doc = await helper.createDocument() + let err + try { + handler.checkProvier('definition', doc.textDocument) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + }) + + describe('withRequestToken', () => { + it('should cancel previous request when called again', async () => { + let cancelled = false + let p = handler.withRequestToken('test', token => { + return new Promise(s => { + token.onCancellationRequested(() => { + cancelled = true + clearTimeout(timer) + s(undefined) + }) + let timer = setTimeout(() => { + s(undefined) + }, 3000) + }) + }, false) + setTimeout(async () => { + await handler.withRequestToken('test', () => { + return Promise.resolve(undefined) + }, false) + }, 50) + await p + expect(cancelled).toBe(true) + }) + + it('should cancel request on insert start', async () => { + let cancelled = false + let p = handler.withRequestToken('test', token => { + return new Promise(s => { + token.onCancellationRequested(() => { + cancelled = true + clearTimeout(timer) + s(undefined) + }) + let timer = setTimeout(() => { + s(undefined) + }, 3000) + }) + }, false) + await nvim.input('i') + await p + expect(cancelled).toBe(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/inlayHint.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/inlayHint.test.ts new file mode 100644 index 00000000..a5c7947d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/inlayHint.test.ts @@ -0,0 +1,233 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Position, Range } from 'vscode-languageserver-protocol' +import InlayHintHandler from '../../handler/inlayHint/index' +import { InlayHint } from '../../inlayHint' +import languages from '../../languages' +import { isValidInlayHint, sameHint } from '../../provider/inlayHintManager' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +let handler: InlayHintHandler +let disposables: Disposable[] = [] +let ns: number +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + handler = helper.plugin.getHandler().inlayHintHandler + ns = await nvim.createNamespace('coc-inlayHint') +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('InlayHint', () => { + describe('utils', () => { + it('should check same hint', () => { + let hint = InlayHint.create(Position.create(0, 0), 'foo') + expect(sameHint(hint, InlayHint.create(Position.create(0, 0), 'bar'))).toBe(false) + expect(sameHint(hint, InlayHint.create(Position.create(0, 0), [{ value: 'foo' }]))).toBe(true) + }) + + it('should check valid hint', () => { + let hint = InlayHint.create(Position.create(0, 0), 'foo') + expect(isValidInlayHint(hint, Range.create(0, 0, 1, 0))).toBe(true) + expect(isValidInlayHint(InlayHint.create(Position.create(0, 0), ''), Range.create(0, 0, 1, 0))).toBe(false) + expect(isValidInlayHint(InlayHint.create(Position.create(3, 0), 'foo'), Range.create(0, 0, 1, 0))).toBe(false) + expect(isValidInlayHint({ label: 'f' } as any, Range.create(0, 0, 1, 0))).toBe(false) + }) + }) + + describe('provideInlayHints', () => { + it('should not throw when failed', async () => { + disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: () => { + return Promise.reject(new Error('Test failure')) + } + })) + let doc = await workspace.document + let tokenSource = new CancellationTokenSource() + let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token) + expect(res).toEqual([]) + }) + + it('should merge provide results', async () => { + disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: () => { + return [InlayHint.create(Position.create(0, 0), 'foo')] + } + })) + disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: () => { + return [ + InlayHint.create(Position.create(0, 0), 'foo'), + InlayHint.create(Position.create(1, 0), 'bar'), + InlayHint.create(Position.create(5, 0), 'bad')] + } + })) + let doc = await workspace.document + let tokenSource = new CancellationTokenSource() + let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 3, 0), tokenSource.token) + expect(res.length).toBe(2) + }) + + it('should resolve inlay hint', async () => { + disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: () => { + return [InlayHint.create(Position.create(0, 0), 'foo')] + }, + resolveInlayHint: hint => { + hint.tooltip = 'tooltip' + return hint + } + })) + let doc = await workspace.document + let tokenSource = new CancellationTokenSource() + let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token) + let resolved = await languages.resolveInlayHint(res[0], tokenSource.token) + expect(resolved.tooltip).toBe('tooltip') + resolved = await languages.resolveInlayHint(resolved, tokenSource.token) + expect(resolved.tooltip).toBe('tooltip') + }) + + it('should not resolve when cancelled', async () => { + disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: () => { + return [InlayHint.create(Position.create(0, 0), 'foo')] + }, + resolveInlayHint: (hint, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timer) + resolve(null) + }) + let timer = setTimeout(() => { + resolve(Object.assign({}, hint, { tooltip: 'tooltip' })) + }, 200) + }) + } + })) + let doc = await workspace.document + let tokenSource = new CancellationTokenSource() + let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token) + let p = languages.resolveInlayHint(res[0], tokenSource.token) + tokenSource.cancel() + let resolved = await p + expect(resolved.tooltip).toBeUndefined() + }) + }) + + describe('setVirtualText', () => { + async function registerProvider(content: string): Promise { + let doc = await workspace.document + let disposable = languages.registerInlayHintsProvider([{ language: '*' }], { + provideInlayHints: (document, range) => { + let content = document.getText(range) + let lines = content.split(/\r?\n/) + let hints: InlayHint[] = [] + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (!line.length) continue + let parts = line.split(/\s+/) + hints.push(...parts.map(s => InlayHint.create(Position.create(range.start.line + i, line.length), s))) + } + return hints + } + }) + await doc.buffer.setLines(content.split(/\n/), { start: 0, end: -1 }) + await doc.synchronize() + return disposable + } + + async function waitRefresh(bufnr: number) { + let buf = handler.getItem(bufnr) + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + reject(new Error('not refresh after 1s')) + }, 1000) + buf.onDidRefresh(() => { + clearTimeout(timer) + resolve() + }) + }) + } + + it('should not refresh when languageId not match', async () => { + let doc = await workspace.document + disposables.push(languages.registerInlayHintsProvider([{ language: 'javascript' }], { + provideInlayHints: () => { + let hint = InlayHint.create(Position.create(0, 0), 'foo') + return [hint] + } + })) + await nvim.setLine('foo') + await doc.synchronize() + await helper.wait(30) + let markers = await doc.buffer.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBe(0) + }) + + it('should refresh on text change', async () => { + let buf = await nvim.buffer + let disposable = await registerProvider('foo') + disposables.push(disposable) + await waitRefresh(buf.id) + await buf.setLines(['a', 'b', 'c'], { start: 0, end: -1 }) + await waitRefresh(buf.id) + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBe(3) + let item = handler.getItem(buf.id) + await item.renderRange() + expect(item.current.length).toBe(3) + }) + + it('should refresh on provider dispose', async () => { + let buf = await nvim.buffer + let disposable = await registerProvider('foo bar') + await waitRefresh(buf.id) + disposable.dispose() + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBe(0) + let item = handler.getItem(buf.id) + expect(item.current.length).toBe(0) + await item.renderRange() + expect(item.current.length).toBe(0) + }) + + it('should refresh on scroll', async () => { + let arr = new Array(200) + let content = arr.fill('foo').join('\n') + let buf = await nvim.buffer + let disposable = await registerProvider(content) + disposables.push(disposable) + await waitRefresh(buf.id) + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + let len = markers.length + await nvim.command('normal! G') + await waitRefresh(buf.id) + await nvim.input('') + await waitRefresh(buf.id) + markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBeGreaterThan(len) + }) + + it('should cancel previous render', async () => { + let buf = await nvim.buffer + let disposable = await registerProvider('foo') + disposables.push(disposable) + await waitRefresh(buf.id) + let item = handler.getItem(buf.id) + await item.renderRange() + await item.renderRange() + expect(item.current.length).toBe(1) + }) + }) +}) + diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/linkedEditing.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/linkedEditing.test.ts new file mode 100644 index 00000000..b1f53399 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/linkedEditing.test.ts @@ -0,0 +1,157 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Range, Position } from 'vscode-languageserver-protocol' +import LinkedEditingHandler from '../../handler/linkedEditing' +import languages from '../../languages' +import workspace from '../../workspace' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let handler: LinkedEditingHandler +let disposables: Disposable[] = [] +let wordPattern: string | undefined +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + handler = helper.plugin.getHandler().linkedEditingHandler +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + helper.updateConfiguration('coc.preferences.enableLinkedEditing', true) +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +async function registerProvider(content: string, position: Position): Promise { + let doc = await workspace.document + disposables.push(languages.registerLinkedEditingRangeProvider([{ language: '*' }], { + provideLinkedEditingRanges: (doc, pos) => { + let document = workspace.getDocument(doc.uri) + let range = document.getWordRangeAtPosition(pos) + if (!range) return null + let text = doc.getText(range) + let ranges: Range[] = document.getSymbolRanges(text) + return { ranges, wordPattern } + } + })) + await nvim.setLine(content) + await doc.synchronize() + await handler.enable(doc, position) +} + +async function assertMatches(len: number): Promise { + let res = await nvim.call('getmatches') as any[] + res = res.filter(o => o.group === 'CocLinkedEditing') + expect(res.length).toBe(len) +} + +describe('LinkedEditing', () => { + it('should active and cancel on cursor moved', async () => { + await registerProvider('foo foo a ', Position.create(0, 0)) + await assertMatches(2) + await nvim.command(`normal! $`) + await helper.wait(50) + await assertMatches(0) + }) + + it('should active when moved to another word', async () => { + await registerProvider('foo foo bar bar bar', Position.create(0, 0)) + await nvim.call('cursor', [1, 9]) + await helper.wait(50) + await assertMatches(3) + }) + + it('should active on text change', async () => { + let doc = await workspace.document + await registerProvider('foo foo a ', Position.create(0, 0)) + await assertMatches(2) + await nvim.call('cursor', [1, 1]) + await nvim.call('nvim_buf_set_text', [doc.bufnr, 0, 0, 0, 0, ['i']]) + await doc.synchronize() + let line = await nvim.line + expect(line).toBe('ifoo ifoo a ') + await nvim.call('nvim_buf_set_text', [doc.bufnr, 0, 0, 0, 1, []]) + await doc.synchronize() + line = await nvim.line + expect(line).toBe('foo foo a ') + }) + + it('should cancel when change out of range', async () => { + let doc = await workspace.document + await registerProvider('foo foo bar', Position.create(0, 0)) + await assertMatches(2) + await nvim.call('nvim_buf_set_text', [doc.bufnr, 0, 9, 0, 10, ['']]) + await doc.synchronize() + await assertMatches(0) + }) + + it('should cancel on editor change', async () => { + await registerProvider('foo foo a ', Position.create(0, 0)) + await nvim.command(`enew`) + await helper.wait(50) + await assertMatches(0) + }) + + it('should cancel when insert none word character', async () => { + await registerProvider('foo foo a ', Position.create(0, 0)) + await nvim.call('cursor', [1, 4]) + await nvim.input('i') + await nvim.input('a') + await helper.wait(50) + await assertMatches(2) + await nvim.input('i') + await nvim.input('@') + await helper.wait(50) + await assertMatches(0) + }) + + it('should cancel when insert not match wordPattern', async () => { + wordPattern = '[A-Z]' + await registerProvider('foo foo a ', Position.create(0, 0)) + await nvim.call('cursor', [1, 4]) + await nvim.input('i') + await nvim.input('A') + await helper.wait(50) + await assertMatches(2) + await nvim.input('i') + await nvim.input('3') + await helper.wait(50) + await assertMatches(0) + }) + + it('should cancel request on cursor moved', async () => { + disposables.push(languages.registerLinkedEditingRangeProvider([{ language: '*' }], { + provideLinkedEditingRanges: (doc, pos, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timer) + resolve(null) + }) + let timer = setTimeout(() => { + let document = workspace.getDocument(doc.uri) + let range = document.getWordRangeAtPosition(pos) + if (!range) return resolve(null) + let text = doc.getText(range) + let ranges: Range[] = document.getSymbolRanges(text) + resolve({ ranges, wordPattern }) + }, 1000) + }) + } + })) + let doc = await workspace.document + await nvim.setLine('foo foo ') + await doc.synchronize() + await nvim.call('cursor', [1, 2]) + await helper.wait(30) + await nvim.call('cursor', [1, 9]) + await helper.wait(30) + await assertMatches(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/links.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/links.test.ts new file mode 100644 index 00000000..6126b36f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/links.test.ts @@ -0,0 +1,137 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, DocumentLink, Range } from 'vscode-languageserver-protocol' +import LinksHandler from '../../handler/links' +import languages from '../../languages' +import workspace from '../../workspace' +import events from '../../events' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let links: LinksHandler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + links = helper.plugin.getHandler().links +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('Links', () => { + it('should get document links', async () => { + disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], { + provideDocumentLinks: (_doc, _token) => { + return [ + DocumentLink.create(Range.create(0, 0, 0, 5), 'test:///foo'), + DocumentLink.create(Range.create(1, 0, 1, 5), 'test:///bar') + ] + } + })) + let res = await links.getLinks() + expect(res.length).toBe(2) + }) + + it('should throw error when link target not resolved', async () => { + disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], { + provideDocumentLinks(_doc, _token) { + return [ + DocumentLink.create(Range.create(0, 0, 0, 5)) + ] + }, + resolveDocumentLink(link) { + return link + } + })) + let res = await links.getLinks() + let err + try { + await links.openLink(res[0]) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should open link at current position', async () => { + await nvim.setLine('foo') + await nvim.command('normal! 0') + disposables.push(workspace.registerTextDocumentContentProvider('test', { + provideTextDocumentContent: () => { + return 'test' + } + })) + disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], { + provideDocumentLinks(_doc, _token) { + return [ + DocumentLink.create(Range.create(0, 0, 0, 5)), + ] + }, + resolveDocumentLink(link) { + link.target = 'test:///foo' + return link + } + })) + await links.openCurrentLink() + let bufname = await nvim.call('bufname', '%') + expect(bufname).toBe('test:///foo') + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await nvim.call('cursor', [3, 1]) + let res = await links.openCurrentLink() + expect(res).toBe(false) + }) + + it('should return false when current links not found', async () => { + await nvim.setLine('foo') + await nvim.command('normal! 0') + disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], { + provideDocumentLinks(_doc, _token) { + return [] + } + })) + let res = await links.openCurrentLink() + expect(res).toBe(false) + }) + + it('should show tooltip', async () => { + await nvim.setLine('foo') + await nvim.call('cursor', [1, 1]) + disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], { + provideDocumentLinks(_doc, _token) { + let link = DocumentLink.create(Range.create(0, 0, 0, 5)) + link.tooltip = 'test' + return [link] + }, + resolveDocumentLink(link) { + link.target = 'http://example.com' + return link + } + })) + await links.showTooltip() + let win = await helper.getFloat() + let buf = await win.buffer + let lines = await buf.lines + expect(lines[0]).toMatch('test') + }) + + it('should enable tooltip on CursorHold', async () => { + let doc = await workspace.document + helper.updateConfiguration('links.tooltip', true) + await nvim.setLine('http://www.baidu.com') + await nvim.call('cursor', [1, 1]) + let link = await links.getCurrentLink() + expect(link).toBeDefined() + await events.fire('CursorHold', [doc.bufnr]) + let win = await helper.getFloat() + let buf = await win.buffer + let lines = await buf.lines + expect(lines[0]).toMatch('Press') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/locations.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/locations.test.ts new file mode 100644 index 00000000..2e583bfb --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/locations.test.ts @@ -0,0 +1,323 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, LocationLink, Location, Range, Position, CancellationTokenSource } from 'vscode-languageserver-protocol' +import LocationHandler from '../../handler/locations' +import languages from '../../languages' +import services from '../../services' +import workspace from '../../workspace' +import { disposeAll } from '../../util' +import helper from '../helper' +import { URI } from 'vscode-uri' + +let nvim: Neovim +let locations: LocationHandler +let disposables: Disposable[] = [] +let currLocations: Location[] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + Object.assign(workspace.env, { + locationlist: false + }) + locations = helper.plugin.getHandler().locations +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +function createLocation(name: string, sl: number, sc: number, el: number, ec: number): Location { + return Location.create(`test://${name}`, Range.create(sl, sc, el, ec)) +} + +describe('locations', () => { + describe('no provider', () => { + it('should return null when provider does not exist', async () => { + let doc = (await workspace.document).textDocument + let pos = Position.create(0, 0) + let tokenSource = new CancellationTokenSource() + let token = tokenSource.token + expect(await languages.getDefinition(doc, pos, token)).toBe(null) + expect(await languages.getDefinitionLinks(doc, pos, token)).toBe(null) + expect(await languages.getDeclaration(doc, pos, token)).toBe(null) + expect(await languages.getTypeDefinition(doc, pos, token)).toBe(null) + expect(await languages.getImplementation(doc, pos, token)).toBe(null) + expect(await languages.getReferences(doc, { includeDeclaration: false }, pos, token)).toBe(null) + }) + }) + + describe('reference', () => { + beforeEach(() => { + disposables.push(languages.registerReferencesProvider([{ language: '*' }], { + provideReferences: () => { + return currLocations + } + })) + }) + + it('should get references', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)] + let res = await locations.references() + expect(res.length).toBe(2) + }) + + it('should jump to references', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0)] + let res = await locations.gotoReferences('edit', true) + expect(res).toBe(true) + let name = await nvim.call('bufname', ['%']) + expect(name).toBe('test://foo') + }) + + it('should return false when references not found', async () => { + currLocations = [] + let res = await locations.gotoReferences('edit', true) + expect(res).toBe(false) + }) + }) + + describe('definition', () => { + beforeEach(() => { + disposables.push(languages.registerDefinitionProvider([{ language: '*' }], { + provideDefinition: () => { + return currLocations + } + })) + }) + + it('should get definitions', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)] + let res = await locations.definitions() + expect(res.length).toBe(2) + }) + + it('should jump to definitions', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0)] + let res = await locations.gotoDefinition('edit') + expect(res).toBe(true) + let name = await nvim.call('bufname', ['%']) + expect(name).toBe('test://foo') + }) + + it('should return false when definitions not found', async () => { + currLocations = [] + let res = await locations.gotoDefinition('edit') + expect(res).toBe(false) + }) + }) + + describe('declaration', () => { + beforeEach(() => { + disposables.push(languages.registerDeclarationProvider([{ language: '*' }], { + provideDeclaration: () => { + return currLocations + } + })) + }) + + it('should get declarations', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)] + let res = await locations.declarations() as Location[] + expect(res.length).toBe(2) + }) + + it('should jump to declaration', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0)] + let res = await locations.gotoDeclaration('edit') + expect(res).toBe(true) + let name = await nvim.call('bufname', ['%']) + expect(name).toBe('test://foo') + }) + + it('should return false when declaration not found', async () => { + currLocations = [] + let res = await locations.gotoDeclaration('edit') + expect(res).toBe(false) + }) + }) + + describe('typeDefinition', () => { + beforeEach(() => { + disposables.push(languages.registerTypeDefinitionProvider([{ language: '*' }], { + provideTypeDefinition: () => { + return currLocations + } + })) + }) + + it('should get type definition', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)] + let res = await locations.typeDefinitions() as Location[] + expect(res.length).toBe(2) + }) + + it('should jump to type definition', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0)] + let res = await locations.gotoTypeDefinition('edit') + expect(res).toBe(true) + let name = await nvim.call('bufname', ['%']) + expect(name).toBe('test://foo') + }) + + it('should return false when type definition not found', async () => { + currLocations = [] + let res = await locations.gotoTypeDefinition('edit') + expect(res).toBe(false) + }) + }) + + describe('implementation', () => { + beforeEach(() => { + disposables.push(languages.registerImplementationProvider([{ language: '*' }], { + provideImplementation: () => { + return currLocations + } + })) + }) + + it('should get implementations', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)] + let res = await locations.implementations() as Location[] + expect(res.length).toBe(2) + }) + + it('should jump to implementation', async () => { + currLocations = [createLocation('foo', 0, 0, 0, 0)] + let res = await locations.gotoImplementation('edit') + expect(res).toBe(true) + let name = await nvim.call('bufname', ['%']) + expect(name).toBe('test://foo') + }) + + it('should return false when implementation not found', async () => { + currLocations = [] + let res = await locations.gotoImplementation('edit') + expect(res).toBe(false) + }) + }) + + describe('getTagList', () => { + it('should return null when cword does not exist', async () => { + let res = await locations.getTagList() + expect(res).toBe(null) + }) + + it('should return null when provider does not exist', async () => { + await nvim.setLine('foo') + await nvim.command('normal! ^') + let res = await locations.getTagList() + expect(res).toBe(null) + }) + + it('should return null when result is empty', async () => { + disposables.push(languages.registerDefinitionProvider([{ language: '*' }], { + provideDefinition: () => { + return [] + } + })) + await nvim.setLine('foo') + await nvim.command('normal! ^') + let res = await locations.getTagList() + expect(res).toBe(null) + }) + + it('should return tag definitions', async () => { + disposables.push(languages.registerDefinitionProvider([{ language: '*' }], { + provideDefinition: () => { + return [createLocation('bar', 2, 0, 2, 5), Location.create(URI.file('/foo').toString(), Range.create(1, 0, 1, 5))] + } + })) + await nvim.setLine('foo') + await nvim.command('normal! ^') + let res = await locations.getTagList() + expect(res).toEqual([ + { + name: 'foo', + cmd: 'keepjumps 3 | normal 1|', + filename: 'test://bar' + }, + { name: 'foo', cmd: 'keepjumps 2 | normal 1|', filename: '/foo' } + ]) + }) + }) + + describe('findLocations', () => { + // hook result + let fn + let result: any + beforeAll(() => { + fn = services.sendRequest + services.sendRequest = () => { + return Promise.resolve(result) + } + }) + + afterAll(() => { + services.sendRequest = fn + }) + + it('should handle locations from language client', async () => { + result = [createLocation('bar', 2, 0, 2, 5)] + await locations.findLocations('foo', 'mylocation', {}, false) + let res = await nvim.getVar('coc_jump_locations') + expect(res).toEqual([{ + uri: 'test://bar', + lnum: 3, + end_lnum: 3, + col: 1, + end_col: 6, + filename: 'test://bar', + text: '', + range: Range.create(2, 0, 2, 5) + }]) + }) + + it('should handle nested locations', async () => { + let location: any = { + location: createLocation('file', 0, 0, 0, 0), + children: [{ + location: createLocation('foo', 3, 0, 3, 5), + children: [] + }, { + location: createLocation('bar', 4, 0, 4, 5), + children: [] + }] + } + result = location + await locations.findLocations('foo', 'mylocation', {}, false) + let res = await nvim.getVar('coc_jump_locations') as any[] + expect(res.length).toBe(3) + }) + }) + + describe('handleLocations', () => { + it('should not throw when location is undefined', async () => { + await locations.handleLocations(null) + }) + + it('should not throw when locations is empty array', async () => { + await locations.handleLocations([]) + }) + + it('should handle single location', async () => { + await locations.handleLocations(createLocation('single', 0, 0, 0, 0)) + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toBe('test://single') + }) + + it('should handle location link', async () => { + let link = LocationLink.create('test://link', Range.create(0, 0, 0, 3), Range.create(1, 0, 1, 3)) + await locations.handleLocations([link]) + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toBe('test://link') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/outline.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/outline.test.ts new file mode 100644 index 00000000..e961fb17 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/outline.test.ts @@ -0,0 +1,467 @@ +import { Buffer, Neovim } from '@chemzqm/neovim' +import { CodeAction, CodeActionKind, Disposable, DocumentSymbol, Range, SymbolKind, SymbolTag, TextEdit } from 'vscode-languageserver-protocol' +import events from '../../events' +import Symbols from '../../handler/symbols/index' +import languages from '../../languages' +import { ProviderResult } from '../../provider' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' +import Parser from './parser' + +let nvim: Neovim +let symbols: Symbols +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + symbols = helper.plugin.getHandler().symbols +}) + +beforeEach(() => { + disposables.push(languages.registerDocumentSymbolProvider([{ language: 'javascript' }], { + provideDocumentSymbols: document => { + let content = document.getText() + let showDetail = content.includes('detail') + let parser = new Parser(content, showDetail) + let res: DocumentSymbol[] = parser.parse() + if (res.length) { + res[0].tags = [SymbolTag.Deprecated] + } + return Promise.resolve(res) + } + })) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + disposables = [] + await helper.reset() + await nvim.command(`let w:cocViewId = ''`) + +}) + +async function getOutlineBuffer(): Promise { + let winid = await nvim.call('coc#window#find', ['cocViewId', 'OUTLINE']) + if (winid == -1) return undefined + let bufnr = await nvim.call('winbufnr', [winid]) + if (bufnr == -1) return undefined + return nvim.createBuffer(bufnr) +} + +describe('symbols outline', () => { + + let defaultCode = `class myClass { + fun1() { } + fun2() {} +}` + + async function createBuffer(code = defaultCode): Promise { + await helper.edit() + let buf = await nvim.buffer + await nvim.command('setf javascript') + await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false }) + let doc = await workspace.document + await doc.synchronize() + return buf + } + + describe('configuration', () => { + it('should follow cursor', async () => { + await createBuffer() + let curr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(0) + let bufnr = await nvim.call('bufnr', ['%']) + await nvim.command('wincmd p') + await nvim.command('exe 3') + await events.fire('CursorHold', [curr]) + await helper.wait(50) + let buf = nvim.createBuffer(bufnr) + let lines = await buf.getLines() + expect(lines.slice(1)).toEqual([ + '- c myClass 1', ' m fun1 2', ' m fun2 3' + ]) + let signs = await buf.getSigns({ group: 'CocTree' }) + expect(signs.length).toBe(1) + expect(signs[0]).toEqual({ + lnum: 2, + id: 3001, + name: 'CocTreeSelected', + priority: 10, + group: 'CocTree' + }) + }) + + it('should not follow cursor', async () => { + workspace.configurations.updateUserConfig({ + 'outline.followCursor': false, + }) + await createBuffer() + let curr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(0) + let bufnr = await nvim.call('bufnr', ['%']) + await nvim.command('wincmd p') + await nvim.command('exe 3') + await events.fire('CursorHold', [curr]) + await helper.wait(50) + let buf = nvim.createBuffer(bufnr) + let signs = await buf.getSigns({ group: 'CocTree' }) + expect(signs.length).toBe(0) + }) + + it('should keep current window', async () => { + workspace.configurations.updateUserConfig({ + 'outline.keepWindow': true, + }) + await createBuffer() + let curr = await nvim.call('bufnr', ['%']) + await symbols.showOutline() + let bufnr = await nvim.call('bufnr', ['%']) + expect(curr).toBe(bufnr) + }) + + it('should check on buffer switch', async () => { + workspace.configurations.updateUserConfig({ + 'outline.checkBufferSwitch': true, + }) + await createBuffer() + await symbols.showOutline(1) + await helper.edit('unnamed') + await helper.wait(200) + let buf = await getOutlineBuffer() + let lines = await buf.lines + expect(lines[0]).toMatch('Document symbol provider not found') + }) + + it('should not check on buffer switch', async () => { + workspace.configurations.updateUserConfig({ + 'outline.checkBufferSwitch': false + }) + await helper.wait(30) + await createBuffer() + await symbols.showOutline(1) + await helper.edit('unnamed') + await helper.wait(100) + let buf = await getOutlineBuffer() + let lines = await buf.lines + expect(lines.slice(1)).toEqual([ + '- c myClass 1', ' m fun1 2', ' m fun2 3' + ]) + }) + + it('should not check on buffer reload', async () => { + workspace.configurations.updateUserConfig({ + 'outline.checkBufferSwitch': false + }) + await symbols.showOutline(1) + await helper.wait(50) + await createBuffer() + await helper.wait(50) + let buf = await getOutlineBuffer() + expect(buf).toBeDefined() + }) + + it('should sort by position', async () => { + let code = `class myClass { + fun2() { } + fun1() {} +}` + workspace.configurations.updateUserConfig({ + 'outline.sortBy': 'position', + }) + await createBuffer(code) + await symbols.showOutline(1) + let buf = await getOutlineBuffer() + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTLINE Position', '- c myClass 1', ' m fun2 2', ' m fun1 3' + ]) + }) + + it('should sort by name', async () => { + let code = `class myClass { + fun2() {} + fun1() {} +}` + workspace.configurations.updateUserConfig({ + 'outline.sortBy': 'name', + }) + await createBuffer(code) + await symbols.showOutline(1) + let buf = await getOutlineBuffer() + let lines = await buf.lines + expect(lines).toEqual([ + 'OUTLINE Name', '- c myClass 1', ' m fun1 3', ' m fun2 2' + ]) + }) + + it('should change sort method', async () => { + workspace.configurations.updateUserConfig({ + 'outline.detailAsDescription': false + }) + let code = `class detail { + fun2() {} + fun1() {} +}` + await createBuffer(code) + await symbols.showOutline(0) + await helper.wait(30) + await nvim.input('') + await helper.waitFloat() + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.waitFloat() + await nvim.input('3') + await helper.waitFor('getline', [1], 'OUTLINE Position') + }) + + it('should show detail as description', async () => { + workspace.configurations.updateUserConfig({ + 'outline.detailAsDescription': true + }) + let code = `class detail { + fun2() {} +}` + await createBuffer(code) + await symbols.showOutline(1) + let buf = await getOutlineBuffer() + let lines = await buf.lines + expect(lines.slice(1)).toEqual([ + '- c detail 1', ' m fun2 () 2' + ]) + }) + }) + + describe('events', () => { + + it('should not close TreeView on buffer reload', async () => { + await createBuffer() + await symbols.showOutline(0) + await nvim.command('edit') + await helper.wait(30) + let winid = await nvim.call('coc#window#find', ['cocViewId', 'OUTLINE']) + expect(winid).toBeGreaterThan(0) + }) + + it('should dispose on buffer unload', async () => { + await createBuffer() + let curr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(0) + await nvim.command('tabe') + await nvim.command(`bd! ${curr}`) + await helper.wait(30) + let buf = await getOutlineBuffer() + expect(buf).toBeUndefined() + }) + + it('should check current window on BufEnter', async () => { + await createBuffer() + await symbols.showOutline(1) + let winid = await nvim.call('win_getid', []) + await nvim.command('enew') + await helper.wait(100) + let win = await nvim.window + expect(win.id).toBe(winid) + }) + + it('should recreated when original window exists', async () => { + await symbols.showOutline(1) + await helper.wait(50) + await createBuffer() + await helper.wait(50) + let buf = await getOutlineBuffer() + expect(buf).toBeDefined() + }) + + it('should keep old outline when new buffer not attached', async () => { + await createBuffer() + await symbols.showOutline(1) + await nvim.command(`vnew +setl\\ buftype=nofile`) + await helper.wait(50) + let buf = await getOutlineBuffer() + expect(buf).toBeDefined() + let lines = await buf.lines + expect(lines.slice(1)).toEqual([ + '- c myClass 1', ' m fun1 2', ' m fun2 3' + ]) + }) + + it('should not reload when switch to original buffer', async () => { + await createBuffer() + await symbols.showOutline(0) + let buf = await getOutlineBuffer() + let name = await buf.name + await nvim.command('wincmd p') + await helper.wait(50) + buf = await getOutlineBuffer() + let curr = await buf.name + expect(curr).toBe(name) + }) + }) + + describe('show()', () => { + it('should not throw when document not attached', async () => { + await nvim.command(`edit +setl\\ buftype=nofile t`) + await workspace.document + await symbols.showOutline(1) + }) + + it('should not throw when provider does not exist', async () => { + await symbols.showOutline(1) + let buf = await getOutlineBuffer() + expect(buf).toBeDefined() + }) + + it('should not throw when symbols is empty', async () => { + await createBuffer('') + await symbols.showOutline(1) + let buf = await getOutlineBuffer() + expect(buf).toBeDefined() + }) + + it('should jump to selected symbol', async () => { + await createBuffer() + let bufnr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(0) + await helper.waitFor('getline', [3], ' m fun1 2') + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + let curr = await nvim.call('bufnr', ['%']) + expect(curr).toBe(bufnr) + let cursor = await nvim.call('coc#cursor#position') + expect(cursor).toEqual([1, 2]) + }) + + it('should update symbols', async () => { + await createBuffer() + let doc = await workspace.document + let bufnr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(1) + await helper.wait(10) + let buf = nvim.createBuffer(bufnr) + let code = 'class foo{}' + await buf.setLines(code.split('\n'), { + start: 0, + end: -1, + strictIndexing: false + }) + await doc.synchronize() + buf = await getOutlineBuffer() + await helper.waitFor('eval', [`getbufline(${buf.id},1)[0]`], /No\sresults/) + let lines = await buf.lines + expect(lines).toEqual([ + 'No results', + '', + 'OUTLINE Category' + ]) + }) + + it('should show label in description', async () => { + disposables.push(languages.registerDocumentSymbolProvider([{ language: 'vim' }], { + meta: { + label: 'vimlsp' + }, + provideDocumentSymbols: _ => { + let res: DocumentSymbol[] = [{ + name: 'let', + range: Range.create(0, 0, 0, 3), + kind: SymbolKind.Constant, + selectionRange: Range.create(0, 0, 0, 3), + tags: [SymbolTag.Deprecated] + }] + return Promise.resolve(res) + } + })) + let doc = await helper.createDocument('t.vim') + await nvim.command('setf vim') + let buf = await nvim.buffer + await buf.setLines(['let'], { start: 0, end: -1, strictIndexing: false }) + await doc.synchronize() + await symbols.showOutline(0) + await helper.waitFor('getline', [1], 'OUTLINE vimlsp') + }) + }) + + describe('actions', () => { + it('should invoke visual select', async () => { + await createBuffer() + let bufnr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(0) + await helper.waitFor('getline', [3], /fun1/) + await nvim.command('exe 3') + await nvim.input('') + await helper.waitFloat() + await nvim.input('') + await helper.waitFor('mode', [], 'v') + let buf = await nvim.buffer + expect(buf.id).toBe(bufnr) + }) + + it('should invoke selected code action', async () => { + const codeAction = CodeAction.create('my action', CodeActionKind.Refactor) + let uri: string + disposables.push(languages.registerCodeActionProvider([{ language: '*' }], { + provideCodeActions: () => [codeAction], + resolveCodeAction: (action): ProviderResult => { + action.edit = { + changes: { + [uri]: [TextEdit.del(Range.create(0, 0, 0, 5))] + } + } + return action + } + }, undefined)) + await createBuffer() + let bufnr = await nvim.call('bufnr', ['%']) + let doc = workspace.getDocument(bufnr) + uri = doc.uri + await symbols.showOutline(0) + await helper.wait(200) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + await nvim.input('') + await helper.wait(200) + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines[0]).toBe(' myClass {') + }) + }) + + describe('hide()', () => { + it('should hide outline', async () => { + await createBuffer('') + await symbols.showOutline(1) + await helper.wait(50) + await symbols.hideOutline() + let buf = await getOutlineBuffer() + expect(buf).toBeUndefined() + }) + + it('should not throw when outline does not exist', async () => { + await symbols.hideOutline() + let buf = await getOutlineBuffer() + expect(buf).toBeUndefined() + }) + }) + + describe('dispose', () => { + it('should dispose provider and views', async () => { + await createBuffer('') + let bufnr = await nvim.call('bufnr', ['%']) + await symbols.showOutline(1) + symbols.dispose() + await helper.wait(50) + expect(symbols.hasOutline(bufnr)).toBe(false) + let buf = await getOutlineBuffer() + expect(buf).toBeUndefined() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/parser.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/parser.ts new file mode 100644 index 00000000..99b9a158 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/parser.ts @@ -0,0 +1,118 @@ +import { DocumentSymbol, Range, SymbolKind } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' + +/** + * A syntax parser that parse `class` and `method` only. + */ +export default class Parser { + private _curr = 0 + private _symbols: DocumentSymbol[] = [] + private currSymbol: DocumentSymbol | undefined + private len: number + private textDocument: TextDocument + constructor(private _content: string, private showDetail = false) { + this.len = _content.length + this.textDocument = TextDocument.create('test:///a', 'txt', 1, _content) + } + + public parse(): DocumentSymbol[] { + while (this._curr <= this.len - 1) { + this.parseToken() + } + return this._symbols + } + + /** + * Parse a symbol, reset currSymbol & _curr + */ + private parseToken(): void { + this.skipSpaces() + if (this.currSymbol) { + let endOffset = this.textDocument.offsetAt(this.currSymbol.range.end) + if (this._curr > endOffset) { + this.currSymbol = undefined + } + } + let remain = this.getLineRemain() + let ms = remain.match(/^(class)\s(\w+)\s\{\s*/) + if (ms) { + // find class + let start = this._curr + 6 + let end = start + ms[2].length + let selectionRange = Range.create(this.textDocument.positionAt(start), this.textDocument.positionAt(end)) + let endPosition = this.findMatchedIndex(this._curr + ms[0].length) + let range = Range.create(this.textDocument.positionAt(this._curr), this.textDocument.positionAt(endPosition)) + let symbolInfo: DocumentSymbol = { + range, + selectionRange, + kind: SymbolKind.Class, + name: ms[2], + children: [] + } + if (this.currSymbol && this.currSymbol.children) { + this.currSymbol.children.push(symbolInfo) + } else { + this._symbols.push(symbolInfo) + } + this.currSymbol = symbolInfo + } else if (this.currSymbol && this.currSymbol.kind == SymbolKind.Class) { + let ms = remain.match(/(\w+)\((.*)\)\s*\{/) + if (ms) { + // find method + let start = this._curr + let end = start + ms[1].length + let selectionRange = Range.create(this.textDocument.positionAt(start), this.textDocument.positionAt(end)) + let endPosition = this.findMatchedIndex(this._curr + ms[0].length) + let range = Range.create(this.textDocument.positionAt(this._curr), this.textDocument.positionAt(endPosition)) + let symbolInfo: DocumentSymbol = { + range, + selectionRange, + kind: SymbolKind.Method, + detail: this.showDetail ? `(${ms[2]})` : undefined, + name: ms[1] + } + if (this.currSymbol && this.currSymbol.children) { + this.currSymbol.children.push(symbolInfo) + } else { + this._symbols.push(symbolInfo) + } + } + } + this._curr = this._curr + remain.length + 1 + } + + private findMatchedIndex(start: number): number { + let level = 0 + for (let i = start; i < this.len; i++) { + let ch = this._content[i] + if (ch == '{') { + level = level + 1 + } + if (ch == '}') { + if (level == 0) return i + level = level - 1 + } + } + throw new Error(`Can't find matched }`) + } + + private getLineRemain(): string { + let chars = '' + for (let i = this._curr; i < this.len; i++) { + let ch = this._content[i] + if (ch == '\n') break + chars = chars + ch + } + return chars + } + + private skipSpaces(): void { + for (let i = this._curr; i < this.len; i++) { + let ch = this._content[i] + if (!ch || /\S/.test(ch)) { + this._curr = i + break + } + } + } +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/refactor.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/refactor.test.ts new file mode 100644 index 00000000..74b34a64 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/refactor.test.ts @@ -0,0 +1,677 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from '@chemzqm/neovim/lib/api/Buffer' +import fs from 'fs' +import { Position, Range, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import RefactorBuffer, { FileItemDef, fixChangeParams } from '../../handler/refactor/buffer' +import Changes from '../../handler/refactor/changes' +import Refactor from '../../handler/refactor/index' +import languages from '../../languages' +import { DidChangeTextDocumentParams } from '../../types' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let refactor: Refactor + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + refactor = helper.plugin.getHandler().refactor +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + refactor.reset() + await helper.reset() +}) + +function createEdit(uri: string): WorkspaceEdit { + let edit = TextEdit.insert(Position.create(0, 0), 'a') + let doc = { uri, version: null } + return { documentChanges: [TextDocumentEdit.create(doc, [edit])] } +} + +// assert ranges is expected. +async function assertSynchronized(buf: RefactorBuffer) { + let buffer = nvim.createBuffer(buf.bufnr) + let lines = await buffer.lines + let items: { lnum: number, lines: string[] }[] = [] + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (line.includes('\u3000') && line.length > 1) { + items.push({ lnum: i + 1, lines: [] }) + } + } + let curr: { lnum: number, lines: string[] }[] = [] + buf.fileItems.forEach(item => { + item.ranges.forEach(r => { + curr.push({ lnum: r.lnum, lines: [] }) + }) + }) + curr.sort((a, b) => a.lnum - b.lnum) + expect(items).toEqual(curr) +} + +describe('fixChangeParams', () => { + function createChangeParams(range: Range, text: string, original: string, originalLines: ReadonlyArray): DidChangeTextDocumentParams { + return { + textDocument: { + uri: 'untitled:/1', + version: 1, + }, + originalLines, + original, + bufnr: 1, + contentChanges: [{ range, text }] + } + } + + it('should fix delete change params', async () => { + let e = createChangeParams(Range.create(0, 4, 2, 4), '', 'x\nfoo\n\u3000bar', [ + '\u3000barx', + 'foo', + '\u3000bara' + ]) + e = fixChangeParams(e) + expect(e.original).toBe('\u3000barx\nfoo\n') + expect(e.contentChanges[0].range).toEqual(Range.create(0, 0, 2, 0)) + }) + + it('should fix insert change params', async () => { + let e = createChangeParams(Range.create(0, 4, 0, 4), 'x\nfoo\n\u3000bar', '', [ + '\u3000bara' + ]) + e = fixChangeParams(e) + expect(e.original).toBe('') + let change = e.contentChanges[0] + expect(change.range).toEqual(Range.create(0, 0, 0, 0)) + expect(change.text).toBe('\u3000barx\nfoo\n') + }) +}) + +describe('refactor', () => { + describe('checkInsert()', () => { + it('should check inserted ranges', async () => { + let c = new Changes() + expect(c.checkInsert([1])).toBeUndefined() + c.add([{ filepath: __filename, start: 1, lnum: 1, lines: [''] }]) + expect(c.checkInsert([2])).toBeUndefined() + }) + }) + + describe('getFileRange()', () => { + it('should throw when range does not exist', async () => { + let uri = URI.file(__filename).toString() + let locations = [{ uri, range: Range.create(0, 0, 0, 6) }] + let buf = await refactor.fromLocations(locations) + let fn = () => { + buf.getFileRange(1) + } + expect(fn).toThrow(Error) + }) + + it('should find file range', async () => { + let uri = URI.file(__filename).toString() + let locations = [{ uri, range: Range.create(0, 0, 0, 6) }] + let buf = await refactor.fromLocations(locations) + let res = buf.getFileRange(4) + expect(res).toBeDefined() + }) + }) + + describe('getRange()', () => { + it('should get delete range', async () => { + let filename = await createTmpFile('foo\n\nbar\n') + let fileItem: FileItemDef = { + filepath: filename, + ranges: [{ start: 0, end: 1 }, { start: 2, end: 3 }] + } + let buf = await refactor.createRefactorBuffer() + await buf.addFileItems([fileItem]) + let res = buf.getFileRange(4) + let r = buf.getDeleteRange(res) + expect(r).toEqual(Range.create(3, 0, 6, 0)) + res = buf.getFileRange(7) + r = buf.getDeleteRange(res) + expect(r).toEqual(Range.create(6, 0, 8, 0)) + }) + + it('should get replace range', async () => { + let filename = await createTmpFile('foo\n\nbar\n') + let fileItem: FileItemDef = { + filepath: filename, + ranges: [{ start: 0, end: 1 }, { start: 2, end: 3 }] + } + let buf = await refactor.createRefactorBuffer() + await buf.addFileItems([fileItem]) + let res = buf.getFileRange(4) + let r = buf.getReplaceRange(res) + expect(r).toEqual(Range.create(4, 0, 4, 3)) + res = buf.getFileRange(7) + r = buf.getReplaceRange(res) + expect(r).toEqual(Range.create(7, 0, 7, 3)) + }) + }) + + describe('fromWorkspaceEdit()', () => { + it('should not create from invalid workspaceEdit', async () => { + let res = await refactor.fromWorkspaceEdit(undefined) + expect(res).toBeUndefined() + res = await refactor.fromWorkspaceEdit({ documentChanges: [] }) + expect(res).toBeUndefined() + }) + + it('should create from document changes', async () => { + let edit = createEdit(URI.file(__filename).toString()) + let buf = await refactor.fromWorkspaceEdit(edit) + let shown = await buf.valid + expect(shown).toBe(true) + let items = buf.fileItems + expect(items.length).toBe(1) + await nvim.command(`bd! ${buf.bufnr}`) + await helper.wait(30) + let has = refactor.has(buf.bufnr) + expect(has).toBe(false) + }) + + it('should create from workspaceEdit', async () => { + let changes = { + [URI.file(__filename).toString()]: [{ + range: Range.create(0, 0, 0, 6), + newText: '' + }, { + range: Range.create(1, 0, 1, 6), + newText: '' + }, { + range: Range.create(50, 0, 50, 1), + newText: ' ' + }, { + range: Range.create(60, 0, 60, 1), + newText: ' ' + }] + } + let edit: WorkspaceEdit = { changes } + let buf = await refactor.fromWorkspaceEdit(edit) + let shown = await buf.valid + expect(shown).toBe(true) + let items = buf.fileItems + expect(items.length).toBe(1) + }) + }) + + describe('fromLocations()', () => { + it('should create from locations', async () => { + let uri = URI.file(__filename).toString() + let locations = [{ + uri, + range: Range.create(0, 0, 0, 6), + }, { + uri, + range: Range.create(1, 0, 1, 6), + }] + let buf = await refactor.fromLocations(locations) + let shown = await buf.valid + expect(shown).toBe(true) + let items = buf.fileItems + expect(items.length).toBe(1) + }) + + it('should not create from empty locations', async () => { + let buf = await refactor.fromLocations([]) + expect(buf).toBeUndefined() + }) + }) + + describe('onChange()', () => { + async function setup(): Promise { + let uri = URI.file(__filename).toString() + let locations = [{ + uri, + range: Range.create(0, 0, 0, 6), + }, { + uri, + range: Range.create(1, 0, 1, 6), + }, { + uri, + range: Range.create(10, 0, 10, 6), + }] + return await refactor.fromLocations(locations) + } + + it('should refresh on empty text change', async () => { + let buf = await setup() + let line = await nvim.call('getline', [4]) + let doc = workspace.getDocument(buf.bufnr) + await nvim.call('setline', [4, line]) + doc._forceSync() + let srcId = await nvim.createNamespace('coc-refactor') + let markers = await helper.getMarkers(doc.bufnr, srcId) + expect(markers.length).toBe(2) + }) + + it('should detect range delete and undo', async () => { + let buf = await setup() + let doc = workspace.getDocument(buf.bufnr) + let r = buf.getFileRange(4) + let end = r.lnum + r.lines.length + await nvim.command(`${r.lnum},${end + 1}d`) + await doc.synchronize() + await assertSynchronized(buf) + await nvim.command('undo') + await doc.synchronize() + await assertSynchronized(buf) + }) + + it('should detect normal delete', async () => { + let buf = await setup() + let doc = workspace.getDocument(buf.bufnr) + let r = buf.getFileRange(4) + await nvim.command(`${r.lnum + 1},${r.lnum + 1}d`) + await doc.synchronize() + await assertSynchronized(buf) + }) + + it('should detect insert', async () => { + let buf = await setup() + let doc = workspace.getDocument(buf.bufnr) + let buffer = nvim.createBuffer(buf.bufnr) + await buffer.append(['foo']) + await doc.synchronize() + await assertSynchronized(buf) + await buffer.append(['foo', '\u3000']) + await doc.synchronize() + await assertSynchronized(buf) + }) + }) + + describe('onDocumentChange()', () => { + it('should ignore when change after range', async () => { + let doc = await helper.createDocument() + await doc.buffer.append(['foo', 'bar']) + await doc.synchronize() + let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(0, 0, 0, 3) }]) + let lines = await nvim.call('getline', [1, '$']) + await doc.buffer.append(['def']) + await doc.synchronize() + let newLines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(newLines) + await assertSynchronized(buf) + }) + + it('should adjust when change before range', async () => { + let doc = await helper.createDocument() + await doc.buffer.append(['', '', '', '', 'foo', 'bar']) + await doc.synchronize() + let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }]) + await doc.buffer.setLines(['def'], { start: 0, end: 0, strictIndexing: false }) + await doc.synchronize() + let fileRange = buf.getFileRange(4) + expect(fileRange.start).toBe(2) + expect(fileRange.lines.length).toBe(6) + await assertSynchronized(buf) + }) + + it('should remove ranges when lines empty', async () => { + let doc = await helper.createDocument() + await doc.buffer.append(['', '', '', '', 'foo', 'bar']) + await doc.synchronize() + let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }]) + await doc.buffer.setLines([], { start: 0, end: -1, strictIndexing: false }) + await doc.synchronize() + let lines = await nvim.call('getline', [1, '$']) + expect(lines.length).toBe(3) + let items = buf.fileItems + expect(items.length).toBe(0) + await assertSynchronized(buf) + }) + + it('should change when liens changed', async () => { + let doc = await helper.createDocument() + await doc.buffer.append(['', '', '', '', 'foo', 'bar']) + await doc.synchronize() + let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }]) + await doc.buffer.setLines(['def', 'def'], { start: 5, end: 6, strictIndexing: false }) + await doc.synchronize() + let lines = await nvim.call('getline', [1, '$']) + expect(lines[lines.length - 2]).toBe('def') + await assertSynchronized(buf) + }) + }) + + describe('getFileChanges()', () => { + it('should get changes #1', async () => { + await helper.createDocument() + let lines = ` +Save current buffer to make changes +\u3000 +\u3000 +\u3000/a.ts + }) + } ` + let buf = await refactor.fromLines(lines.split('\n')) + let changes = await buf.getFileChanges() + expect(changes).toEqual([{ lnum: 5, filepath: '/a.ts', lines: [' })', ' } '] }]) + }) + + it('should get changes #2', async () => { + let lines = ` +\u3000/a.ts + }) + } ` + let buf = await refactor.fromLines(lines.split('\n')) + let changes = await buf.getFileChanges() + expect(changes).toEqual([{ lnum: 2, filepath: '/a.ts', lines: [' })', ' } '] }]) + }) + + it('should get changes #3', async () => { + let lines = ` +\u3000/a.ts + }) + } +\u3000` + let buf = await refactor.fromLines(lines.split('\n')) + let changes = await buf.getFileChanges() + expect(changes).toEqual([{ lnum: 2, filepath: '/a.ts', lines: [' })', ' }'] }]) + }) + + it('should get changes #4', async () => { + let lines = ` +\u3000/a.ts +foo +\u3000/b.ts +bar +\u3000` + let buf = await refactor.fromLines(lines.split('\n')) + let changes = await buf.getFileChanges() + expect(changes).toEqual([ + { filepath: '/a.ts', lnum: 2, lines: ['foo'] }, + { filepath: '/b.ts', lnum: 4, lines: ['bar'] } + ]) + }) + }) + + describe('createRefactorBuffer()', () => { + it('should create refactor buffer', async () => { + let winid = await nvim.call('win_getid') + let buf = await refactor.createRefactorBuffer() + let curr = await nvim.call('win_getid') + expect(curr).toBeGreaterThan(winid) + let valid = await buf.valid + expect(valid).toBe(true) + buf = await refactor.createRefactorBuffer('vim') + valid = await buf.valid + expect(valid).toBe(true) + }) + + it('should use conceal for line numbers', async () => { + let buf = await refactor.createRefactorBuffer(undefined, true) + let fileItem: FileItemDef = { + filepath: __filename, + ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }] + } + await buf.addFileItems([fileItem]) + let arr = await nvim.call('getmatches') as any[] + arr = arr.filter(o => o.group == 'Conceal') + expect(arr.length).toBeGreaterThan(0) + await buf.addFileItems([{ + filepath: __filename, + ranges: [{ start: 1, end: 3 }] + }]) + await nvim.command('normal! ggdG') + let doc = workspace.getDocument(buf.bufnr) + await doc.synchronize() + let b = nvim.createBuffer(buf.bufnr) + let res = await b.getVar('line_infos') + expect(res).toEqual({}) + }) + }) + + describe('splitOpen()', () => { + async function setup(): Promise { + let buf = await refactor.createRefactorBuffer() + let fileItem: FileItemDef = { + filepath: __filename, + ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }] + } + await buf.addFileItems([fileItem]) + await nvim.call('cursor', [5, 1]) + return buf + } + + it('should jump to position by ', async () => { + let buf = await setup() + await buf.splitOpen() + let line = await nvim.eval('line(".")') + let bufname = await nvim.eval('bufname("%")') + expect(bufname).toMatch('refactor.test.ts') + expect(line).toBe(11) + }) + + it('should jump split window when original window not valid', async () => { + let win = await nvim.window + let buf = await setup() + await nvim.call('nvim_win_close', [win.id, true]) + await buf.splitOpen() + let line = await nvim.eval('line(".")') + let bufname = await nvim.eval('bufname("%")') + expect(bufname).toMatch('refactor.test.ts') + expect(line).toBe(11) + }) + }) + + describe('showMenu()', () => { + async function setup(): Promise { + let buf = await refactor.createRefactorBuffer() + let fileItem: FileItemDef = { + filepath: __filename, + ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }] + } + await buf.addFileItems([fileItem]) + await nvim.call('cursor', [5, 1]) + return buf + } + + it('should do nothing when cancelled or range not found', async () => { + let buf = await setup() + let p = buf.showMenu() + await helper.wait(50) + await nvim.input('') + await p + let bufnr = await nvim.call('bufnr', ['%']) + expect(bufnr).toBe(buf.bufnr) + await nvim.call('cursor', [1, 1]) + p = buf.showMenu() + await helper.wait(50) + await nvim.input('1') + await p + bufnr = await nvim.call('bufnr', ['%']) + expect(bufnr).toBe(buf.bufnr) + }) + + it('should open file in new tab', async () => { + let buf = await setup() + await nvim.call('cursor', [4, 1]) + let p = buf.showMenu() + await helper.wait(30) + await nvim.input('1') + await p + let nr = await nvim.call('tabpagenr') + expect(nr).toBe(2) + let lnum = await nvim.call('line', ['.']) + expect(lnum).toBe(11) + }) + + it('should remove current block', async () => { + let buf = await setup() + await nvim.call('cursor', [4, 1]) + let p = buf.showMenu() + await helper.wait(30) + await nvim.input('2') + await p + let items = buf.fileItems + expect(items[0].ranges.length).toBe(1) + await assertSynchronized(buf) + }) + }) + + describe('saveRefactor()', () => { + it('should adjust line ranges after change', async () => { + let filename = await createTmpFile('foo\n\nbar\n') + let fileItem: FileItemDef = { + filepath: filename, + ranges: [{ start: 0, end: 1 }, { start: 2, end: 3 }] + } + let buf = await refactor.createRefactorBuffer() + const getRanges = () => { + let items = buf.fileItems + let item = items.find(o => o.filepath == filename) + return item.ranges.map(o => { + return [o.start, o.start + o.lines.length] + }) + } + await buf.addFileItems([fileItem, { + filepath: __filename, + ranges: [{ start: 1, end: 5 }] + }]) + expect(getRanges()).toEqual([[0, 1], [2, 3]]) + nvim.pauseNotification() + nvim.call('setline', [5, ['xyoo']], true) + nvim.command('undojoin', true) + nvim.call('append', [5, ['de']], true) + nvim.command('undojoin', true) + nvim.call('setline', [9, ['b']], true) + await nvim.resumeNotification() + let doc = workspace.getDocument(buf.bufnr) + await doc.synchronize() + let res = await refactor.save(buf.buffer.id) + expect(res).toBe(true) + expect(getRanges()).toEqual([[0, 2], [3, 4]]) + let content = fs.readFileSync(filename, 'utf8') + expect(content).toBe('xyoo\nde\n\nb\n') + }) + + it('should not save when no change made', async () => { + let buf = await refactor.createRefactorBuffer() + let fileItem: FileItemDef = { + filepath: __filename, + ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }] + } + await buf.addFileItems([fileItem]) + let res = await buf.save() + expect(res).toBe(false) + }) + + it('should sync buffer change to file', async () => { + let doc = await helper.createDocument() + await doc.buffer.replace(['foo', 'bar', 'line'], 0) + await helper.wait(30) + let filename = URI.parse(doc.uri).fsPath + let fileItem: FileItemDef = { + filepath: filename, + ranges: [{ start: 0, end: 2 }] + } + let buf = await refactor.createRefactorBuffer() + await buf.addFileItems([fileItem]) + await nvim.call('setline', [5, 'changed']) + let res = await buf.save() + expect(res).toBe(true) + expect(fs.existsSync(filename)).toBe(true) + let content = fs.readFileSync(filename, 'utf8') + let lines = content.split('\n') + expect(lines).toEqual(['changed', 'bar', 'line', '']) + fs.unlinkSync(filename) + }) + }) + + describe('doRefactor', () => { + let disposable: Disposable + + afterEach(() => { + if (disposable) disposable.dispose() + disposable = null + }) + + it('should throw when rename provider not found', async () => { + await helper.createDocument() + let err + try { + await refactor.doRefactor() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should show message when prepare failed', async () => { + await helper.createDocument() + disposable = languages.registerRenameProvider(['*'], { + prepareRename: () => { + return undefined + }, + provideRenameEdits: () => { + return null + } + }) + await refactor.doRefactor() + let res = await helper.getCmdline() + expect(res).toMatch(/unable to rename/) + }) + + it('should show message when returned edits is null', async () => { + await helper.createDocument() + disposable = languages.registerRenameProvider(['*'], { + provideRenameEdits: () => { + return null + } + }) + await refactor.doRefactor() + let res = await helper.getCmdline() + expect(res).toMatch(/returns null/) + }) + + it('should open refactor window when edits is valid', async () => { + let filepath = __filename + disposable = languages.registerRenameProvider(['*'], { + provideRenameEdits: () => { + let changes = { + [URI.file(filepath).toString()]: [{ + range: Range.create(0, 0, 0, 6), + newText: '' + }, { + range: Range.create(1, 0, 1, 6), + newText: '' + }] + } + let edit: WorkspaceEdit = { changes } + return edit + } + }) + await helper.createDocument(filepath) + let winid = await nvim.call('win_getid') + await refactor.doRefactor() + let currWin = await nvim.call('win_getid') + expect(currWin - winid).toBeGreaterThan(0) + let bufnr = await nvim.call('bufnr', ['%']) + let b = refactor.getBuffer(bufnr) + expect(b).toBeDefined() + }) + }) + + describe('search', () => { + it('should open refactor buffer from search result', async () => { + let escaped = await nvim.call('fnameescape', [__dirname]) + await nvim.command(`cd ${escaped}`) + await helper.createDocument() + await refactor.search(['registerRenameProvider']) + let buf = await nvim.buffer + let name = await buf.name + expect(name).toMatch(/__coc_refactor__/) + let lines = await buf.lines + expect(lines[0]).toMatch(/Save current buffer/) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/rename.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/rename.test.ts new file mode 100644 index 00000000..104784e9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/rename.test.ts @@ -0,0 +1,262 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import Rename from '../../handler/rename' +import languages from '../../languages' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let rename: Rename + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + rename = helper.plugin.getHandler().rename +}) + +function getWordRangeAtPosition(doc: TextDocument, position: Position): Range | null { + let lines = doc.getText().split(/\r?\n/) + let line = lines[position.line] + if (line.length == 0 || position.character >= line.length) return null + if (!/\w/.test(line[position.character])) return null + let start = position.character + let end = position.character + 1 + if (!/\w/.test(line[start])) { + return Range.create(position, { line: position.line, character: position.character + 1 }) + } + while (start >= 0) { + let ch = line[start - 1] + if (!ch || !/\w/.test(ch)) break + start = start - 1 + } + while (end <= line.length) { + let ch = line[end] + if (!ch || !/\w/.test(ch)) break + end = end + 1 + } + return Range.create(position.line, start, position.line, end) +} + +function getSymbolRanges(textDocument: TextDocument, word: string): Range[] { + let res: Range[] = [] + let str = '' + let content = textDocument.getText() + for (let i = 0, l = content.length; i < l; i++) { + let ch = content[i] + if ('-' == ch && str.length == 0) { + continue + } + let isKeyword = /\w/.test(ch) + if (isKeyword) { + str = str + ch + } + if (str.length > 0 && !isKeyword && str == word) { + res.push(Range.create(textDocument.positionAt(i - str.length), textDocument.positionAt(i))) + } + if (!isKeyword) { + str = '' + } + } + return res +} + +beforeEach(() => { + disposables.push(languages.registerRenameProvider([{ language: 'javascript' }], { + provideRenameEdits: (doc, position: Position, newName: string) => { + let range = getWordRangeAtPosition(doc, position) + if (range) { + let word = doc.getText(range) + if (word) { + let ranges = getSymbolRanges(doc, word) + return { + changes: { + [doc.uri]: ranges.map(o => TextEdit.replace(o, newName)) + } + } + } + } + return undefined + }, + prepareRename: (doc, position) => { + let range = getWordRangeAtPosition(doc, position) + return range ? { range, placeholder: doc.getText(range) } : null + } + })) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('rename handler', () => { + describe('getWordEdit', () => { + it('should not throw when provider not found', async () => { + await helper.edit() + let res = await rename.getWordEdit() + expect(res).toBe(null) + }) + + it('should return null when prepare failed', async () => { + let doc = await helper.createDocument('t.js') + await nvim.setLine('你') + await doc.synchronize() + let res = await rename.getWordEdit() + expect(res).toBe(null) + }) + + it('should return workspace edit', async () => { + let doc = await helper.createDocument('t.js') + await nvim.setLine('foo foo') + await doc.synchronize() + let res = await rename.getWordEdit() + expect(res).toBeDefined() + expect(res.changes[doc.uri].length).toBe(2) + }) + + it('should extract words from buffer', async () => { + let doc = await helper.createDocument('t') + await nvim.setLine('你 你 你') + await doc.synchronize() + let res = await rename.getWordEdit() + expect(res).toBeDefined() + expect(res.changes[doc.uri].length).toBe(3) + }) + }) + + describe('rename', () => { + it('should throw when provider not found', async () => { + await helper.edit() + let err + try { + await rename.rename('foo') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should return false for invalid position', async () => { + await helper.createDocument('t.js') + let res = await rename.rename('foo') + expect(res).toBe(false) + }) + + it('should use newName from placeholder', async () => { + await helper.createDocument('t.js') + await nvim.setLine('foo foo foo') + let p = rename.rename() + await helper.wait(50) + await nvim.input('') + await helper.wait(10) + await nvim.input('bar') + await nvim.input('') + let res = await p + expect(res).toBe(true) + }) + + it('should return false for empty name', async () => { + await helper.createDocument('t.js') + await nvim.setLine('foo foo foo') + let p = rename.rename() + await helper.wait(50) + await nvim.input('') + await helper.wait(20) + await nvim.input('') + let res = await p + expect(res).toBe(false) + }) + + it('should use newName from range', async () => { + disposables.push(languages.registerRenameProvider([{ language: '*' }], { + provideRenameEdits: (doc, position: Position, newName: string) => { + let range = getWordRangeAtPosition(doc, position) + if (range) { + let word = doc.getText(range) + if (word) { + let ranges = getSymbolRanges(doc, word) + return { + changes: { + [doc.uri]: ranges.map(o => TextEdit.replace(o, newName)) + } + } + } + } + return undefined + }, + prepareRename: (doc, position) => { + let range = getWordRangeAtPosition(doc, position) + return range ? range : null + } + })) + await helper.createDocument() + await nvim.setLine('foo foo foo') + let p = rename.rename() + await helper.wait(50) + await nvim.input('') + await helper.wait(10) + await nvim.input('bar') + await nvim.input('') + let res = await p + expect(res).toBe(true) + await helper.waitFor('getline', ['.'], 'bar bar bar') + }) + + it('should use newName from cword', async () => { + disposables.push(languages.registerRenameProvider([{ language: '*' }], { + provideRenameEdits: (doc, position: Position, newName: string) => { + let range = getWordRangeAtPosition(doc, position) + if (range) { + let word = doc.getText(range) + if (word) { + let ranges = getSymbolRanges(doc, word) + return { + changes: { + [doc.uri]: ranges.map(o => TextEdit.replace(o, newName)) + } + } + } + } + return undefined + } + })) + await helper.createDocument() + await nvim.setLine('foo foo foo') + let p = rename.rename() + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await nvim.input('bar') + await nvim.input('') + let res = await p + expect(res).toBe(true) + let line = await nvim.getLine() + expect(line).toBe('bar bar bar') + }) + + it('should return false when result is empty', async () => { + disposables.push(languages.registerRenameProvider([{ language: '*' }], { + provideRenameEdits: () => { + return null + } + })) + await helper.createDocument() + await nvim.setLine('foo foo foo') + let p = rename.rename() + await helper.wait(50) + await nvim.input('') + await helper.wait(10) + await nvim.input('bar') + await nvim.input('') + let res = await p + expect(res).toBe(false) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/search.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/search.test.ts new file mode 100644 index 00000000..dd90ebfe --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/search.test.ts @@ -0,0 +1,101 @@ +import { Neovim } from '@chemzqm/neovim' +import Refactor from '../../handler/refactor' +import Search, { getPathFromArgs } from '../../handler/refactor/search' +import helper from '../helper' +import path from 'path' + +let nvim: Neovim +let refactor: Refactor +// use fake rg command +let cmd = path.resolve(__dirname, '../rg') +let cwd = process.cwd() + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + refactor = helper.plugin.getHandler().refactor +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + refactor.reset() + await helper.reset() +}) + +describe('getPathFromArgs', () => { + it('should get undefined path', async () => { + let res = getPathFromArgs(['a']) + expect(res).toBeUndefined() + res = getPathFromArgs(['a', 'b', '-c']) + expect(res).toBeUndefined() + res = getPathFromArgs(['a', '-b', 'c']) + expect(res).toBeUndefined() + }) +}) + +describe('search', () => { + + it('should open refactor window', async () => { + let search = new Search(nvim, cmd) + let buf = await refactor.createRefactorBuffer() + await search.run([], cwd, buf) + await helper.wait(50) + let fileItems = buf.fileItems + expect(fileItems.length).toBe(2) + expect(fileItems[0].ranges.length).toBe(2) + }) + + it('should abort task', async () => { + let search = new Search(nvim, cmd) + let buf = await refactor.createRefactorBuffer() + let p = search.run(['--sleep', '1000'], cwd, buf) + search.abort() + await p + let fileItems = buf.fileItems + expect(fileItems.length).toBe(0) + }) + + it('should work with CocAction search', async () => { + await helper.doAction('search', ['CocAction']) + let bufnr = await nvim.call('bufnr', ['%']) + let buf = refactor.getBuffer(bufnr) + expect(buf).toBeDefined() + }) + + it('should fail on invalid command', async () => { + let search = new Search(nvim, 'rrg') + let buf = await refactor.createRefactorBuffer() + let err + try { + await search.run([], cwd, buf) + } catch (e) { + err = e + } + expect(err).toBeDefined() + let msg = await helper.getCmdline() + expect(msg).toMatch(/Error on command "rrg"/) + }) + + it('should show empty result when no result found', async () => { + await helper.doAction('search', ['should found ' + ' no result']) + let bufnr = await nvim.call('bufnr', ['%']) + let buf = refactor.getBuffer(bufnr) + expect(buf).toBeDefined() + let buffer = await nvim.buffer + let lines = await buffer.lines + expect(lines[1]).toMatch(/No match found/) + }) + + it('should use corrent search folder for rg', async () => { + let search = new Search(nvim, 'rg') + await helper.createDocument() + let buf = await refactor.createRefactorBuffer() + await search.run(['-w', 'createRefactorBuffer', 'src/__tests__'], cwd, buf) + let buffer = await nvim.buffer + let lines = await buffer.lines + expect(lines[1].startsWith('Files: ')).toBe(true) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/selectionRange.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/selectionRange.test.ts new file mode 100644 index 00000000..3d04cc3c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/selectionRange.test.ts @@ -0,0 +1,144 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import SelectionRange from '../../handler/selectionRange' +import languages from '../../languages' +import workspace from '../../workspace' +import window from '../../window' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let selection: SelectionRange + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + selection = helper.plugin.getHandler().selectionRange +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('selectionRange', () => { + describe('getSelectionRanges()', () => { + it('should throw error when selectionRange provider does not exist', async () => { + let doc = await helper.createDocument() + await doc.synchronize() + let err + try { + await selection.getSelectionRanges() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should return ranges', async () => { + await helper.createDocument() + disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], { + provideSelectionRanges: _doc => { + return [{ + range: Range.create(0, 0, 0, 1) + }] + } + })) + let res = await selection.getSelectionRanges() + expect(res).toBeDefined() + expect(Array.isArray(res)).toBe(true) + }) + }) + + describe('selectRange()', () => { + async function getSelectedRange(): Promise { + let m = await nvim.mode + expect(m.mode).toBe('v') + let bufnr = await nvim.call('bufnr', ['%']) + await nvim.input('') + let doc = workspace.getDocument(bufnr) + let res = await window.getSelectedRange('v') + return res + } + + it('should select ranges forward', async () => { + let doc = await helper.createDocument() + let called = 0 + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar\ntest\n')]) + await nvim.call('cursor', [1, 1]) + disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], { + provideSelectionRanges: _doc => { + called += 1 + let arr = [{ + range: Range.create(0, 0, 0, 1) + }, { + range: Range.create(0, 0, 0, 3) + }, { + range: Range.create(0, 0, 1, 3) + }] + return arr + } + })) + await doc.synchronize() + await selection.selectRange('', false) + await selection.selectRange('', true) + expect(called).toBe(1) + let res = await getSelectedRange() + expect(res).toEqual(Range.create(0, 0, 0, 1)) + await selection.selectRange('v', true) + expect(called).toBe(2) + res = await getSelectedRange() + expect(res).toEqual(Range.create(0, 0, 0, 3)) + await selection.selectRange('v', true) + expect(called).toBe(3) + res = await getSelectedRange() + expect(res).toEqual(Range.create(0, 0, 1, 3)) + await selection.selectRange('v', true) + expect(called).toBe(4) + let m = await nvim.mode + expect(m.mode).toBe('n') + }) + + it('should select ranges backward', async () => { + let doc = await helper.createDocument() + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar\ntest\n')]) + await nvim.call('cursor', [1, 1]) + disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], { + provideSelectionRanges: _doc => { + let arr = [{ + range: Range.create(0, 0, 0, 1) + }, { + range: Range.create(0, 0, 0, 3) + }, { + range: Range.create(0, 0, 1, 3) + }] + return arr + } + })) + await doc.synchronize() + await selection.selectRange('', true) + let mode = await nvim.call('mode') + expect(mode).toBe('v') + await nvim.input('') + await window.selectRange(Range.create(0, 0, 1, 3)) + await nvim.input('') + await selection.selectRange('v', false) + let r = await getSelectedRange() + expect(r).toEqual(Range.create(0, 0, 0, 3)) + await nvim.input('') + await selection.selectRange('v', false) + r = await getSelectedRange() + expect(r).toEqual(Range.create(0, 0, 0, 1)) + await nvim.input('') + await selection.selectRange('v', false) + mode = await nvim.call('mode') + expect(mode).toBe('n') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/semanticTokens.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/semanticTokens.test.ts new file mode 100644 index 00000000..19317956 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/semanticTokens.test.ts @@ -0,0 +1,584 @@ +import { Buffer, Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { Disposable, Range, SemanticTokensLegend } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import commandManager from '../../commands' +import SemanticTokens from '../../handler/semanticTokens/index' +import languages from '../../languages' +import { disposeAll } from '../../util' +import window from '../../window' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let ns: number +let disposables: Disposable[] = [] +let highlighter: SemanticTokens +let legend: SemanticTokensLegend = { + tokenTypes: [ + "comment", + "keyword", + "string", + "number", + "regexp", + "operator", + "namespace", + "type", + "struct", + "class", + "interface", + "enum", + "enumMember", + "typeParameter", + "function", + "method", + "property", + "macro", + "variable", + "parameter", + "angle", + "arithmetic", + "attribute", + "bitwise", + "boolean", + "brace", + "bracket", + "builtinType", + "character", + "colon", + "comma", + "comparison", + "constParameter", + "dot", + "escapeSequence", + "formatSpecifier", + "generic", + "label", + "lifetime", + "logical", + "operator", + "parenthesis", + "punctuation", + "selfKeyword", + "semicolon", + "typeAlias", + "union", + "unresolvedReference" + ], + tokenModifiers: [ + "documentation", + "declaration", + "definition", + "static", + "abstract", + "deprecated", + "readonly", + "constant", + "controlFlow", + "injected", + "mutable", + "consuming", + "async", + "library", + "public", + "unsafe", + "attribute", + "trait", + "callable", + "intraDocLink" + ] +} + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + ns = await nvim.call('coc#highlight#create_namespace', ['semanticTokens']) + highlighter = helper.plugin.getHandler().semanticHighlighter +}) + +afterAll(async () => { + await helper.shutdown() +}) + +const defaultResult = { + resultId: '1', + data: [ + 0, 0, 2, 1, 0, + 0, 3, 4, 14, 2, + 0, 4, 1, 41, 0, + 0, 1, 1, 41, 3, + 0, 2, 1, 25, 0, + 1, 4, 8, 17, 0, + 0, 8, 1, 41, 0, + 0, 1, 3, 2, 0, + 0, 3, 1, 41, 0, + 0, 1, 1, 44, 0, + 1, 0, 1, 25, 0, + ] +} + +function registerRangeProvider(filetype: string, fn: (range: Range) => number[]): Disposable { + return languages.registerDocumentRangeSemanticTokensProvider([{ language: filetype }], { + provideDocumentRangeSemanticTokens: (_, range) => { + return { + data: fn(range) + } + } + }, legend) +} + +function registerProvider(): void { + disposables.push(languages.registerDocumentSemanticTokensProvider([{ language: 'rust' }], { + provideDocumentSemanticTokens: () => { + return defaultResult + }, + provideDocumentSemanticTokensEdits: (_, previousResultId) => { + if (previousResultId !== '1') return undefined + return { + resultId: '2', + edits: [{ + start: 0, + deleteCount: 0, + data: [0, 0, 3, 1, 0] + }] + } + } + }, legend)) +} + +async function createRustBuffer(): Promise { + helper.updateConfiguration('semanticTokens.filetypes', ['rust']) + registerProvider() + let code = `fn main() { + println!("H"); +}` + let buf = await nvim.buffer + await nvim.command('setf rust') + await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false }) + let doc = await workspace.document + await doc.patchChange() + return buf +} + +afterEach(async () => { + helper.updateConfiguration('semanticTokens.filetypes', []) + await helper.reset() + disposeAll(disposables) +}) + +describe('semanticTokens', () => { + describe('showHighlightInfo()', () => { + it('should show error when buffer not attached', async () => { + await nvim.command('h') + await highlighter.showHighlightInfo() + let line = await helper.getCmdline() + expect(line).toMatch('not attached') + await highlighter.inspectSemanticToken() + }) + + it('should show message when not enabled', async () => { + await helper.edit('t.txt') + await highlighter.showHighlightInfo() + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines[2]).toMatch('not enabled for current filetype') + }) + + it('should show semantic tokens info', async () => { + await createRustBuffer() + await highlighter.highlightCurrent() + await commandManager.executeCommand('semanticTokens.checkCurrent') + let buf = await nvim.buffer + let lines = await buf.lines + let content = lines.join('\n') + expect(content).toMatch('Semantic highlight groups used by current buffer') + }) + + it('should show highlight info for empty legend', async () => { + helper.updateConfiguration('semanticTokens.filetypes', ['*']) + disposables.push(languages.registerDocumentRangeSemanticTokensProvider([{ language: '*' }], { + provideDocumentRangeSemanticTokens: (_, range) => { + return { + data: [] + } + } + }, { tokenModifiers: [], tokenTypes: [] })) + await highlighter.showHighlightInfo() + await highlighter.showHighlightInfo() + let buf = await nvim.buffer + let lines = await buf.lines + let content = lines.join('\n') + expect(content).toMatch('No token') + }) + }) + + describe('highlightCurrent()', () => { + it('should refresh highlights', async () => { + await createRustBuffer() + await nvim.command('hi link CocSemDeclarationFunction MoreMsg') + await nvim.command('hi link CocSemDocumentation Statement') + await window.moveTo({ line: 0, character: 4 }) + await highlighter.highlightCurrent() + await commandManager.executeCommand('semanticTokens.inspect') + let win = await helper.getFloat() + let buf = await win.buffer + let lines = await buf.lines + let content = lines.join('\n') + expect(content).toMatch('CocSemDeclarationFunction') + await window.moveTo({ line: 1, character: 0 }) + await commandManager.executeCommand('semanticTokens.inspect') + win = await helper.getFloat() + expect(win).toBeUndefined() + }) + + it('should refresh highlights by command', async () => { + await helper.edit() + let err + try { + await commandManager.executeCommand('semanticTokens.refreshCurrent') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should refresh when buffer visible', async () => { + helper.updateConfiguration('semanticTokens.filetypes', ['rust']) + let code = `fn main() { + println!("H"); +}` + let buf = await nvim.buffer + await nvim.command('setf rust') + await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false }) + await helper.wait(10) + let doc = await workspace.document + await doc.synchronize() + let item = await highlighter.getCurrentItem() + expect(item.enabled).toBe(false) + await nvim.command('edit bar') + registerProvider() + expect(item.enabled).toBe(true) + await helper.wait(20) + await nvim.command(`b ${buf.id}`) + await item.waitRefresh() + expect(item.highlights).toBeDefined() + }) + + it('should reuse exists tokens when version not changed', async () => { + let doc = await helper.createDocument('t.vim') + await doc.applyEdits([{ range: Range.create(0, 0, 0, 0), newText: 'let' }]) + let fn = jest.fn() + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + disposables.push(languages.registerDocumentSemanticTokensProvider([{ language: 'vim' }], { + provideDocumentSemanticTokens: () => { + fn() + return new Promise(resolve => { + resolve({ + resultId: '1', + data: [0, 0, 3, 1, 0] + }) + }) + } + }, legend)) + let item = await highlighter.getCurrentItem() + item.cancel() + await item.doHighlight() + await item.doHighlight() + expect(fn).toBeCalledTimes(1) + }) + + it('should only highlight limited range on update', async () => { + let doc = await helper.createDocument('t.vim') + let fn = jest.fn() + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + disposables.push(languages.registerDocumentSemanticTokensProvider([{ language: 'vim' }], { + provideDocumentSemanticTokens: (doc, token) => { + let text = doc.getText() + if (!text.trim()) { + return Promise.resolve({ resultId: '1', data: [] }) + } + fn() + let lines = text.split('\n') + let data = [0, 0, 1, 1, 0] + for (let i = 0; i < lines.length; i++) { + data.push(1, 0, 1, 1, 0) + } + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timer) + resolve(undefined) + }) + let timer = setTimeout(() => { + resolve({ resultId: '1', data }) + }, 50) + }) + } + }, legend)) + let item = await highlighter.getCurrentItem() + await item.doHighlight() + let newLine = 'l\n' + await doc.applyEdits([{ range: Range.create(0, 0, 0, 0), newText: `${newLine.repeat(2000)}` }]) + await item.doHighlight() + await item.waitRefresh() + expect(fn).toBeCalled() + let buf = nvim.createBuffer(doc.bufnr) + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + let len = markers.length + expect(len).toBeLessThan(400) + await nvim.command('normal! gg') + await helper.wait(50) + await nvim.command('normal! 200G') + await helper.wait(50) + markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBeGreaterThan(len) + }) + + it('should highlight hidden buffer on shown', async () => { + helper.updateConfiguration('semanticTokens.filetypes', ['rust']) + registerProvider() + let code = 'fn main() {\n println!("H"); \n}' + let filepath = path.join(os.tmpdir(), 'a.rs') + fs.writeFileSync(filepath, code, 'utf8') + let uri = URI.file(filepath).toString() + await workspace.loadFile(uri) + let doc = workspace.getDocument(uri) + let item = highlighter.getItem(doc.bufnr) + let fn = jest.fn() + item.onDidRefresh(() => { + fn() + }) + let buf = doc.buffer + await helper.wait(10) + expect(doc.filetype).toBe('rust') + expect(fn).toBeCalledTimes(0) + await nvim.command(`b ${buf.id}`) + await helper.wait(50) + expect(fn).toBeCalledTimes(1) + }) + + it('should not highlight on shown when document not changed', async () => { + let fn = jest.fn() + let buf = await createRustBuffer() + let item = await highlighter.getCurrentItem() + await item.waitRefresh() + await nvim.command('enew') + item.doHighlight = async () => { + fn() + } + await nvim.command(`b ${buf.id}`) + await helper.wait(100) + expect(fn).toBeCalledTimes(0) + }) + }) + + describe('clear highlights', () => { + it('should clear highlights of current buffer', async () => { + await createRustBuffer() + await highlighter.highlightCurrent() + let buf = await nvim.buffer + let markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBeGreaterThan(0) + await commandManager.executeCommand('semanticTokens.clearCurrent') + markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBe(0) + }) + + it('should clear all highlights', async () => { + await createRustBuffer() + await highlighter.highlightCurrent() + let buf = await nvim.buffer + await commandManager.executeCommand('semanticTokens.clearAll') + let markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBe(0) + }) + }) + + describe('rangeProvider', () => { + it('should invoke range provider first time when both kinds exist', async () => { + let fn = jest.fn() + disposables.push(registerRangeProvider('rust', () => { + fn() + return [] + })) + let buf = await createRustBuffer() + let item = highlighter.getItem(buf.id) + await item.waitRefresh() + await helper.wait(50) + expect(fn).toBeCalled() + }) + + it('should do range highlight first time', async () => { + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + let r: Range + disposables.push(registerRangeProvider('vim', range => { + r = range + return [0, 0, 3, 1, 0] + })) + let filepath = await createTmpFile('let') + fs.renameSync(filepath, filepath + '.vim') + let doc = await helper.createDocument(filepath + '.vim') + expect(doc.filetype).toBe('vim') + await helper.waitValue(() => { + return typeof r !== 'undefined' + }, true) + }) + + it('should do range highlight after cursor moved', async () => { + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + let doc = await helper.createDocument('t.vim') + let r: Range + expect(doc.filetype).toBe('vim') + await nvim.call('setline', [2, (new Array(200).fill(''))]) + await doc.applyEdits([{ range: Range.create(0, 0, 0, 0), newText: 'let' }]) + await helper.wait(50) + disposables.push(registerRangeProvider('vim', range => { + r = range + return [] + })) + await nvim.command('normal! G') + await helper.wait(100) + expect(r).toBeDefined() + expect(r.end).toEqual({ line: 201, character: 0 }) + }) + + it('should only cancel range highlight request', async () => { + let rangeCancelled = false + disposables.push(languages.registerDocumentRangeSemanticTokensProvider([{ language: 'vim' }], { + provideDocumentRangeSemanticTokens: (_, range, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timeout) + rangeCancelled = true + resolve(null) + }) + let timeout = setTimeout(() => { + resolve({ data: [] }) + }, 500) + }) + } + }, legend)) + disposables.push(languages.registerDocumentSemanticTokensProvider([{ language: 'vim' }], { + provideDocumentSemanticTokens: (_, token) => { + return new Promise(resolve => { + resolve({ + resultId: '1', + data: [0, 0, 3, 1, 0] + }) + }) + } + }, legend)) + let doc = await helper.createDocument('t.vim') + await doc.applyEdits([{ range: Range.create(0, 0, 0, 0), newText: 'let' }]) + let item = await highlighter.getCurrentItem() + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + item.cancel() + let p = item.doHighlight() + await helper.wait(10) + item.cancel(true) + await p + }) + }) + + describe('triggerSemanticTokens', () => { + it('should be disabled by default', async () => { + helper.updateConfiguration('semanticTokens.filetypes', []) + await workspace.document + const curr = await highlighter.getCurrentItem() + expect(curr.enabled).toBe(false) + }) + + it('should be enabled', async () => { + await createRustBuffer() + const curr = await highlighter.getCurrentItem() + expect(curr.enabled).toBe(true) + }) + + it('should get legend by API', async () => { + await createRustBuffer() + const doc = await workspace.document + const l = languages.getLegend(doc.textDocument) + expect(l).toEqual(legend) + }) + + it('should doHighlight', async () => { + await createRustBuffer() + const doc = await workspace.document + await nvim.call('CocAction', 'semanticHighlight') + const highlights = await nvim.call("coc#highlight#get_highlights", [doc.bufnr, 'semanticTokens']) + expect(highlights.length).toBeGreaterThan(0) + expect(highlights[0][0]).toBe('CocSemKeyword') + }) + }) + + describe('delta update', () => { + it('should perform highlight update', async () => { + await createRustBuffer() + let buf = await nvim.buffer + await highlighter.highlightCurrent() + await window.moveTo({ line: 0, character: 0 }) + let doc = await workspace.document + await nvim.input('if') + await helper.wait(50) + await doc.synchronize() + let curr = await highlighter.getCurrentItem() + await curr.forceHighlight() + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBeGreaterThan(0) + }) + }) + + describe('checkState', () => { + it('should throw for invalid state', async () => { + let doc = await workspace.document + const toThrow = (cb: () => void) => { + expect(cb).toThrow(Error) + } + let item = highlighter.getItem(doc.bufnr) + toThrow(() => { + item.checkState() + }) + helper.updateConfiguration('semanticTokens.filetypes', ['*']) + toThrow(() => { + item.checkState() + }) + toThrow(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + workspace._env.updateHighlight = false + item.checkState() + }) + let enabled = item.enabled + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + workspace._env.updateHighlight = true + expect(enabled).toBe(false) + doc.detach() + toThrow(() => { + item.checkState() + }) + }) + }) + + describe('enabled', () => { + it('should check if buffer enabled for semanticTokens', async () => { + let doc = await workspace.document + let item = highlighter.getItem(doc.bufnr) + disposables.push(languages.registerDocumentRangeSemanticTokensProvider([{ language: '*' }], { + provideDocumentRangeSemanticTokens: (_, range) => { + return { + data: [] + } + } + }, { tokenModifiers: [], tokenTypes: [] })) + expect(item.enabled).toBe(false) + helper.updateConfiguration('semanticTokens.filetypes', ['vim']) + expect(item.enabled).toBe(false) + helper.updateConfiguration('semanticTokens.filetypes', ['*']) + expect(item.enabled).toBe(true) + doc.detach() + expect(item.enabled).toBe(false) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/signature.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/signature.test.ts new file mode 100644 index 00000000..e7b656f7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/signature.test.ts @@ -0,0 +1,369 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable, ParameterInformation, SignatureInformation } from 'vscode-languageserver-protocol' +import Signature from '../../handler/signature' +import languages from '../../languages' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +let signature: Signature +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + signature = helper.plugin.getHandler().signature +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('signatureHelp', () => { + + describe('triggerSignatureHelp', () => { + it('should show signature by api', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, [])) + await helper.createDocument() + await nvim.input('foo') + await signature.triggerSignatureHelp() + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines[2]).toMatch('my signature') + }) + + it('should use 0 when activeParameter is undefined', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo(a)', 'my signature', { label: 'a' })], + activeParameter: undefined, + activeSignature: null + } + } + }, [])) + await helper.createDocument() + await nvim.input('foo') + await signature.triggerSignatureHelp() + let win = await helper.getFloat() + expect(win).toBeDefined() + let highlights = await win.getVar('highlights') + expect(highlights).toBeDefined() + expect(highlights[0].hlGroup).toBe('CocUnderline') + }) + + it('should trigger by space', async () => { + let promise = new Promise(resolve => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + resolve(undefined) + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, [' '])) + }) + await helper.createDocument() + await nvim.input('i') + await helper.wait(30) + await nvim.input(' ') + await promise + }) + + it('should show signature help with param label as string', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [ + SignatureInformation.create('foo()', 'my signature'), + SignatureInformation.create('foo(a, b)', 'my signature', ParameterInformation.create('a', 'description')), + ], + activeParameter: 0, + activeSignature: 1 + } + } + }, [])) + await helper.createDocument() + await nvim.input('foo') + await signature.triggerSignatureHelp() + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines.join('\n')).toMatch(/description/) + }) + }) + + describe('events', () => { + it('should trigger signature help', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo(x, y)', 'my signature')], + activeParameter: 0, + activeSignature: 0 + } + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('foo') + await nvim.input('(') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines[2]).toMatch('my signature') + }) + + it('should cancel trigger on InsertLeave', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: async (_doc, _position, token) => { + return new Promise(resolve => { + let timer = setTimeout(() => { + resolve({ + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + }) + }, 1000) + token.onCancellationRequested(() => { + clearTimeout(timer) + resolve(undefined) + }) + }) + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('foo') + let p = signature.triggerSignatureHelp() + await helper.wait(10) + await nvim.command('stopinsert') + await nvim.call('feedkeys', [String.fromCharCode(27), 'in']) + let res = await p + expect(res).toBe(false) + }) + + it('should not close signature on type', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('foo(') + await helper.wait(100) + await nvim.input('bar') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines[2]).toMatch('my signature') + }) + + it('should close signature float when empty signatures returned', async () => { + let empty = false + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + if (empty) return undefined + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('foo(') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeDefined() + empty = true + await signature.triggerSignatureHelp() + await helper.wait(50) + let res = await nvim.call('coc#float#valid', [win.id]) + expect(res).toBe(0) + }) + }) + + describe('float window', () => { + it('should align signature window to top', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + let buf = await nvim.buffer + await buf.setLines(['', '', '', '', ''], { start: 0, end: -1, strictIndexing: true }) + await nvim.call('cursor', [5, 1]) + await nvim.input('foo(') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines[2]).toMatch('my signature') + let res = await nvim.call('GetFloatCursorRelative', [win.id]) as any + expect(res.row).toBeLessThan(0) + }) + + it('should show parameter docs', async () => { + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo(a, b)', 'my signature', + ParameterInformation.create('a', 'foo'), + ParameterInformation.create([7, 8], 'bar'))], + activeParameter: 1, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + let buf = await nvim.buffer + await buf.setLines(['', '', '', '', ''], { start: 0, end: -1, strictIndexing: true }) + await nvim.call('cursor', [5, 1]) + await nvim.input('foo(a,') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeDefined() + let lines = await helper.getWinLines(win.id) + expect(lines.join('\n')).toMatch('bar') + }) + }) + + describe('configurations', () => { + let { configurations } = workspace + afterEach(() => { + configurations.updateUserConfig({ + 'signature.target': 'float', + 'signature.hideOnTextChange': false, + 'signature.enable': true, + 'signature.triggerSignatureWait': 500 + }) + }) + + it('should cancel signature on timeout', async () => { + configurations.updateUserConfig({ 'signature.triggerSignatureWait': 50 }) + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position, token) => { + return new Promise(resolve => { + token.onCancellationRequested(() => { + clearTimeout(timer) + resolve(undefined) + }) + let timer = setTimeout(() => { + resolve({ + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + }) + }, 200) + }) + } + }, ['(', ','])) + await helper.createDocument() + await signature.triggerSignatureHelp() + let win = await helper.getFloat() + expect(win).toBeUndefined() + configurations.updateUserConfig({ 'signature.triggerSignatureWait': 100 }) + }) + + it('should hide signature window on text change', async () => { + configurations.updateUserConfig({ 'signature.hideOnTextChange': true }) + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('ifoo(') + let winid = await helper.waitFloat() + await nvim.input('x') + await helper.wait(100) + let res = await nvim.call('coc#float#valid', [winid]) + expect(res).toBe(0) + configurations.updateUserConfig({ 'signature.hideOnTextChange': false }) + }) + + it('should disable signature help trigger', async () => { + configurations.updateUserConfig({ 'signature.enable': false }) + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo()', 'my signature')], + activeParameter: null, + activeSignature: null + } + } + }, ['(', ','])) + await helper.createDocument() + await nvim.input('foo') + await nvim.input('(') + await helper.wait(100) + let win = await helper.getFloat() + expect(win).toBeUndefined() + }) + + it('should echo simple signature help', async () => { + let idx = 0 + let activeSignature = null + configurations.updateUserConfig({ 'signature.target': 'echo' }) + disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], { + provideSignatureHelp: (_doc, _position) => { + return { + signatures: [SignatureInformation.create('foo(a, b)', 'my signature', + ParameterInformation.create('a', 'foo'), + ParameterInformation.create([7, 8], 'bar')), + SignatureInformation.create('a'.repeat(workspace.env.columns + 10)) + ], + activeParameter: idx, + activeSignature + } + } + }, [])) + await helper.createDocument() + await nvim.input('foo(') + await signature.triggerSignatureHelp() + let line = await helper.getCmdline() + expect(line).toMatch('(a, b)') + await nvim.input('a,') + idx = 1 + await signature.triggerSignatureHelp() + line = await helper.getCmdline() + expect(line).toMatch('foo(a, b)') + activeSignature = 1 + await signature.triggerSignatureHelp() + line = await helper.getCmdline() + expect(line).toMatch('aaaaaa') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/symbols.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/symbols.test.ts new file mode 100644 index 00000000..ecaeaebb --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/symbols.test.ts @@ -0,0 +1,280 @@ +import { Buffer, Neovim } from '@chemzqm/neovim' +import { Disposable, SymbolInformation, SymbolKind, Range } from 'vscode-languageserver-protocol' +import Symbols from '../../handler/symbols/index' +import languages from '../../languages' +import workspace from '../../workspace' +import window from '../../window' +import events from '../../events' +import { disposeAll } from '../../util' +import helper from '../helper' +import Parser from './parser' + +let nvim: Neovim +let symbols: Symbols +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + symbols = helper.plugin.getHandler().symbols +}) + +beforeEach(() => { + disposables.push(languages.registerDocumentSymbolProvider([{ language: 'javascript' }], { + provideDocumentSymbols: document => { + let text = document.getText() + let parser = new Parser(text, text.includes('detail')) + let res = parser.parse() + return Promise.resolve(res) + } + })) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + disposables = [] + await helper.reset() +}) + +describe('Parser', () => { + it('should parse content', async () => { + let code = `class myClass { + fun1() { } + }` + let parser = new Parser(code) + let res = parser.parse() + expect(res.length).toBeGreaterThan(0) + }) +}) + +describe('symbols handler', () => { + + async function createBuffer(code: string): Promise { + let buf = await nvim.buffer + await nvim.command('setf javascript') + await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false }) + let doc = await workspace.document + doc.forceSync() + return buf + } + + describe('configuration', () => { + it('should get configuration', async () => { + let functionUpdate = symbols.functionUpdate + expect(functionUpdate).toBe(false) + helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', true) + functionUpdate = symbols.functionUpdate + expect(functionUpdate).toBe(true) + }) + + it('should update symbols automatically', async () => { + helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', true) + let code = `class myClass { + fun1() { + } + }` + let buf = await createBuffer(code) + await nvim.call('cursor', [2, 8]) + await events.fire('CursorHold', [buf.id]) + let val = await buf.getVar('coc_current_function') + expect(val).toBe('fun1') + await nvim.call('cursor', [1, 8]) + await events.fire('CursorHold', [buf.id]) + val = await buf.getVar('coc_current_function') + expect(val).toBe('myClass') + }) + }) + + describe('documentSymbols', () => { + it('should get symbols of current buffer', async () => { + let code = `class detail { + fun1() { } + }` + await createBuffer(code) + let res = await helper.plugin.cocAction('documentSymbols') + expect(res.length).toBe(2) + expect(res[1].detail).toBeDefined() + }) + + it('should get current function symbols', async () => { + let code = `class myClass { + fun1() { + } + fun2() { + } + } + ` + await createBuffer(code) + await nvim.call('cursor', [3, 0]) + let res = await helper.doAction('getCurrentFunctionSymbol') + expect(res).toBe('fun1') + await nvim.command('normal! G') + res = await helper.doAction('getCurrentFunctionSymbol') + expect(res).toBe('') + }) + + it('should reset coc_current_function when symbols do not exist', async () => { + let code = `class myClass { + fun1() { + } + }` + await createBuffer(code) + await nvim.call('cursor', [3, 0]) + let res = await helper.doAction('getCurrentFunctionSymbol') + expect(res).toBe('fun1') + await nvim.command('normal! ggdG') + res = await symbols.getCurrentFunctionSymbol() + expect(res).toBe('') + }) + + it('should support SymbolInformation', async () => { + disposables.push(languages.registerDocumentSymbolProvider(['*'], { + provideDocumentSymbols: () => { + return [ + SymbolInformation.create('root', SymbolKind.Function, Range.create(0, 0, 0, 10)), + SymbolInformation.create('child', SymbolKind.Function, Range.create(0, 0, 0, 10), '', 'root') + ] + } + })) + await helper.createDocument() + let res = await symbols.getDocumentSymbols() + expect(res.length).toBe(2) + expect(res[0].text).toBe('root') + expect(res[1].text).toBe('child') + }) + }) + + describe('selectSymbolRange', () => { + it('should show warning when no symbols exist', async () => { + disposables.push(languages.registerDocumentSymbolProvider(['*'], { + provideDocumentSymbols: () => { + return [] + } + })) + await helper.createDocument() + await nvim.call('cursor', [3, 0]) + await symbols.selectSymbolRange(false, '', ['Function']) + let msg = await helper.getCmdline() + expect(msg).toMatch(/No symbols found/) + }) + + it('should select symbol range at cursor position', async () => { + let code = `class myClass { + fun1() { + } + }` + await createBuffer(code) + await nvim.call('cursor', [3, 0]) + await helper.doAction('selectSymbolRange', false, '', ['Function', 'Method']) + let mode = await nvim.mode + expect(mode.mode).toBe('v') + await nvim.input('') + let res = await window.getSelectedRange('v') + expect(res).toEqual({ start: { line: 1, character: 6 }, end: { line: 2, character: 6 } }) + }) + + it('should select inner range', async () => { + let code = `class myClass { + fun1() { + let foo; + } +}` + let buf = await createBuffer(code) + await nvim.call('cursor', [3, 3]) + await symbols.selectSymbolRange(true, '', ['Method']) + let mode = await nvim.mode + expect(mode.mode).toBe('v') + await nvim.input('') + let res = await window.getSelectedRange('v') + expect(res).toEqual({ + start: { line: 2, character: 8 }, end: { line: 2, character: 16 } + }) + }) + + it('should reset visualmode when selection not found', async () => { + let code = `class myClass {}` + await createBuffer(code) + await nvim.call('cursor', [1, 1]) + await nvim.command('normal! gg0v$') + let mode = await nvim.mode + expect(mode.mode).toBe('v') + await nvim.input('') + await symbols.selectSymbolRange(true, 'v', ['Method']) + mode = await nvim.mode + expect(mode.mode).toBe('v') + }) + + it('should select symbol range from select range', async () => { + let code = `class myClass { + fun1() { + } + }` + let buf = await createBuffer(code) + await nvim.call('cursor', [2, 8]) + await nvim.command('normal! viw') + await nvim.input('') + await helper.doAction('selectSymbolRange', false, 'v', ['Class']) + let mode = await nvim.mode + expect(mode.mode).toBe('v') + let doc = workspace.getDocument(buf.id) + await nvim.input('') + let res = await window.getSelectedRange('v') + expect(res).toEqual({ start: { line: 0, character: 0 }, end: { line: 3, character: 4 } }) + }) + }) + + describe('cancel', () => { + it('should cancel symbols request on insert', async () => { + let cancelled = false + disposables.push(languages.registerDocumentSymbolProvider([{ language: 'text' }], { + provideDocumentSymbols: (_doc, token) => { + return new Promise(s => { + token.onCancellationRequested(() => { + if (timer) clearTimeout(timer) + cancelled = true + s(undefined) + }) + let timer = setTimeout(() => { + s(undefined) + }, 3000) + }) + } + })) + let doc = await helper.createDocument('t.txt') + let p = symbols.getDocumentSymbols(doc.bufnr) + setTimeout(async () => { + await nvim.input('i') + }, 500) + await p + expect(cancelled).toBe(true) + }) + }) + + describe('workspaceSymbols', () => { + it('should get workspace symbols', async () => { + disposables.push(languages.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols: (_query, _token) => { + return [SymbolInformation.create('far', SymbolKind.Class, Range.create(0, 0, 0, 0))] + }, + resolveWorkspaceSymbol: sym => { + let res = Object.assign({}, sym) + res.location.uri = 'test:///foo' + return res + } + })) + disposables.push(languages.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols: (_query, _token) => { + return [SymbolInformation.create('bar', SymbolKind.Function, Range.create(0, 0, 0, 0))] + } + })) + let res = await symbols.getWorkspaceSymbols('a') + expect(res.length).toBe(2) + let resolved = await symbols.resolveWorkspaceSymbol(res[0]) + expect(resolved?.location?.uri).toBe('test:///foo') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/handler/workspace.test.ts b/sources_non_forked/coc.nvim/src/__tests__/handler/workspace.test.ts new file mode 100644 index 00000000..9990db65 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/handler/workspace.test.ts @@ -0,0 +1,99 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import WorkspaceHandler from '../../handler/workspace' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import extensions from '../../extensions' +import helper from '../helper' + +let nvim: Neovim +let handler: WorkspaceHandler +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + handler = helper.plugin.getHandler().workspace +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('Workspace handler', () => { + describe('methods', () => { + it('should open log', async () => { + await handler.openLog() + let bufname = await nvim.call('bufname', ['%']) as string + expect(bufname.endsWith('coc-nvim.log')).toBe(true) + }) + + it('should get configuration of current document', async () => { + let config = await handler.getConfiguration('suggest') + let wait = config.get('triggerCompletionWait') + expect(wait).toBe(0) + }) + + it('should get root patterns', async () => { + let doc = await helper.createDocument() + let patterns = handler.getRootPatterns(doc.bufnr) + expect(patterns).toBeDefined() + }) + }) + + describe('doKeymap()', () => { + it('should return default value when key mapping does not exist', async () => { + let res = await handler.doKeymap('not_exists', '', ' { + let called = false + await nvim.command('nmap do (coc-test)') + disposables.push(workspace.registerKeymap(['n'], 'test', () => { + called = true + }, { repeat: true, silent: true, sync: false })) + await helper.wait(100) + await nvim.call('feedkeys', ['do', 'i']) + await helper.wait(30) + expect(called).toBe(true) + }) + }) + + describe('snippetCheck()', () => { + it('should return false when coc-snippets not found', async () => { + expect(await handler.snippetCheck(true, false)).toBe(false) + }) + + it('should check jump', async () => { + expect(await handler.snippetCheck(false, true)).toBe(false) + }) + + it('should check expand by coc-snippets', async () => { + let has = extensions.has + let getExtensionApi = extensions.getExtensionApi + extensions.has = () => { + return true + } + extensions.getExtensionApi = () => { + return { + expandable: () => { + return true + } + } + } + disposables.push({ + dispose: () => { + extensions.has = has + extensions.getExtensionApi = getExtensionApi + } + }) + let res = await handler.snippetCheck(true, false) + expect(res).toBe(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/helper.test.ts b/sources_non_forked/coc.nvim/src/__tests__/helper.test.ts new file mode 100644 index 00000000..2c1e10ed --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/helper.test.ts @@ -0,0 +1,22 @@ +import { Neovim } from '@chemzqm/neovim' +import Plugin from '../plugin' +import helper from './helper' + +let nvim: Neovim +let plugin: Plugin +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + plugin = helper.plugin +}) + +describe('Helper', () => { + it('should setup', () => { + expect(nvim).toBeTruthy() + expect(plugin.isReady).toBeTruthy() + }) +}) + +afterAll(async () => { + await helper.shutdown() +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/helper.ts b/sources_non_forked/coc.nvim/src/__tests__/helper.ts new file mode 100644 index 00000000..167b3fd5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/helper.ts @@ -0,0 +1,360 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import { Buffer, Neovim, Window } from '@chemzqm/neovim' +import * as cp from 'child_process' +import { EventEmitter } from 'events' +import fs from 'fs' +import os from 'os' +import path from 'path' +import util from 'util' +import { v4 as uuid } from 'uuid' +import { Disposable } from 'vscode-languageserver-protocol' +import attach from '../attach' +import completion from '../completion' +import events from '../events' +import Document from '../model/document' +import Plugin from '../plugin' +import { OutputChannel, VimCompleteItem } from '../types' +import { terminate } from '../util/processes' +import workspace from '../workspace' + +export interface CursorPosition { + bufnum: number + lnum: number + col: number +} + +const nullChannel: OutputChannel = { + content: '', + show: () => {}, + dispose: () => {}, + name: 'null', + append: () => {}, + appendLine: () => {}, + clear: () => {}, + hide: () => {} +} + +process.on('uncaughtException', err => { + let msg = 'Uncaught exception: ' + err.stack + console.error(msg) +}) +export class Helper extends EventEmitter { + public nvim: Neovim + public proc: cp.ChildProcess + public plugin: Plugin + + constructor() { + super() + this.setMaxListeners(99) + } + + public setupNvim(): void { + const vimrc = path.resolve(__dirname, 'vimrc') + let proc = this.proc = cp.spawn(process.env.COC_TEST_NVIM ?? 'nvim', ['-u', vimrc, '-i', 'NONE', '--embed'], { + cwd: __dirname + }) + let plugin = attach({ proc }) + this.nvim = plugin.nvim + } + + public setup(): Promise { + const vimrc = path.resolve(__dirname, 'vimrc') + let proc = this.proc = cp.spawn('nvim', ['-u', vimrc, '-i', 'NONE', '--embed'], { + cwd: __dirname + }) + let plugin = this.plugin = attach({ proc }) + this.nvim = plugin.nvim + this.nvim.uiAttach(160, 80, {}).catch(e => { + console.error(e) + }) + this.nvim.on('notification', (method, args) => { + if (method == 'redraw') { + for (let arg of args) { + let event = arg[0] + this.emit(event, arg.slice(1)) + if (event == 'put') { + let arr = arg.slice(1).map(o => o[0]) + let line = arr.join('').trim() + if (line.length > 3) { + // console.log(line) + } + } + } + } + }) + return new Promise(resolve => { + plugin.once('ready', resolve) + }) + } + + public async shutdown(): Promise { + if (this.plugin) this.plugin.dispose() + this.nvim.removeAllListeners() + this.nvim = null + if (this.proc) { + this.proc.unref() + terminate(this.proc) + this.proc = null + } + await this.wait(60) + } + + public async waitPopup(): Promise { + let visible = await this.nvim.call('pumvisible') + if (visible) return + let res = await events.race(['MenuPopupChanged'], 5000) + if (!res) throw new Error('wait pum timeout after 5s') + } + + public async waitPreviewWindow(): Promise { + for (let i = 0; i < 40; i++) { + await this.wait(50) + let has = await this.nvim.call('coc#list#has_preview') + if (has > 0) return + } + throw new Error('timeout after 2s') + } + + public async waitPrompt(): Promise { + for (let i = 0; i < 40; i++) { + await this.wait(50) + let prompt = await this.nvim.call('coc#prompt#activated') + if (prompt) return + } + throw new Error('Wait prompt timeout after 2s') + } + + public async waitFloat(): Promise { + for (let i = 0; i < 50; i++) { + await this.wait(20) + let winid = await this.nvim.call('GetFloatWin') + if (winid) return winid + } + throw new Error('timeout after 2s') + } + + public async selectCompleteItem(idx: number): Promise { + await this.nvim.call('nvim_select_popupmenu_item', [idx, true, true, {}]) + } + + public async doAction(method: string, ...args: any[]): Promise { + return await this.plugin.cocAction(method, ...args) + } + + public async synchronize(): Promise { + let doc = await workspace.document + doc.forceSync() + } + + public async reset(): Promise { + let mode = await this.nvim.mode + if (mode.blocking && mode.mode == 'r') { + await this.nvim.input('') + } else if (mode.mode != 'n' || mode.blocking) { + await this.nvim.call('feedkeys', [String.fromCharCode(27), 'in']) + } + completion.stop() + workspace.reset() + await this.nvim.command('silent! %bwipeout!') + await this.nvim.command('setl nopreviewwindow') + await this.wait(30) + await workspace.document + } + + public async pumvisible(): Promise { + let res = await this.nvim.call('pumvisible', []) as number + return res == 1 + } + + public wait(ms = 30): Promise { + return new Promise(resolve => { + setTimeout(() => { + resolve() + }, ms) + }) + } + + public async visible(word: string, source?: string): Promise { + await this.waitPopup() + let context = await this.nvim.getVar('coc#_context') as any + let items = context.candidates + if (!items) return false + let item = items.find(o => o.word == word) + if (!item || !item.user_data) return false + try { + let arr = item.user_data.split(':', 2) + if (source && arr[0] !== source) { + return false + } + } catch (e) { + return false + } + return true + } + + public async notVisible(word: string): Promise { + let items = await this.getItems() + return items.findIndex(o => o.word == word) == -1 + } + + public async getItems(): Promise { + let visible = await this.pumvisible() + if (!visible) return [] + let context = await this.nvim.getVar('coc#_context') as any + let items = context.candidates + return items || [] + } + + public async edit(file?: string): Promise { + if (!file || !path.isAbsolute(file)) { + file = path.join(__dirname, file ? file : `${uuid()}`) + } + let escaped = await this.nvim.call('fnameescape', file) as string + await this.nvim.command(`edit ${escaped}`) + let doc = await workspace.document + return doc.buffer + } + + public async createDocument(name?: string): Promise { + let buf = await this.edit(name) + let doc = workspace.getDocument(buf.id) + if (!doc) return await workspace.document + return doc + } + + public async listInput(input: string): Promise { + await events.fire('InputChar', ['list', input, 0]) + } + + public async getMarkers(bufnr: number, ns: number): Promise<[number, number, number][]> { + return await this.nvim.call('nvim_buf_get_extmarks', [bufnr, ns, 0, -1, {}]) as [number, number, number][] + } + + public async getCmdline(): Promise { + let str = '' + for (let i = 1, l = 70; i < l; i++) { + let ch = await this.nvim.call('screenchar', [79, i]) + if (ch == -1) break + str += String.fromCharCode(ch) + } + return str.trim() + } + + public updateConfiguration(key: string, value: any): () => void { + let { configurations } = workspace + let curr = workspace.getConfiguration(key) + configurations.updateUserConfig({ [key]: value }) + return () => { + configurations.updateUserConfig({ [key]: curr }) + } + } + + public async mockFunction(name: string, result: string | number | any): Promise { + let content = ` + function! ${name}(...) + return ${typeof result == 'number' ? result : JSON.stringify(result)} + endfunction` + await this.nvim.exec(content) + } + + public async items(): Promise { + let context = await this.nvim.getVar('coc#_context') + return context['candidates'] || [] + } + + public async screenLine(line: number): Promise { + let res = '' + for (let i = 1; i <= 80; i++) { + let ch = await this.nvim.call('screenchar', [line, i]) + res = res + String.fromCharCode(ch) + } + return res + } + + public async getWinLines(winid: number): Promise { + return await this.nvim.eval(`getbufline(winbufnr(${winid}), 1, '$')`) as string[] + } + + public async getFloat(): Promise { + let wins = await this.nvim.windows + let floatWin: Window + for (let win of wins) { + let f = await win.getVar('float') + if (f) floatWin = win + } + return floatWin + } + + public async getFloats(): Promise { + let ids = await this.nvim.call('coc#float#get_float_win_list', []) + if (!ids) return [] + return ids.map(id => this.nvim.createWindow(id)) + } + + public async getExtmarkers(bufnr: number, ns: number): Promise<[number, number, number, number, string][]> { + let res = await this.nvim.call('nvim_buf_get_extmarks', [bufnr, ns, 0, -1, { details: true }]) as any + return res.map(o => { + return [o[1], o[2], o[3].end_row, o[3].end_col, o[3].hl_group] + }) + } + + public async waitFor(method: string, args: any[], value: T): Promise { + let find = false + for (let i = 0; i < 40; i++) { + await this.wait(50) + let res = await this.nvim.call(method, args) as T + if (res == value || (value instanceof RegExp && value.test(res.toString()))) { + find = true + break + } + } + if (!find) { + throw new Error(`waitFor ${value} timeout`) + } + } + + public async waitValue(fn: () => T, value: T): Promise { + let find = false + for (let i = 0; i < 40; i++) { + await this.wait(50) + let res = fn() + if (res == value) { + find = true + break + } + } + if (!find) { + throw new Error(`waitValue ${value} timeout`) + } + } + + public createNullChannel(): OutputChannel { + return nullChannel + } +} + +export function rmdir(dir: string): void { + if (typeof fs['rm'] === 'function') { + fs['rmSync'](dir, { recursive: true }) + } else { + fs.rmdirSync(dir, { recursive: true }) + } +} + +export async function createTmpFile(content: string, disposables?: Disposable[]): Promise { + let tmpFolder = path.join(os.tmpdir(), `coc-${process.pid}`) + if (!fs.existsSync(tmpFolder)) { + fs.mkdirSync(tmpFolder) + } + let fsPath = path.join(tmpFolder, uuid()) + await util.promisify(fs.writeFile)(fsPath, content, 'utf8') + if (disposables) { + disposables.push(Disposable.create(() => { + if (fs.existsSync(fsPath)) fs.unlinkSync(fsPath) + })) + } + return fsPath +} + +export default new Helper() diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/commandTask.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/commandTask.test.ts new file mode 100644 index 00000000..1acd9ff0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/commandTask.test.ts @@ -0,0 +1,136 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { ListContext, ListTask } from '../../types' +import manager from '../../list/manager' +import helper, { createTmpFile } from '../helper' +import BasicList from '../../list/basic' +import { Disposable } from 'vscode-languageserver-protocol' +import { disposeAll } from '../../util' + +class DataList extends BasicList { + public name = 'data' + public async loadItems(_context: ListContext): Promise { + let fsPath = await createTmpFile(`console.log('foo');console.log('');console.log('bar');`) + return this.createCommandTask({ + cmd: 'node', + args: [fsPath], + cwd: path.dirname(fsPath), + onLine: line => { + if (!line) return undefined + return { + label: line + } + } + }) + } +} + +class SleepList extends BasicList { + public name = 'sleep' + public loadItems(_context: ListContext): Promise { + return Promise.resolve(this.createCommandTask({ + cmd: 'sleep', + args: ['10'], + onLine: line => { + return { + label: line + } + } + })) + } +} + +class StderrList extends BasicList { + public name = 'stderr' + public async loadItems(_context: ListContext): Promise { + let fsPath = await createTmpFile(`console.error('stderr');console.log('stdout')`) + return Promise.resolve(this.createCommandTask({ + cmd: 'node', + args: [fsPath], + cwd: path.dirname(fsPath), + onLine: line => { + return { + label: line + } + } + })) + } +} + +class ErrorTask extends BasicList { + public name = 'error' + public async loadItems(_context: ListContext): Promise { + return Promise.resolve(this.createCommandTask({ + cmd: 'NOT_EXISTS', + args: [], + cwd: __dirname, + onLine: line => { + return { + label: line + } + } + })) + } +} + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + manager.reset() + await helper.reset() +}) + +describe('Command task', () => { + it('should not show stderr', async () => { + disposables.push(manager.registerList(new StderrList(nvim))) + await manager.start(['stderr']) + await manager.session.ui.ready + let lines = await nvim.call('getline', [1, '$']) as string[] + expect(lines).toEqual(['stdout']) + }) + + it('should show error for bad key', async () => { + let list = new DataList(nvim) + list.config.fixKey('') + await helper.wait(200) + await nvim.command('redraw') + let msg = await helper.getCmdline() + expect(msg).toMatch('not supported') + }) + + it('should not show error', async () => { + disposables.push(manager.registerList(new ErrorTask(nvim))) + await manager.start(['error']) + await helper.wait(300) + await nvim.command('redraw') + let len = manager.session.ui.length + expect(len).toBe(0) + }) + + it('should create command task', async () => { + let list = new DataList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['data']) + await manager.session.ui.ready + await helper.wait(100) + let lines = await nvim.call('getline', [1, '$']) as string[] + expect(lines).toEqual(['foo', 'bar']) + }) + + it('should stop command task', async () => { + let list = new SleepList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['sleep']) + manager.session.stop() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/manager.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/manager.test.ts new file mode 100644 index 00000000..adfd4497 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/manager.test.ts @@ -0,0 +1,508 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import manager from '../../list/manager' +import events from '../../events' +import { QuickfixItem, IList, ListItem } from '../../types' +import helper from '../helper' + +let nvim: Neovim +const locations: ReadonlyArray = [{ + filename: __filename, + col: 2, + lnum: 1, + text: 'foo' +}, { + filename: __filename, + col: 1, + lnum: 2, + text: 'Bar' +}, { + filename: __filename, + col: 1, + lnum: 3, + text: 'option' +}] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + await nvim.setVar('coc_jump_locations', locations) +}) + +afterEach(async () => { + manager.reset() + await helper.reset() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('list', () => { + describe('events', () => { + it('should cancel and enable prompt', async () => { + let winid = await nvim.call('win_getid') + await manager.start(['location']) + await manager.session.ui.ready + await nvim.call('win_gotoid', [winid]) + await helper.wait(50) + let res = await nvim.call('coc#prompt#activated') + expect(res).toBe(0) + await nvim.command('wincmd p') + await helper.wait(50) + res = await nvim.call('coc#prompt#activated') + expect(res).toBe(1) + }) + }) + + describe('list commands', () => { + it('should be activated', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.wait(50) + expect(manager.isActivated).toBe(true) + let line = await nvim.getLine() + expect(line).toMatch(/manager.test.ts/) + }) + + it('should get list names', () => { + let names = manager.names + expect(names.length > 0).toBe(true) + }) + + it('should resume list', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.wait(30) + await nvim.eval('feedkeys("j", "in")') + await helper.wait(30) + let line = await nvim.call('line', '.') + expect(line).toBe(2) + await manager.cancel() + await helper.wait(30) + await manager.resume() + await helper.wait(30) + line = await nvim.call('line', '.') + expect(line).toBe(2) + }) + + it('should not quit list with --no-quit', async () => { + await manager.start(['--normal', '--no-quit', 'location']) + await manager.session.ui.ready + let winnr = await nvim.eval('win_getid()') as number + await manager.doAction() + await helper.wait(100) + let wins = await nvim.windows + let ids = wins.map(o => o.id) + expect(ids).toContain(winnr) + }) + + it('should do default action for first item', async () => { + await manager.start(['--normal', '--first', 'location']) + await helper.wait(300) + let name = await nvim.eval('bufname("%")') as string + let filename = path.basename(__filename) + expect(name.includes(filename)).toBe(true) + let pos = await nvim.eval('getcurpos()') + expect(pos[1]).toBe(1) + expect(pos[2]).toBe(2) + }) + + it('should goto next & previous', async () => { + await manager.start(['location']) + await manager.session?.ui.ready + await helper.wait(60) + await manager.doAction() + await manager.cancel() + let bufname = await nvim.eval('expand("%:p")') + expect(bufname).toMatch('manager.test.ts') + await manager.next() + let line = await nvim.call('line', '.') + expect(line).toBe(2) + await helper.wait(60) + await manager.previous() + line = await nvim.call('line', '.') + expect(line).toBe(1) + }) + + it('should parse arguments', async () => { + await manager.start(['--input=test', '--reverse', '--normal', '--no-sort', '--ignore-case', '--top', '--number-select', '--auto-preview', '--strict', 'location']) + await helper.wait(30) + let opts = manager.session?.listOptions + expect(opts).toEqual({ + reverse: true, + numberSelect: true, + autoPreview: true, + first: false, + input: 'test', + interactive: false, + matcher: 'strict', + ignorecase: true, + position: 'top', + mode: 'normal', + noQuit: false, + sort: false + }) + }) + }) + + describe('list configuration', () => { + it('should change indicator', async () => { + helper.updateConfiguration('list.indicator', '>>') + await manager.start(['location']) + await manager.session.ui.ready + await helper.wait(200) + let line = await helper.getCmdline() + expect(line).toMatch('>>') + }) + + it('should split right for preview window', async () => { + helper.updateConfiguration('list.previewSplitRight', true) + let win = await nvim.window + await manager.start(['location']) + await helper.wait(100) + await manager.doAction('preview') + await helper.wait(100) + manager.prompt.cancel() + await helper.wait(10) + await nvim.call('win_gotoid', [win.id]) + await nvim.command('wincmd l') + let curr = await nvim.window + let isPreview = await curr.getVar('previewwindow') + expect(isPreview).toBe(1) + }) + + it('should toggle selection mode', async () => { + await manager.start(['--normal', 'location']) + await manager.session?.ui.ready + await nvim.input('V') + await helper.wait(30) + await nvim.input('1') + await helper.wait(30) + await nvim.input('j') + await helper.wait(100) + await manager.session?.ui.toggleSelection() + let items = await manager.session?.ui.getItems() + expect(items.length).toBe(2) + }) + + it('should change next/previous keymap', async () => { + helper.updateConfiguration('list.nextKeymap', '') + helper.updateConfiguration('list.previousKeymap', '') + await manager.start(['location']) + await manager.session.ui.ready + await helper.wait(100) + await nvim.eval('feedkeys("\\", "in")') + await helper.wait(100) + let line = await nvim.line + expect(line).toMatch('Bar') + await nvim.eval('feedkeys("\\", "in")') + await helper.wait(100) + line = await nvim.line + expect(line).toMatch('foo') + }) + + it('should respect mouse events', async () => { + async function setMouseEvent(line: number): Promise { + let winid = manager.session?.ui.winid + await nvim.command(`let v:mouse_winid = ${winid}`) + await nvim.command(`let v:mouse_lnum = ${line}`) + await nvim.command(`let v:mouse_col = 1`) + } + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.wait(100) + await setMouseEvent(1) + await manager.onNormalInput('') + await setMouseEvent(2) + await manager.onNormalInput('') + await setMouseEvent(3) + await manager.onNormalInput('') + await helper.wait(100) + let items = await manager.session?.ui.getItems() + expect(items.length).toBe(3) + }) + + it('should toggle preview', async () => { + await manager.start(['--normal', '--auto-preview', 'location']) + await manager.session.ui.ready + await helper.wait(100) + await manager.togglePreview() + await helper.wait(100) + await manager.togglePreview() + await helper.wait(100) + let has = await nvim.call('coc#list#has_preview') + expect(has).toBeGreaterThan(0) + }) + + it('should show help of current list', async () => { + await manager.start(['--normal', '--auto-preview', 'location']) + await helper.wait(200) + await manager.session?.showHelp() + let bufname = await nvim.call('bufname', '%') + expect(bufname).toBe('[LIST HELP]') + }) + + it('should resolve list item', async () => { + let list: IList = { + name: 'test', + actions: [{ + name: 'open', execute: _item => { + // noop + } + }], + defaultAction: 'open', + loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]), + resolveItem: item => { + item.label = item.label.slice(0, 1) + return Promise.resolve(item) + } + } + let disposable = manager.registerList(list) + await manager.start(['--normal', 'test']) + await manager.session.ui.ready + await helper.wait(50) + let line = await nvim.line + expect(line).toBe('f') + disposable.dispose() + }) + }) + + describe('descriptions', () => { + it('should get descriptions', async () => { + let res = manager.descriptions + expect(res).toBeDefined() + expect(res.location).toBeDefined() + }) + }) + + describe('loadItems()', () => { + it('should load items for list', async () => { + let res = await manager.loadItems('location') + expect(res.length).toBeGreaterThan(0) + ; (manager as any).lastSession = undefined + manager.toggleMode() + manager.stop() + }) + }) + + describe('onInsertInput()', () => { + it('should handle insert input', async () => { + await manager.onInsertInput('k') + await manager.onInsertInput('') + await manager.start(['--number-select', 'location']) + await manager.session.ui.ready + await manager.onInsertInput('1') + await helper.wait(300) + let bufname = await nvim.call('expand', ['%:p']) + expect(bufname).toMatch('manager.test.ts') + }) + + it('should ignore invalid input', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await manager.onInsertInput('') + await manager.onInsertInput(String.fromCharCode(65533)) + await manager.onInsertInput(String.fromCharCode(30)) + expect(manager.isActivated).toBe(true) + }) + + it('should ignore insert', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await nvim.eval('feedkeys("\\x", "in")') + await helper.wait(50) + expect(manager.isActivated).toBe(true) + }) + }) + + describe('parseArgs()', () => { + it('should show error for bad option', async () => { + manager.parseArgs(['$x', 'location']) + let msg = await helper.getCmdline() + expect(msg).toMatch('Invalid list option') + }) + + it('should show error for option that does not exist', async () => { + manager.parseArgs(['-xyz', 'location']) + let msg = await helper.getCmdline() + expect(msg).toMatch('Invalid option') + }) + + it('should show error for interactive with list not support interactive', async () => { + manager.parseArgs(['--interactive', 'location']) + let msg = await helper.getCmdline() + expect(msg).toMatch('not supported') + }) + }) + + describe('resume()', () => { + it('should resume by name', async () => { + await events.fire('FocusGained', []) + await manager.start(['location']) + await manager.session.ui.ready + await manager.session.hide() + await helper.wait(100) + await manager.resume('location') + expect(manager.isActivated).toBe(true) + }) + }) + + describe('first(), last()', () => { + it('should get session by name', async () => { + let last: string + let list: IList = { + name: 'test', + actions: [{ + name: 'open', + execute: (item: ListItem) => { + last = item.label + } + }], + defaultAction: 'open', + loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]) + } + manager.registerList(list) + await manager.start(['test']) + await manager.session.ui.ready + await manager.first('a') + await manager.last('a') + await manager.first('test') + expect(last).toBe('foo') + await manager.last('test') + expect(last).toBe('bar') + }) + }) + + describe('registerList()', () => { + it('should recreat list', async () => { + let list: IList = { + name: 'test', + actions: [{ + name: 'open', execute: _item => { + // noop + } + }], + defaultAction: 'open', + loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]) + } + manager.registerList(list) + helper.updateConfiguration('list.source.test.defaultAction', 'open') + let disposable = manager.registerList(list) + disposable.dispose() + await helper.wait(30) + let msg = await helper.getCmdline() + expect(msg).toMatch('recreated') + }) + }) + + describe('start()', () => { + it('should show error when loadItems throws', async () => { + let list: IList = { + name: 'test', + actions: [{ + name: 'open', + execute: (_item: ListItem) => { + } + }], + defaultAction: 'open', + loadItems: () => { + throw new Error('test error') + } + } + manager.registerList(list) + await manager.start(['test']) + await helper.wait(100) + }) + }) + + describe('list options', () => { + it('should respect auto preview option', async () => { + await manager.start(['--auto-preview', 'location']) + await manager.session.ui.ready + await helper.waitFor('winnr', ['$'], 3) + let previewWinnr = await nvim.call('coc#list#has_preview') + expect(previewWinnr).toBe(2) + let bufnr = await nvim.call('winbufnr', previewWinnr) + let buf = nvim.createBuffer(bufnr) + let name = await buf.name + expect(name).toMatch('manager.test.ts') + await nvim.eval('feedkeys("j", "in")') + await helper.wait(100) + let winnr = await nvim.call('coc#list#has_preview') + expect(winnr).toBe(previewWinnr) + }) + + it('should respect input option', async () => { + await manager.start(['--input=foo', 'location']) + await manager.session.ui.ready + await helper.wait(30) + let line = await helper.getCmdline() + expect(line).toMatch('foo') + expect(manager.isActivated).toBe(true) + }) + + it('should respect regex filter', async () => { + await manager.start(['--input=f.o', '--regex', 'location']) + await helper.wait(200) + let item = await manager.session?.ui.item + expect(item.label).toMatch('foo') + }) + + it('should respect normal option', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + let line = await helper.getCmdline() + expect(line).toBe('') + }) + + it('should respect nosort option', async () => { + await manager.start(['--ignore-case', '--no-sort', 'location']) + await manager.session.ui.ready + expect(manager.isActivated).toBe(true) + await nvim.input('oo') + await helper.wait(100) + let line = await nvim.call('getline', ['.']) + expect(line).toMatch('foo') + }) + + it('should respect ignorecase option', async () => { + await manager.start(['--ignore-case', '--strict', 'location']) + await manager.session.ui.ready + expect(manager.isActivated).toBe(true) + await nvim.input('bar') + await helper.wait(100) + let n = manager.session?.ui.length + expect(n).toBe(1) + let line = await nvim.line + expect(line).toMatch('Bar') + }) + + it('should respect top option', async () => { + await manager.start(['--top', 'location']) + await manager.session.ui.ready + let nr = await nvim.call('winnr') + expect(nr).toBe(1) + }) + + it('should respect number select option', async () => { + await manager.start(['--number-select', 'location']) + await manager.session.ui.ready + await helper.wait(100) + await nvim.eval('feedkeys("2", "in")') + await helper.wait(100) + let lnum = locations[1].lnum + let curr = await nvim.call('line', '.') + expect(lnum).toBe(curr) + }) + + it('should respect tab option', async () => { + await manager.start(['--tab', '--auto-preview', 'location']) + await manager.session.ui.ready + await helper.wait(100) + await nvim.command('wincmd l') + let previewwindow = await nvim.eval('w:previewwindow') + expect(previewwindow).toBe(1) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/mappings.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/mappings.test.ts new file mode 100644 index 00000000..1a34c115 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/mappings.test.ts @@ -0,0 +1,764 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import BasicList from '../../list/basic' +import manager from '../../list/manager' +import { IList, ListContext, ListItem, QuickfixItem } from '../../types' +import { disposeAll } from '../../util/index' +import window from '../../window' +import helper from '../helper' + +class TestList extends BasicList { + public name = 'test' + public timeout = 3000 + public text = 'test' + public detail = 'detail' + public loadItems(_context: ListContext, token: CancellationToken): Promise { + return new Promise(resolve => { + let timer = setTimeout(() => { + resolve([{ label: this.text }]) + }, this.timeout) + token.onCancellationRequested(() => { + if (timer) { + clearTimeout(timer) + resolve([]) + } + }) + }) + } +} + +let nvim: Neovim +let disposables: Disposable[] = [] +const locations: ReadonlyArray = [{ + filename: __filename, + col: 2, + lnum: 1, + text: 'foo' +}, { + filename: __filename, + col: 1, + lnum: 2, + text: 'Bar' +}, { + filename: __filename, + col: 1, + lnum: 3, + text: 'option' +}] + +const lineList: IList = { + name: 'lines', + actions: [{ + name: 'open', + execute: async item => { + await window.moveTo({ + line: (item as ListItem).data.line, + character: 0 + }) + // noop + } + }], + defaultAction: 'open', + async loadItems(_context, _token): Promise { + let lines = [] + for (let i = 0; i < 100; i++) { + lines.push(i.toString()) + } + return lines.map((line, idx) => ({ + label: line, + data: { line: idx } + })) + } +} + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + await nvim.setVar('coc_jump_locations', locations) +}) + +afterAll(async () => { + disposeAll(disposables) + await helper.shutdown() +}) + +afterEach(async () => { + manager.reset() + await helper.reset() +}) + +describe('isValidAction()', () => { + it('should check invalid action', async () => { + let mappings = manager.mappings + expect(mappings.isValidAction('foo')).toBe(false) + expect(mappings.isValidAction('do:switch')).toBe(true) + expect(mappings.isValidAction('eval:@*')).toBe(true) + expect(mappings.isValidAction('undefined:undefined')).toBe(false) + }) +}) + +describe('User mappings', () => { + it('should show warning for invalid key', async () => { + let revert = helper.updateConfiguration('list.insertMappings', { + xy: 'action:tabe', + }) + await helper.wait(30) + let msg = await helper.getCmdline() + revert() + await nvim.command('echo ""') + expect(msg).toMatch('Invalid configuration') + revert = helper.updateConfiguration('list.insertMappings', { + '': 'action:tabe', + }) + await helper.wait(30) + msg = await helper.getCmdline() + revert() + expect(msg).toMatch('Invalid configuration') + revert = helper.updateConfiguration('list.insertMappings', { + '': 'foo:bar', + }) + await helper.wait(30) + msg = await helper.getCmdline() + revert() + expect(msg).toMatch('Invalid configuration') + }) + + it('should execute action keymap', async () => { + let revert = helper.updateConfiguration('list.insertMappings', { + '': 'action:quickfix', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let buftype = await nvim.eval('&buftype') + expect(buftype).toBe('quickfix') + revert() + }) + + it('should execute expr keymap', async () => { + await helper.mockFunction('TabOpen', 'quickfix') + helper.updateConfiguration('list.insertMappings', { + '': 'expr:TabOpen', + }) + helper.updateConfiguration('list.normalMappings', { + t: 'expr:TabOpen', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let buftype = await nvim.eval('&buftype') + expect(buftype).toBe('quickfix') + await nvim.command('close') + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('t') + buftype = await nvim.eval('&buftype') + expect(buftype).toBe('quickfix') + }) + + it('should execute do mappings', async () => { + helper.updateConfiguration('list.previousKeymap', '') + helper.updateConfiguration('list.nextKeymap', '') + helper.updateConfiguration('list.insertMappings', { + '': 'do:next', + '': 'do:previous', + '': 'do:exit', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let item = await manager.session?.ui.item + expect(item.label).toMatch(locations[1].text) + await helper.listInput('') + item = await manager.session?.ui.item + expect(item.label).toMatch(locations[0].text) + await helper.listInput('') + item = await manager.session?.ui.item + expect(item.label).toMatch(locations[1].text) + await helper.listInput('') + item = await manager.session?.ui.item + expect(item.label).toMatch(locations[0].text) + await helper.listInput('') + expect(manager.isActivated).toBe(false) + }) + + it('should execute prompt mappings', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'prompt:previous', + '': 'prompt:next', + '': 'prompt:start', + '': 'prompt:end', + '': 'prompt:left', + '': 'prompt:right', + '': 'prompt:deleteforward', + '': 'prompt:deletebackward', + '': 'prompt:removetail', + '': 'prompt:removeahead', + }) + await manager.start(['location']) + await manager.session.ui.ready + for (let key of ['', '', '', '', '', '', '', '', '', '']) { + await helper.listInput(key) + } + expect(manager.isActivated).toBe(true) + }) + + it('should execute feedkeys keymap', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'feedkeys:\\', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let line = await nvim.call('line', '.') + expect(line).toBe(locations.length) + }) + + it('should execute normal keymap', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'normal:G', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let line = await nvim.call('line', '.') + expect(line).toBe(locations.length) + }) + + it('should execute command keymap', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'command:wincmd p', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(true) + let winnr = await nvim.call('winnr') + expect(winnr).toBe(1) + }) + + it('should execute call keymap', async () => { + await helper.mockFunction('Test', 1) + helper.updateConfiguration('list.insertMappings', { + '': 'call:Test', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(true) + }) + + it('should insert clipboard register to prompt', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'prompt:paste', + }) + await nvim.command('let @* = "foobar"') + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let { input } = manager.prompt + expect(input).toMatch('foobar') + await nvim.command('let @* = ""') + await helper.listInput('') + expect(manager.prompt.input).toMatch('foobar') + }) + + it('should insert text from default register to prompt', async () => { + helper.updateConfiguration('list.insertMappings', { + '': 'eval:@@', + }) + await nvim.command('let @@ = "bar"') + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let { input } = manager.prompt + expect(input).toMatch('bar') + }) +}) + +describe('doAction()', () => { + it('should throw when action not found', async () => { + let mappings = manager.mappings + let fn = async () => { + await mappings.doAction('foo:bar') + } + await expect(fn()).rejects.toThrow(/doesn't exist/) + }) + + it('should not throw when session does not exist', async () => { + let mappings = manager.mappings + await mappings.doAction('do:selectall') + await mappings.doAction('do:help') + await mappings.doAction('do:refresh') + await mappings.doAction('do:toggle') + await mappings.doAction('do:jumpback') + await mappings.doAction('prompt:previous') + await mappings.doAction('prompt:next') + await mappings.doAction('do:refresh') + }) + + it('should not throw when action name does not exist', async () => { + await helper.mockFunction('MyExpr', '') + let mappings = manager.mappings + await mappings.doAction('expr', 'MyExpr') + }) +}) + +describe('getAction()', () => { + it('should throw for invalid action', async () => { + let mappings = manager.mappings + let fn = () => { + mappings.getAction('foo') + } + expect(fn).toThrow(Error) + fn = () => { + mappings.getAction('do:bar') + } + expect(fn).toThrow(Error) + }) +}) + +describe('Default normal mappings', () => { + it('should invoke action', async () => { + await manager.start(['--normal', '--no-quit', 'location']) + await manager.session.ui.ready + let winid = manager.session.ui.winid + await helper.listInput('t') + let nr = await nvim.call('tabpagenr') + expect(nr).toBe(2) + await nvim.call('win_gotoid', [winid]) + await helper.listInput('s') + let winnr = await nvim.call('winnr', ['$']) + expect(winnr).toBe(3) + await nvim.call('win_gotoid', [winid]) + await helper.listInput('d') + let filename = await nvim.call('expand', ['%']) + expect(filename).toMatch(path.basename(__filename)) + await nvim.call('win_gotoid', [winid]) + await helper.listInput('') + filename = await nvim.call('expand', ['%']) + expect(filename).toMatch(path.basename(__filename)) + }) + + it('should select all items by ', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('') + let selected = manager.session?.ui.selectedItems + expect(selected.length).toBe(locations.length) + }) + + it('should stop by ', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('') + let loading = manager.session?.worker.isLoading + expect(loading).toBe(false) + }) + + it('should jump back by ', async () => { + let doc = await helper.createDocument() + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('') + let bufnr = await nvim.call('bufnr', ['%']) + expect(bufnr).toBe(doc.bufnr) + }) + + it('should scroll preview window by , ', async () => { + await helper.createDocument() + await manager.start(['--auto-preview', '--normal', 'location']) + await manager.session.ui.ready + await helper.waitPreviewWindow() + let winnr = await nvim.call('coc#list#has_preview') as number + let winid = await nvim.call('win_getid', [winnr]) + await helper.listInput('') + let res = await nvim.call('getwininfo', [winid]) + expect(res[0].topline).toBeGreaterThan(1) + await helper.listInput('') + res = await nvim.call('getwininfo', [winid]) + expect(res[0].topline).toBeLessThan(7) + }) + + it('should insert command by :', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput(':') + await nvim.eval('feedkeys("let g:x = 1\\", "in")') + let res = await nvim.getVar('x') + expect(res).toBe(1) + }) + + it('should select action by ', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + let p = helper.listInput('') + await helper.wait(50) + await nvim.input('t') + await p + let nr = await nvim.call('tabpagenr') + expect(nr).toBe(2) + }) + + it('should preview by p', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('p') + let winnr = await nvim.call('coc#list#has_preview') + expect(winnr).toBe(2) + }) + + it('should stop task by ', async () => { + disposables.push(manager.registerList(new TestList(nvim))) + let p = manager.start(['--normal', 'test']) + await helper.wait(50) + await nvim.input('') + await p + let len = manager.session?.ui.length + expect(len).toBe(0) + }) + + it('should cancel list by ', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await nvim.eval('feedkeys("\\", "in")') + await helper.waitValue(() => { + return manager.isActivated + }, false) + }) + + it('should reload list by ', async () => { + let list = new TestList(nvim) + list.timeout = 0 + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'test']) + await manager.session.ui.ready + list.text = 'new' + await helper.listInput('') + await helper.wait(30) + let line = await nvim.line + expect(line).toMatch('new') + }) + + it('should toggle selection ', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput(' ') + let selected = manager.session?.ui.selectedItems + expect(selected.length).toBe(1) + await helper.listInput('k') + await helper.listInput(' ') + selected = manager.session?.ui.selectedItems + expect(selected.length).toBe(0) + }) + + it('should change to insert mode by i, o, a', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + let keys = ['i', 'I', 'o', 'O', 'a', 'A'] + for (let key of keys) { + await helper.listInput(key) + let mode = manager.prompt.mode + expect(mode).toBe('insert') + await helper.listInput('') + mode = manager.prompt.mode + expect(mode).toBe('normal') + } + }) + + it('should show help by ?', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('?') + let bufname = await nvim.call('bufname', '%') + expect(bufname).toBe('[LIST HELP]') + }) +}) + +describe('list insert mappings', () => { + it('should open by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let bufname = await nvim.call('expand', ['%:p']) + expect(bufname).toMatch('mappings.test.ts') + }) + + it('should paste input by ', async () => { + await nvim.command('let @* = "foo"') + await nvim.command('let @@ = "foo"') + await nvim.call('setreg', ['*', 'foo']) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let input = manager.prompt.input + expect(input).toBe('foo') + }) + + it('should insert register content by ', async () => { + await nvim.command('let @* = "foo"') + await nvim.command('let @@ = "foo"') + await nvim.call('setreg', ['*', 'foo']) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + await helper.listInput('*') + let input = manager.prompt.input + expect(input).toBe('foo') + await helper.listInput('') + await helper.listInput('<') + input = manager.prompt.input + expect(input).toBe('foo') + manager.prompt.reset() + }) + + it('should cancel by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(false) + }) + + it('should select action by insert ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + let p = helper.listInput('') + await helper.wait(50) + await nvim.input('d') + await p + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch(path.basename(__filename)) + }) + + it('should select action for visual selected items', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.wait(50) + await nvim.input('V') + await helper.wait(30) + await nvim.input('2') + await helper.wait(30) + await nvim.input('j') + await helper.wait(30) + await manager.doAction('quickfix') + let buftype = await nvim.eval('&buftype') + expect(buftype).toBe('quickfix') + }) + + it('should stop loading by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(true) + }) + + it('should reload by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(true) + }) + + it('should change to normal mode by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + expect(manager.isActivated).toBe(true) + }) + + it('should select line by and ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await nvim.eval('feedkeys("\\", "in")') + await nvim.eval('feedkeys("\\", "in")') + expect(manager.isActivated).toBe(true) + let line = await nvim.line + expect(line).toMatch('foo') + }) + + it('should move cursor by and ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('f') + await helper.listInput('') + await helper.listInput('') + await helper.listInput('a') + await helper.listInput('') + await helper.listInput('') + await helper.listInput('c') + let input = manager.prompt.input + expect(input).toBe('afc') + }) + + it('should move cursor by and ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + await helper.listInput('') + await helper.listInput('a') + let input = manager.prompt.input + expect(input).toBe('a') + }) + + it('should move cursor by ', async () => { + disposables.push(manager.registerList(lineList)) + await manager.start(['lines']) + await manager.session.ui.ready + await helper.listInput('') + await helper.listInput('') + await helper.listInput('') + }) + + it('should scroll window by and ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + await helper.listInput('') + }) + + it('should change input by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('f') + await helper.listInput('') + let input = manager.prompt.input + expect(input).toBe('') + }) + + it('should change input by ', async () => { + let revert = helper.updateConfiguration('list.insertMappings', { + '': 'prompt:removetail', + }) + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('f') + await helper.listInput('o') + await helper.listInput('o') + await helper.listInput('') + await helper.listInput('') + expect(manager.mappings.hasUserMapping('insert', '')).toBe(true) + let input = manager.prompt.input + revert() + expect(input).toBe('') + }) + + it('should change input by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('f') + await helper.listInput('') + let input = manager.prompt.input + expect(input).toBe('') + }) + + it('should change input by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('f') + await helper.listInput('a') + await helper.listInput('') + let input = manager.prompt.input + expect(input).toBe('') + }) + + it('should change input by ', async () => { + await manager.start(['--input=a', 'location']) + await manager.session.ui.ready + await helper.listInput('') + let input = manager.prompt.input + expect(input).toBe('') + }) + + it('should change input by and ', async () => { + async function session(input: string): Promise { + await manager.start(['location']) + await manager.session.ui.ready + for (let ch of input) { + await helper.listInput(ch) + } + await manager.cancel() + } + await session('foo') + await session('bar') + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let input = manager.prompt.input + expect(input.length).toBeGreaterThan(0) + await helper.listInput('') + input = manager.prompt.input + expect(input.length).toBeGreaterThan(0) + }) + + it('should change matcher by ', async () => { + await manager.start(['location']) + await manager.session.ui.ready + await helper.listInput('') + let matcher = manager.session?.listOptions.matcher + expect(matcher).toBe('strict') + await helper.listInput('') + matcher = manager.session?.listOptions.matcher + expect(matcher).toBe('regex') + await helper.listInput('f') + let len = manager.session?.ui.length + expect(len).toBeGreaterThan(0) + }) +}) + +describe('evalExpression', () => { + it('should exit list', async () => { + helper.updateConfiguration('list.normalMappings', { + t: 'do:exit', + }) + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + expect(manager.mappings.hasUserMapping('normal', 't')).toBe(true) + await helper.listInput('t') + expect(manager.isActivated).toBe(false) + }) + + it('should cancel prompt', async () => { + helper.updateConfiguration('list.normalMappings', { + t: 'do:cancel', + }) + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('t') + let res = await nvim.call('coc#prompt#activated') + expect(res).toBe(0) + }) + + it('should invoke normal command', async () => { + let revert = helper.updateConfiguration('list.normalMappings', { + x: 'normal!:G' + }) + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput('x') + revert() + let lnum = await nvim.call('line', ['.']) + expect(lnum).toBeGreaterThan(1) + }) + + it('should toggle, scroll preview', async () => { + let revert = helper.updateConfiguration('list.normalMappings', { + '': 'do:toggle', + a: 'do:toggle', + b: 'do:previewtoggle', + c: 'do:previewup', + d: 'do:previewdown', + e: 'prompt:insertregister', + f: 'do:stop', + g: 'do:togglemode', + }) + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await helper.listInput(' ') + for (let key of ['a', 'b', 'c', 'd', 'e', 'f', 'g']) { + await helper.listInput(key) + } + revert() + expect(manager.isActivated).toBe(true) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/session.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/session.test.ts new file mode 100644 index 00000000..740e006a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/session.test.ts @@ -0,0 +1,304 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import BasicList from '../../list/basic' +import manager from '../../list/manager' +import ListSession from '../../list/session' +import { ListItem, IList } from '../../types' +import { disposeAll } from '../../util' +import helper from '../helper' + +let labels: string[] = [] +let lastItem: string +let lastItems: ListItem[] + +class SimpleList extends BasicList { + public name = 'simple' + public detail = 'detail' + public options = [{ + name: 'foo', + description: 'foo' + }] + constructor(nvim: Neovim) { + super(nvim) + this.addAction('open', item => { + lastItem = item.label + }) + this.addMultipleAction('multiple', items => { + lastItems = items + }) + this.addAction('parallel', async () => { + await helper.wait(100) + }, { parallel: true }) + this.addAction('reload', item => { + lastItem = item.label + }, { persist: true, reload: true }) + } + public loadItems(): Promise { + return Promise.resolve(labels.map(s => { + return { label: s } as ListItem + })) + } +} + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + manager.reset() + await helper.reset() +}) + +describe('list session', () => { + describe('doDefaultAction()', () => { + it('should throw error when default action does not exist', async () => { + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + list.defaultAction = 'foo' + let len = list.actions.length + list.actions.splice(0, len) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + let err + try { + await manager.session.first() + } catch (e) { + err = e + } + expect(err).toBeDefined() + err = null + try { + await manager.session.last() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + }) + + describe('doItemAction()', () => { + it('should invoke multiple action', async () => { + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + await ui.selectAll() + await manager.doAction('multiple') + expect(lastItems.length).toBe(3) + lastItems = undefined + }) + + it('should invoke parallel action', async () => { + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + await ui.selectAll() + let d = Date.now() + await manager.doAction('parallel') + expect(Date.now() - d).toBeLessThan(300) + }) + + it('should invoke reload action', async () => { + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + labels = ['d', 'e'] + await manager.doAction('reload') + await helper.wait(50) + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual(['d', 'e']) + }) + }) + + describe('reloadItems()', () => { + it('should not reload items when window is hidden', async () => { + let fn = jest.fn() + let list: IList = { + name: 'reload', + defaultAction: 'open', + actions: [{ + name: 'open', + execute: () => {} + }], + loadItems: () => { + fn() + return Promise.resolve([]) + } + } + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'reload']) + let ui = manager.session.ui + await ui.ready + await manager.cancel(true) + let ses = manager.getSession('reload') + await ses.reloadItems() + expect(fn).toBeCalledTimes(1) + }) + }) + + describe('resume()', () => { + it('should do preview on resume', async () => { + labels = ['a', 'b', 'c'] + let lastItem + let list = new SimpleList(nvim) + list.actions.push({ + name: 'preview', + execute: item => { + lastItem = item + } + }) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', '--auto-preview', 'simple']) + let ui = manager.session.ui + await ui.ready + await ui.selectLines(1, 2) + await helper.wait(50) + await nvim.call('coc#window#close', [ui.winid]) + await helper.wait(100) + await manager.session.resume() + await helper.wait(100) + expect(lastItem).toBeDefined() + }) + }) + + describe('jumpBack()', () => { + it('should jump back', async () => { + let win = await nvim.window + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + manager.session.jumpBack() + await helper.wait(50) + let winid = await nvim.call('win_getid') + expect(winid).toBe(win.id) + }) + }) + + describe('doNumberSelect()', () => { + async function create(len: number): Promise { + labels = [] + for (let i = 0; i < len; i++) { + let code = 'a'.charCodeAt(0) + i + labels.push(String.fromCharCode(code)) + } + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', '--number-select', 'simple']) + let ui = manager.session.ui + await ui.ready + return manager.session + } + + it('should return false for invalid number', async () => { + let session = await create(5) + let res = await session.doNumberSelect('a') + expect(res).toBe(false) + res = await session.doNumberSelect('8') + expect(res).toBe(false) + }) + + it('should consider 0 as 10', async () => { + let session = await create(15) + let res = await session.doNumberSelect('0') + expect(res).toBe(true) + expect(lastItem).toBe('j') + }) + }) +}) + +describe('showHelp()', () => { + it('should show description and options in help', async () => { + labels = ['a', 'b', 'c'] + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + await manager.session.showHelp() + let lines = await nvim.call('getline', [1, '$']) + expect(lines.indexOf('DESCRIPTION')).toBeGreaterThan(0) + expect(lines.indexOf('ARGUMENTS')).toBeGreaterThan(0) + }) +}) + +describe('chooseAction()', () => { + it('should filter actions not have shortcuts', async () => { + labels = ['a', 'b', 'c'] + let fn = jest.fn() + let list = new SimpleList(nvim) + list.actions.push({ + name: 'a', + execute: () => { + fn() + } + }) + list.actions.push({ + name: 'b', + execute: () => { + } + }) + list.actions.push({ + name: 'ab', + execute: () => { + } + }) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + await manager.session.ui.ready + let p = manager.session.chooseAction() + await helper.wait(50) + await nvim.input('a') + await p + expect(fn).toBeCalled() + }) + + it('should choose action by menu picker', async () => { + helper.updateConfiguration('list.menuAction', true) + labels = ['a', 'b', 'c'] + let fn = jest.fn() + let list = new SimpleList(nvim) + let len = list.actions.length + list.actions.splice(0, len) + list.actions.push({ + name: 'a', + execute: () => { + fn() + } + }) + list.actions.push({ + name: 'b', + execute: () => { + fn() + } + }) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'simple']) + await manager.session.ui.ready + let p = manager.session.chooseAction() + await helper.wait(100) + await nvim.input('') + await p + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/sources.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/sources.test.ts new file mode 100644 index 00000000..2cf7de9c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/sources.test.ts @@ -0,0 +1,666 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, Diagnostic, DiagnosticSeverity, Disposable, Emitter, Location, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import diagnosticManager from '../../diagnostic/manager' +import events from '../../events' +import languages from '../../languages' +import BasicList, { PreviewOptions, toVimFiletype } from '../../list/basic' +import { formatListItems, formatPath, UnformattedListItem } from '../../list/formatting' +import manager from '../../list/manager' +import Document from '../../model/document' +import services, { IServiceProvider } from '../../services' +import { ListArgument, ListContext, ListItem, ServiceStat } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +let listItems: ListItem[] = [] +class OptionList extends BasicList { + public name = 'option' + public options: ListArgument[] = [{ + name: '-w, -word', + description: 'word' + }, { + name: '-i, -input INPUT', + hasValue: true, + description: 'input' + }] + constructor(nvim) { + super(nvim) + this.addLocationActions() + } + public loadItems(_context: ListContext, _token: CancellationToken): Promise { + return Promise.resolve(listItems) + } +} + +let previewOptions: PreviewOptions +class SimpleList extends BasicList { + public name = 'simple' + public defaultAction: 'preview' + constructor(nvim: Neovim) { + super(nvim) + this.addAction('preview', async (_item, context) => { + await this.preview(previewOptions, context) + }) + } + public loadItems(): Promise { + return Promise.resolve(['a', 'b', 'c'].map((s, idx) => { + return { label: s, location: Location.create('test:///a', Range.create(idx, 0, idx + 1, 0)) } as ListItem + })) + } +} + +let disposables: Disposable[] = [] +let nvim: Neovim +const locations: any[] = [{ + filename: __filename, + range: Range.create(0, 0, 0, 6), + text: 'foo' +}, { + filename: __filename, + range: Range.create(2, 0, 2, 6), + text: 'Bar' +}, { + filename: __filename, + range: Range.create(3, 0, 4, 6), + text: 'multiple' +}] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + manager.dispose() + await helper.shutdown() +}) + +afterEach(async () => { + listItems = [] + disposeAll(disposables) + manager.reset() + await helper.reset() +}) + +describe('formatting', () => { + describe('formatPath()', () => { + it('should format path', async () => { + expect(formatPath('hidden', 'path')).toBe('') + expect(formatPath('full', __filename)).toMatch('sources.test.ts') + expect(formatPath('short', __filename)).toMatch('sources.test.ts') + expect(formatPath('filename', __filename)).toMatch('sources.test.ts') + }) + }) + + describe('formatListItems', () => { + it('should format list items', async () => { + expect(formatListItems(false, [])).toEqual([]) + let items: UnformattedListItem[] = [{ + label: ['a', 'b', 'c'] + }] + expect(formatListItems(false, items)).toEqual([{ + label: 'a\tb\tc' + }]) + items = [{ + label: ['a', 'b', 'c'] + }, { + label: ['foo', 'bar', 'go'] + }] + expect(formatListItems(true, items)).toEqual([{ + label: 'a \tb \tc ' + }, { + label: 'foo\tbar\tgo' + }]) + }) + }) +}) + +describe('configuration', () => { + beforeEach(() => { + let list = new OptionList(nvim) + manager.registerList(list) + }) + + it('should change default options', async () => { + helper.updateConfiguration('list.source.option.defaultOptions', ['--normal']) + await manager.start(['option']) + await manager.session.ui.ready + const mode = manager.prompt.mode + expect(mode).toBe('normal') + }) + + it('should change default action', async () => { + helper.updateConfiguration('list.source.option.defaultAction', 'split') + await manager.start(['option']) + await manager.session.ui.ready + const action = manager.session.defaultAction + expect(action.name).toBe('split') + await manager.session.doAction() + let tab = await nvim.tabpage + let wins = await tab.windows + expect(wins.length).toBeGreaterThan(1) + }) + + it('should change default arguments', async () => { + helper.updateConfiguration('list.source.option.defaultArgs', ['-word']) + await manager.start(['option']) + await manager.session.ui.ready + const context = manager.session.context + expect(context.args).toEqual(['-word']) + }) +}) + +describe('BasicList', () => { + describe('getFiletype()', () => { + it('should get filetype', async () => { + expect(toVimFiletype('latex')).toBe('tex') + expect(toVimFiletype('foo')).toBe('foo') + }) + }) + + describe('parse arguments', () => { + it('should parse args #1', () => { + let list = new OptionList(nvim) + let res = list.parseArguments(['-w']) + expect(res).toEqual({ word: true }) + }) + + it('should parse args #2', () => { + let list = new OptionList(nvim) + let res = list.parseArguments(['-word']) + expect(res).toEqual({ word: true }) + }) + + it('should parse args #3', () => { + let list = new OptionList(nvim) + let res = list.parseArguments(['-input', 'foo']) + expect(res).toEqual({ input: 'foo' }) + }) + }) + + describe('jumpTo()', () => { + let list: OptionList + beforeAll(() => { + list = new OptionList(nvim) + }) + it('should jump to uri', async () => { + let uri = URI.file(__filename).toString() + await list.jumpTo(uri, 'edit') + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch('sources.test.ts') + }) + + it('should jump to location', async () => { + let uri = URI.file(__filename).toString() + let loc = Location.create(uri, Range.create(0, 0, 1, 0)) + await list.jumpTo(loc, 'edit') + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch('sources.test.ts') + }) + + it('should jump to location with empty range', async () => { + let uri = URI.file(__filename).toString() + let loc = Location.create(uri, Range.create(0, 0, 0, 0)) + await list.jumpTo(loc, 'edit') + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch('sources.test.ts') + }) + }) + + describe('convertLocation()', () => { + let list: OptionList + beforeAll(() => { + list = new OptionList(nvim) + }) + it('should convert uri', async () => { + let uri = URI.file(__filename).toString() + let res = await list.convertLocation(uri) + expect(res.uri).toBe(uri) + }) + + it('should convert location with line', async () => { + let uri = URI.file(__filename).toString() + let res = await list.convertLocation({ uri, line: 'convertLocation()', text: 'convertLocation' }) + expect(res.uri).toBe(uri) + res = await list.convertLocation({ uri, line: 'convertLocation()' }) + expect(res.uri).toBe(uri) + }) + + it('should convert location with custom schema', async () => { + let uri = 'test:///foo' + let res = await list.convertLocation({ uri, line: 'convertLocation()' }) + expect(res.uri).toBe(uri) + }) + }) + + describe('createAction()', () => { + it('should overwrite action', async () => { + let idx: number + let list = new OptionList(nvim) + listItems.push({ + label: 'foo', + location: Location.create('untitled:///1', Range.create(0, 0, 0, 0)) + }) + list.createAction({ + name: 'foo', + execute: () => { idx = 0 } + }) + list.createAction({ + name: 'foo', + execute: () => { idx = 1 } + }) + disposables.push(manager.registerList(list)) + await manager.start(['--normal', 'option']) + await manager.session.ui.ready + await manager.doAction('foo') + expect(idx).toBe(1) + }) + }) + + describe('preview()', () => { + beforeEach(() => { + let list = new SimpleList(nvim) + disposables.push(manager.registerList(list)) + }) + + async function doPreview(opts: PreviewOptions): Promise { + previewOptions = opts + await manager.start(['--normal', 'simple']) + await manager.session.ui.ready + await manager.doAction('preview') + let res = await nvim.call('coc#list#has_preview') as number + expect(res).toBeGreaterThan(0) + let winid = await nvim.call('win_getid', [res]) + return winid + } + + it('should preview lines', async () => { + await doPreview({ filetype: '', lines: ['foo', 'bar'] }) + }) + + it('should preview with bufname', async () => { + await doPreview({ + bufname: 't.js', + filetype: 'typescript', + lines: ['foo', 'bar'] + }) + }) + + it('should preview with range highlight', async () => { + let winid = await doPreview({ + bufname: 't.js', + filetype: 'typescript', + lines: ['foo', 'bar'], + range: Range.create(0, 0, 0, 3) + }) + let res = await nvim.call('getmatches', [winid]) + expect(res.length).toBeGreaterThan(0) + }) + }) + + describe('previewLocation()', () => { + it('should preview sketch buffer', async () => { + await nvim.command('new') + await nvim.setLine('foo') + let doc = await workspace.document + expect(doc.uri).toMatch('untitled') + let list = new OptionList(nvim) + listItems.push({ + label: 'foo', + location: Location.create(doc.uri, Range.create(0, 0, 0, 0)) + }) + disposables.push(manager.registerList(list)) + await manager.start(['option']) + await manager.session.ui.ready + await helper.wait(30) + await manager.doAction('preview') + await nvim.command('wincmd p') + let win = await nvim.window + let isPreview = await win.getVar('previewwindow') + expect(isPreview).toBe(1) + let line = await nvim.line + expect(line).toBe('foo') + }) + }) +}) + +describe('list sources', () => { + beforeAll(async () => { + await nvim.setVar('coc_jump_locations', locations) + }) + + describe('locations', () => { + it('should highlight ranges', async () => { + await manager.start(['--normal', '--auto-preview', 'location']) + await manager.session.ui.ready + await helper.wait(200) + manager.prompt.cancel() + await nvim.command('wincmd k') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('sources.test.ts') + let res = await nvim.call('getmatches') + expect(res.length).toBe(1) + }) + + it('should change highlight on cursor move', async () => { + await manager.start(['--normal', '--auto-preview', 'location']) + await manager.session.ui.ready + await nvim.command('exe 2') + let bufnr = await nvim.eval('bufnr("%")') + await events.fire('CursorMoved', [bufnr, [2, 1]]) + await helper.waitFor('winnr', ['$'], 3) + await nvim.command('wincmd k') + let res = await nvim.call('getmatches') + expect(res.length).toBe(1) + expect(res[0]['pos1']).toEqual([3, 1, 6]) + }) + + it('should highlight multiple line range', async () => { + await manager.start(['--normal', '--auto-preview', 'location']) + await manager.session.ui.ready + await nvim.command('exe 3') + let bufnr = await nvim.eval('bufnr("%")') + await events.fire('CursorMoved', [bufnr, [2, 1]]) + await helper.waitFor('winnr', ['$'], 3) + await nvim.command('wincmd k') + let res = await nvim.call('getmatches') + expect(res.length).toBe(1) + expect(res[0]['pos1']).toBeDefined() + expect(res[0]['pos2']).toBeDefined() + }) + + it('should do open action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.doAction('open') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('sources.test.ts') + }) + + it('should do quickfix action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.session.ui.selectAll() + await manager.doAction('quickfix') + let buftype = await nvim.eval('&buftype') + expect(buftype).toBe('quickfix') + }) + + it('should do refactor action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.session.ui.selectAll() + await manager.doAction('refactor') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('coc_refactor') + }) + + it('should do tabe action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.doAction('tabe') + let tabs = await nvim.tabpages + expect(tabs.length).toBe(2) + }) + + it('should do drop action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.doAction('drop') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('sources.test.ts') + }) + + it('should do vsplit action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.doAction('vsplit') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('sources.test.ts') + }) + + it('should do split action', async () => { + await manager.start(['--normal', 'location']) + await manager.session.ui.ready + await manager.doAction('split') + let name = await nvim.eval('bufname("%")') + expect(name).toMatch('sources.test.ts') + }) + }) + + describe('commands', () => { + it('should load commands source', async () => { + await manager.start(['commands']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + }) + + it('should do run action', async () => { + await manager.start(['commands']) + await manager.session?.ui.ready + await manager.doAction() + }) + }) + + describe('diagnostics', () => { + + function createDiagnostic(msg: string, range?: Range, severity?: DiagnosticSeverity, code?: number): Diagnostic { + range = range ? range : Range.create(0, 0, 0, 1) + return Diagnostic.create(range, msg, severity || DiagnosticSeverity.Error, code) + } + + async function createDocument(name?: string): Promise { + let doc = await helper.createDocument(name) + let collection = diagnosticManager.create('test') + disposables.push({ + dispose: () => { + collection.clear() + collection.dispose() + } + }) + let diagnostics: Diagnostic[] = [] + await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], { + start: 0, + end: -1, + strictIndexing: false + }) + diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error, 1001)) + diagnostics.push(createDiagnostic('warning', Range.create(0, 5, 0, 6), DiagnosticSeverity.Warning, 1002)) + diagnostics.push(createDiagnostic('information', Range.create(1, 0, 1, 1), DiagnosticSeverity.Information, 1003)) + diagnostics.push(createDiagnostic('hint', Range.create(1, 2, 1, 3), DiagnosticSeverity.Hint, 1004)) + diagnostics.push(createDiagnostic('error', Range.create(2, 0, 2, 2), DiagnosticSeverity.Error, 1005)) + collection.set(doc.uri, diagnostics) + await doc.synchronize() + return doc + } + + it('should load diagnostics source', async () => { + await createDocument('a') + await manager.start(['diagnostics']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + }) + + it('should not include code', async () => { + let fn = helper.updateConfiguration('list.source.diagnostics.includeCode', false) + disposables.push({ dispose: fn }) + await createDocument('a') + await manager.start(['diagnostics']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let line = await nvim.line + expect(line.match(/100/)).toBeNull() + }) + + it('should hide file path', async () => { + helper.updateConfiguration('list.source.diagnostics.pathFormat', 'hidden') + await createDocument('foo') + await manager.start(['diagnostics']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let line = await nvim.line + expect(line.match(/foo/)).toBeNull() + }) + + it('should refresh on diagnostics refresh', async () => { + let doc = await createDocument('bar') + await manager.start(['diagnostics']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let diagnostics: Diagnostic[] = [] + let collection = diagnosticManager.create('test') + diagnostics.push(createDiagnostic('error', Range.create(2, 0, 2, 2), DiagnosticSeverity.Error, 1009)) + collection.set(doc.uri, diagnostics) + await helper.wait(50) + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines.length).toBeGreaterThan(0) + }) + }) + + describe('extensions', () => { + it('should load extensions source', async () => { + await manager.start(['extensions']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + }) + }) + + describe('folders', () => { + it('should load folders source', async () => { + await manager.start(['folders']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + }) + }) + + describe('lists', () => { + it('should load lists source', async () => { + await manager.start(['lists']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + await helper.listInput('') + await helper.wait(50) + let s = manager.getSession() + expect(s.name != 'lists').toBe(true) + }) + }) + + describe('outline', () => { + it('should load outline source', async () => { + await manager.start(['outline']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + }) + }) + + describe('services', () => { + function createService(name: string): IServiceProvider { + let _onServcieReady = new Emitter() + // public readonly onServcieReady: Event = this. + let service: IServiceProvider = { + id: name, + name, + selector: [{ language: 'vim' }], + state: ServiceStat.Initial, + start(): Promise { + service.state = ServiceStat.Running + _onServcieReady.fire() + return Promise.resolve() + }, + dispose(): void { + service.state = ServiceStat.Stopped + }, + stop(): void { + service.state = ServiceStat.Stopped + }, + restart(): void { + service.state = ServiceStat.Running + _onServcieReady.fire() + }, + onServiceReady: _onServcieReady.event + } + disposables.push(services.regist(service)) + return service + } + + it('should load services source', async () => { + createService('foo') + createService('bar') + await manager.start(['services']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let lines = await nvim.call('getline', [1, '$']) as string[] + expect(lines.length).toBe(2) + }) + + it('should toggle service state', async () => { + let service = createService('foo') + await service.start() + await manager.start(['services']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let ses = manager.session + expect(ses.name).toBe('services') + await ses.doAction('toggle') + expect(service.state).toBe(ServiceStat.Stopped) + await ses.doAction('toggle') + }) + }) + + describe('sources', () => { + it('should load sources source', async () => { + await manager.start(['sources']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let session = manager.getSession() + await session.doAction('open') + let bufname = await nvim.call('bufname', '%') + expect(bufname).toMatch(/native/) + }) + + it('should toggle source state', async () => { + await manager.start(['sources']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let session = manager.getSession() + await session.doAction('toggle') + await session.doAction('toggle') + }) + + it('should refresh source', async () => { + await manager.start(['sources']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + let session = manager.getSession() + await session.doAction('refresh') + }) + }) + + describe('symbols', () => { + it('should load symbols source', async () => { + await helper.createDocument() + let disposable = languages.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols: () => [] + }) + await manager.start(['--interactive', 'symbols']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + disposable.dispose() + }) + }) + + describe('links', () => { + it('should load links source', async () => { + let disposable = languages.registerDocumentLinkProvider([{ scheme: 'file' }, { scheme: 'untitled' }], { + provideDocumentLinks: () => [] + }) + await manager.start(['links']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + disposable.dispose() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/ui.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/ui.test.ts new file mode 100644 index 00000000..4326474a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/ui.test.ts @@ -0,0 +1,274 @@ +import { Neovim } from '@chemzqm/neovim' +import { EventEmitter } from 'events' +import { Disposable } from 'vscode-languageserver-protocol' +import BasicList from '../../list/basic' +import events from '../../events' +import manager from '../../list/manager' +import { ListItem, IList, ListTask } from '../../types' +import { disposeAll } from '../../util' +import helper from '../helper' + +let labels: string[] = [] +let lastItem: string + +class SimpleList extends BasicList { + public name = 'simple' + constructor(nvim: Neovim) { + super(nvim) + this.addAction('open', item => { + lastItem = item.label + }) + } + public loadItems(): Promise { + return Promise.resolve(labels.map(s => { + return { label: s, ansiHighlights: [{ span: [0, 1], hlGroup: 'MoreMsg' }] } as ListItem + })) + } +} + +class SlowTask extends EventEmitter implements ListTask { + private interval: NodeJS.Timer + constructor() { + super() + let i = 0 + let interval = this.interval = setInterval(() => { + i++ + this.emit('data', { + label: i.toString(), highlights: { + spans: [[0, 1]], + hlGroup: 'Search' + } + }) + if (i == 5) { + this.emit('end') + clearInterval(interval) + } + }, 50) + } + + public dispose(): void { + clearInterval(this.interval) + this.removeAllListeners() + } +} + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + manager.reset() + await helper.reset() +}) + +describe('list ui', () => { + describe('selectLines()', () => { + it('should select lines', async () => { + labels = ['foo', 'bar'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['simple']) + let ui = manager.session.ui + await ui.ready + await ui.selectLines(3, 1) + let buf = await nvim.buffer + let res = await buf.getSigns({ group: 'coc-list' }) + expect(res.length).toBe(2) + }) + }) + + describe('preselect', () => { + it('should select preselect item', async () => { + let list: IList = { + actions: [{ + name: 'open', + execute: () => {} + }], + name: 'preselect', + defaultAction: 'open', + loadItems: () => { + return Promise.resolve([{ label: 'foo' }, { label: 'bar', preselect: true }]) + } + } + disposables.push(manager.registerList(list)) + await manager.start(['preselect']) + let ui = manager.session.ui + await ui.ready + let line = await nvim.line + expect(line).toBe('bar') + }) + }) + + describe('resume()', () => { + it('should resume with selected lines', async () => { + labels = ['foo', 'bar'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['simple']) + let ui = manager.session.ui + await ui.ready + await ui.selectLines(1, 2) + await nvim.call('coc#window#close', [ui.winid]) + await helper.wait(100) + await manager.session.resume() + await helper.wait(100) + let buf = await nvim.buffer + let res = await buf.getSigns({ group: 'coc-list' }) + expect(res.length).toBe(2) + }) + }) + + describe('events', () => { + async function mockMouse(winid: number, lnum: number): Promise { + await nvim.command(`let v:mouse_winid = ${winid}`) + await nvim.command(`let v:mouse_lnum = ${lnum}`) + await nvim.command('let v:mouse_col = 1') + } + + it('should fire action on double click', async () => { + labels = ['foo', 'bar'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['simple']) + let ui = manager.session.ui + await ui.ready + await mockMouse(ui.winid, 1) + await manager.session.onMouseEvent('<2-LeftMouse>') + await helper.wait(100) + expect(lastItem).toBe('foo') + }) + + it('should select clicked line', async () => { + labels = ['foo', 'bar'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['simple']) + let ui = manager.session.ui + await ui.ready + await mockMouse(ui.winid, 2) + await ui.onMouse('mouseDown') + await helper.wait(50) + await mockMouse(ui.winid, 2) + await ui.onMouse('mouseUp') + await helper.wait(50) + let item = await ui.item + expect(item.label).toBe('bar') + }) + + it('should jump to original window on click', async () => { + labels = ['foo', 'bar'] + let win = await nvim.window + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['simple']) + let ui = manager.session.ui + await ui.ready + await mockMouse(win.id, 1) + await ui.onMouse('mouseUp') + await helper.wait(50) + let curr = await nvim.window + expect(curr.id).toBe(win.id) + }) + + it('should highlights items on CursorMoved', async () => { + labels = (new Array(400)).fill('a') + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + await nvim.call('cursor', [350, 1]) + await events.fire('CursorMoved', [ui.bufnr, [350, 1]]) + await helper.wait(100) + let res = await nvim.call('coc#highlight#get_highlights', [ui.bufnr, 'list']) + expect(res.length).toBeGreaterThan(300) + }) + }) +}) + +describe('reversed list', () => { + it('should render and add highlights', async () => { + labels = ['a', 'b', 'c', 'd'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['--reverse', 'simple']) + let ui = manager.session.ui + await ui.ready + let buf = nvim.createBuffer(ui.bufnr) + let lines = await buf.lines + expect(lines).toEqual(['d', 'c', 'b', 'a']) + await helper.listInput('a') + await helper.wait(50) + lines = await buf.lines + expect(lines).toEqual(['a']) + let res = await nvim.call('coc#highlight#get_highlights', [ui.bufnr, 'list']) + expect(res.length).toBe(2) + let win = nvim.createWindow(ui.winid) + let height = await win.height + expect(height).toBe(1) + }) + + it('should moveUp and moveDown', async () => { + labels = ['a', 'b', 'c', 'd'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['--reverse', 'simple']) + let ui = manager.session.ui + await ui.ready + ui.moveUp() + await helper.waitFor('line', ['.'], 3) + ui.moveDown() + await helper.waitFor('line', ['.'], 4) + }) + + it('should toggle selection', async () => { + labels = ['a', 'b', 'c', 'd'] + disposables.push(manager.registerList(new SimpleList(nvim))) + await manager.start(['--reverse', '--normal', 'simple']) + let ui = manager.session.ui + await ui.ready + await ui.toggleSelection() + let items = ui.selectedItems + expect(items.length).toBeGreaterThan(0) + expect(items[0].label).toBe('a') + let lnum = await nvim.call('line', ['.']) + expect(lnum).toBe(3) + await helper.listInput('j') + await ui.toggleSelection() + items = ui.selectedItems + expect(items.length).toBe(0) + }) + + it('should prepend list items', async () => { + let o: any + let p = new Promise(resolve => { + let list: IList = { + actions: [{ + name: 'open', + execute: item => { + o = item + } + }], + name: 'slow', + defaultAction: 'open', + loadItems: () => { + let task = new SlowTask() + task.on('end', () => { + resolve(undefined) + }) + return Promise.resolve(task) + } + } + disposables.push(manager.registerList(list)) + void manager.start(['--reverse', '--normal', 'slow']) + }) + await p + await helper.wait(50) + let ui = manager.session.ui + let buf = nvim.createBuffer(ui.bufnr) + let lines = await buf.lines + expect(lines).toEqual(['5', '4', '3', '2', '1']) + let lnum = await nvim.call('line', ['.']) + expect(lnum).toBe(5) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/list/worker.test.ts b/sources_non_forked/coc.nvim/src/__tests__/list/worker.test.ts new file mode 100644 index 00000000..a181a371 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/list/worker.test.ts @@ -0,0 +1,226 @@ +import { Neovim } from '@chemzqm/neovim' +import manager from '../../list/manager' +import { parseInput } from '../../list/worker' +import helper from '../helper' +import { ListContext, ListTask, ListItem } from '../../types' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import { EventEmitter } from 'events' +import colors from 'colors/safe' +import BasicList from '../../list/basic' +import { disposeAll } from '../../util' + +let items: ListItem[] = [] + +class DataList extends BasicList { + public name = 'data' + public loadItems(): Promise { + return Promise.resolve(items) + } +} + +class EmptyList extends BasicList { + public name = 'empty' + public loadItems(): Promise { + let emitter: any = new EventEmitter() + setTimeout(() => { + emitter.emit('end') + }, 20) + return emitter + } +} + +class IntervalTaskList extends BasicList { + public name = 'task' + public timeout = 3000 + public loadItems(_context: ListContext, token: CancellationToken): Promise { + let emitter: any = new EventEmitter() + let i = 0 + let interval = setInterval(() => { + emitter.emit('data', { label: i.toFixed() }) + i++ + }, 50) + emitter.dispose = () => { + clearInterval(interval) + emitter.emit('end') + } + token.onCancellationRequested(() => { + emitter.dispose() + }) + return emitter + } +} + +class DelayTask extends BasicList { + public name = 'delay' + public interactive = true + public loadItems(_context: ListContext, token: CancellationToken): Promise { + let emitter: any = new EventEmitter() + let disposed = false + setTimeout(() => { + if (disposed) return + emitter.emit('data', { label: 'ahead' }) + }, 100) + setTimeout(() => { + if (disposed) return + emitter.emit('data', { label: 'abort' }) + }, 200) + emitter.dispose = () => { + disposed = true + emitter.emit('end') + } + token.onCancellationRequested(() => { + emitter.dispose() + }) + return emitter + } +} + +class InteractiveList extends BasicList { + public name = 'test' + public interactive = true + public loadItems(context: ListContext, _token: CancellationToken): Promise { + return Promise.resolve([{ + label: colors.magenta(context.input || '') + }]) + } +} + +class ErrorList extends BasicList { + public name = 'error' + public interactive = true + public loadItems(_context: ListContext, _token: CancellationToken): Promise { + return Promise.reject(new Error('test error')) + } +} + +class ErrorTaskList extends BasicList { + public name = 'task' + public loadItems(_context: ListContext, _token: CancellationToken): Promise { + let emitter: any = new EventEmitter() + let timeout = setTimeout(() => { + emitter.emit('error', new Error('task error')) + }, 100) + emitter.dispose = () => { + clearTimeout(timeout) + } + return emitter + } +} + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + manager.reset() + await helper.reset() +}) + +describe('parseInput', () => { + it('should parse input with space', async () => { + let res = parseInput('a b') + expect(res).toEqual(['a', 'b']) + res = parseInput('a b ') + expect(res).toEqual(['a', 'b']) + }) + + it('should parse input with escaped space', async () => { + let res = parseInput('a\\ b') + expect(res).toEqual(['a b']) + }) +}) + +describe('list worker', () => { + + it('should work with long running task', async () => { + disposables.push(manager.registerList(new IntervalTaskList(nvim))) + await manager.start(['task']) + await manager.session.ui.ready + await helper.wait(200) + let len = manager.session?.length + expect(len > 2).toBe(true) + await manager.cancel() + }) + + it('should sort by sortText', async () => { + items = [{ + label: 'abc', + sortText: 'b' + }, { + label: 'ade', + sortText: 'a' + }] + disposables.push(manager.registerList(new DataList(nvim))) + await manager.start(['data']) + await manager.session.ui.ready + await nvim.input('a') + await helper.wait(50) + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual(['ade', 'abc']) + await manager.cancel() + }) + + it('should show empty line for empty task', async () => { + disposables.push(manager.registerList(new EmptyList(nvim))) + await manager.start(['empty']) + await manager.session.ui.ready + let line = await nvim.call('getline', [1]) + expect(line).toMatch('No results') + }) + + it('should cancel task by use CancellationToken', async () => { + disposables.push(manager.registerList(new IntervalTaskList(nvim))) + await manager.start(['task']) + expect(manager.session?.worker.isLoading).toBe(true) + await helper.wait(100) + manager.session?.stop() + expect(manager.session?.worker.isLoading).toBe(false) + }) + + it('should render slow interactive list', async () => { + disposables.push(manager.registerList(new DelayTask(nvim))) + await manager.start(['delay']) + await nvim.input('a') + await helper.wait(600) + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual(['ahead', 'abort']) + }) + + it('should work with interactive list', async () => { + disposables.push(manager.registerList(new InteractiveList(nvim))) + await manager.start(['-I', 'test']) + await manager.session?.ui.ready + expect(manager.isActivated).toBe(true) + await nvim.eval('feedkeys("f", "in")') + await helper.wait(100) + await nvim.eval('feedkeys("a", "in")') + await helper.wait(100) + await nvim.eval('feedkeys("x", "in")') + await helper.wait(300) + let item = await manager.session?.ui.item + expect(item.label).toBe('fax') + }) + + it('should not activate on load error', async () => { + disposables.push(manager.registerList(new ErrorList(nvim))) + await manager.start(['test']) + expect(manager.isActivated).toBe(false) + }) + + it('should deactivate on task error', async () => { + disposables.push(manager.registerList(new ErrorTaskList(nvim))) + await manager.start(['task']) + await helper.wait(300) + expect(manager.isActivated).toBe(false) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/markdown/index.test.ts b/sources_non_forked/coc.nvim/src/__tests__/markdown/index.test.ts new file mode 100644 index 00000000..9e0079e1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/markdown/index.test.ts @@ -0,0 +1,265 @@ +import { getHighlightItems, parseMarkdown, parseDocuments } from '../../markdown/index' +import { Documentation } from '../../types' + +describe('getHighlightItems', () => { + it('should get highlights in single line', async () => { + let res = getHighlightItems('this line has highlights', 0, [10, 15]) + expect(res).toEqual([{ + colStart: 10, + colEnd: 15, + lnum: 0, + hlGroup: 'CocUnderline' + }]) + }) + + it('should get highlights when active end extended', async () => { + let res = getHighlightItems('this line', 0, [5, 30]) + expect(res).toEqual([{ + colStart: 5, + colEnd: 9, + lnum: 0, + hlGroup: 'CocUnderline' + }]) + }) + + it('should get highlights across line', async () => { + let res = getHighlightItems('this line\nhas highlights', 0, [5, 15]) + expect(res).toEqual([{ + colStart: 5, colEnd: 9, lnum: 0, hlGroup: 'CocUnderline' + }, { + colStart: 0, colEnd: 5, lnum: 1, hlGroup: 'CocUnderline' + }]) + res = getHighlightItems('a\nb\nc\nd', 0, [2, 5]) + expect(res).toEqual([ + { colStart: 0, colEnd: 1, lnum: 1, hlGroup: 'CocUnderline' }, + { colStart: 0, colEnd: 1, lnum: 2, hlGroup: 'CocUnderline' }, + { colStart: 0, colEnd: 0, lnum: 3, hlGroup: 'CocUnderline' } + ]) + }) +}) + +describe('parseMarkdown', () => { + it('should parse code blocks', async () => { + let content = ` +\`\`\`js +var global = globalThis +\`\`\` +\`\`\`ts +let str:string +\`\`\` +\`\`\`bash +if +\`\`\` +` + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual([ + 'var global = globalThis', + '', + 'let str:string', + '', + 'if' + ]) + expect(res.codes).toEqual([ + { filetype: 'javascript', startLine: 0, endLine: 1 }, + { filetype: 'typescript', startLine: 2, endLine: 3 }, + { filetype: 'sh', startLine: 4, endLine: 5 }, + ]) + }) + + it('should merge empty lines', async () => { + let content = ` +![img](http://img.io) +![img](http://img.io) +[link](http://example.com) +[link](javascript:void(0)) +` + let res = parseMarkdown(content, { excludeImages: true }) + expect(res.lines).toEqual([ + 'link', + '', + 'link: http://example.com' + ]) + }) + + it('should parse html code block', async () => { + let content = ` +example: +\`\`\`html +
    code
    +\`\`\` + ` + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['example:', '', '
    code
    ']) + expect(res.codes).toEqual([{ filetype: 'html', startLine: 2, endLine: 3 }]) + }) + + it('should compose empty lines', async () => { + let content = 'foo\n\n\nbar\n\n\n' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['foo', '', 'bar']) + }) + + it('should merge lines', async () => { + let content = 'first\nsecond' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['first', 'second']) + }) + + it('should parse ansi highlights', async () => { + let content = '__foo__\n[link](link)' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['foo', 'link']) + expect(res.highlights).toEqual([ + { hlGroup: 'CocBold', lnum: 0, colStart: 0, colEnd: 3 }, + { hlGroup: 'CocUnderline', lnum: 1, colStart: 0, colEnd: 4 } + ]) + }) + + it('should exclude images by option', async () => { + let content = 'head\n![img](img)\ncontent ![img](img) ![img](img)' + let res = parseMarkdown(content, { excludeImages: false }) + expect(res.lines).toEqual(['head', '![img](img)', 'content ![img](img) ![img](img)']) + content = 'head\n![img](img)\ncontent ![img](img) ![img](img)' + res = parseMarkdown(content, { excludeImages: true }) + expect(res.lines).toEqual(['head', 'content']) + }) + + it('should render hr', async () => { + let content = 'foo\n***\nbar' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['foo', '', '───', 'bar']) + }) + + it('should render deleted text', async () => { + let content = '~foo~' + let res = parseMarkdown(content, {}) + expect(res.highlights).toEqual([ + { hlGroup: 'CocStrikeThrough', lnum: 0, colStart: 0, colEnd: 3 } + ]) + }) + + it('should render br', async () => { + let content = 'a \nb' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['a', 'b']) + }) + + it('should render code span', async () => { + let content = '`foo`' + let res = parseMarkdown(content, {}) + expect(res.highlights).toEqual([ + { hlGroup: 'CocMarkdownCode', lnum: 0, colStart: 0, colEnd: 3 } + ]) + }) + + it('should render html', async () => { + let content = '
    foo
    ' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual(['foo']) + }) + + it('should render checkbox', async () => { + let content = '- [x] first\n- [ ] second' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual([ + ' * [X] first', ' * [ ] second' + ]) + }) + + it('should render numbered list', async () => { + let content = '1. one\n2. two\n3. three' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual([ + ' 1. one', ' 2. two', ' 3. three' + ]) + }) + + it('should render nested list', async () => { + let content = '- foo\n- bar\n - one\n - two' + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual([ + ' * foo', ' * bar', ' * one', ' * two' + ]) + }) +}) + +describe('parseDocuments', () => { + it('should parse documents with diagnostic filetypes', async () => { + let docs = [{ + filetype: 'Error', + content: 'Error text' + }, { + filetype: 'Warning', + content: 'Warning text' + }] + let res = parseDocuments(docs) + expect(res.lines).toEqual([ + 'Error text', + '─', + 'Warning text' + ]) + expect(res.codes).toEqual([ + { hlGroup: 'CocErrorFloat', startLine: 0, endLine: 1 }, + { hlGroup: 'CocWarningFloat', startLine: 2, endLine: 3 } + ]) + }) + + it('should parse markdown document with filetype document', async () => { + let docs = [{ + filetype: 'typescript', + content: 'const workspace' + }, { + filetype: 'markdown', + content: '**header**' + }] + let res = parseDocuments(docs) + expect(res.lines).toEqual([ + 'const workspace', + '─', + 'header' + ]) + expect(res.highlights).toEqual([{ + hlGroup: 'CocBold', + lnum: 2, + colStart: 0, + colEnd: 6 + }]) + expect(res.codes).toEqual([ + { filetype: 'typescript', startLine: 0, endLine: 1 } + ]) + }) + + it('should parse document with highlights', async () => { + let docs: Documentation[] = [{ + filetype: 'txt', + content: 'foo' + }, { + filetype: 'txt', + content: 'foo bar', + highlights: [{ + lnum: 0, + colStart: 4, + colEnd: 7, + hlGroup: 'String' + }] + }] + let res = parseDocuments(docs) + let { highlights } = res + expect(highlights).toEqual([{ lnum: 2, colStart: 4, colEnd: 7, hlGroup: 'String' }]) + }) + + it('should parse documents with active highlights', async () => { + let docs = [{ + filetype: 'javascript', + content: 'func(foo, bar)', + active: [5, 8] + }, { + filetype: 'javascript', + content: 'func()', + active: [15, 20] + }] + let res = parseDocuments(docs as any) + expect(res.highlights).toEqual([{ colStart: 5, colEnd: 8, lnum: 0, hlGroup: 'CocUnderline' } + ]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/markdown/renderer.test.ts b/sources_non_forked/coc.nvim/src/__tests__/markdown/renderer.test.ts new file mode 100644 index 00000000..f22e78fa --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/markdown/renderer.test.ts @@ -0,0 +1,119 @@ +import { marked } from 'marked' +import Renderer from '../../markdown/renderer' +import * as styles from '../../markdown/styles' +import { parseAnsiHighlights, AnsiResult } from '../../util/ansiparse' + +marked.setOptions({ + renderer: new Renderer() +}) + +function parse(text: string): AnsiResult { + let m = marked(text) + let res = parseAnsiHighlights(m.split(/\n/)[0], true) + return res +} + +describe('styles', () => { + it('should add styles', async () => { + let keys = ['gray', 'magenta', 'bold', 'underline', 'italic', 'strikethrough', 'yellow', 'green', 'blue'] + for (let key of keys) { + let res = styles[key]('text') + expect(res).toContain('text') + } + }) +}) + +describe('Renderer of marked', () => { + it('should create bold highlights', async () => { + let res = parse('**note**.') + expect(res.highlights[0]).toEqual({ + span: [0, 4], + hlGroup: 'CocBold' + }) + }) + + it('should create italic highlights', async () => { + let res = parse('_note_.') + expect(res.highlights[0]).toEqual({ + span: [0, 4], + hlGroup: 'CocItalic' + }) + }) + + it('should create underline highlights for link', async () => { + let res = parse('[baidu](https://baidu.com)') + expect(res.highlights[0]).toEqual({ + span: [0, 5], + hlGroup: 'CocMarkdownLink' + }) + res = parse('https://baidu.com') + expect(res.highlights[0]).toEqual({ + span: [0, 17], + hlGroup: 'CocUnderline' + }) + }) + + it('should parse link', async () => { + // let res = parse('https://doc.rust-lang.org/nightly/core/iter/traits/iterator/Iterator.t.html#map.v') + // console.log(JSON.stringify(res, null, 2)) + let link = 'https://doc.rust-lang.org/nightly/core/iter/traits/iterator/Iterator.t.html#map.v' + let parsed = marked(link) + let res = parseAnsiHighlights(parsed.split(/\n/)[0], true) + expect(res.line).toEqual(link) + expect(res.highlights.length).toBeGreaterThan(0) + expect(res.highlights[0].hlGroup).toBe('CocUnderline') + }) + + it('should create highlight for code span', async () => { + let res = parse('`let foo = "bar"`') + expect(res.highlights[0]).toEqual({ + span: [0, 15], + hlGroup: 'CocMarkdownCode' + }) + }) + + it('should create header highlights', async () => { + let res = parse('# header') + expect(res.highlights[0]).toEqual({ + span: [0, 8], + hlGroup: 'CocMarkdownHeader' + }) + res = parse('## header') + expect(res.highlights[0]).toEqual({ + span: [0, 9], + hlGroup: 'CocMarkdownHeader' + }) + res = parse('### header') + expect(res.highlights[0]).toEqual({ + span: [0, 10], + hlGroup: 'CocMarkdownHeader' + }) + }) + + it('should indent blockquote', async () => { + let res = parse('> header') + expect(res.line).toBe(' header') + }) + + it('should preserve code block', async () => { + let text = '``` js\nconsole.log("foo")\n```' + let m = marked(text) + expect(m.split('\n')).toEqual([ + '``` js', + 'console.log("foo")', + '```', + '' + ]) + }) + + it('should renderer table', async () => { + let text = ` +| Syntax | Description | +| ----------- | ----------- | +| Header | Title | +| Paragraph | Text | +` + let res = marked(text) + expect(res).toContain('Syntax') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/memos.json b/sources_non_forked/coc.nvim/src/__tests__/memos.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/memos.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/attach.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/attach.test.ts new file mode 100644 index 00000000..55f0d544 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/attach.test.ts @@ -0,0 +1,53 @@ +import { Neovim } from '@chemzqm/neovim' +import events from '../../events' +import helper from '../helper' + +function wait(ms: number): Promise { + return new Promise(resolve => { + setTimeout(() => { + resolve() + }, ms) + }) +} +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('attach', () => { + + it('should listen CocInstalled', async () => { + nvim.emit('notification', 'VimEnter') + await helper.wait(100) + }) + + it('should not throw on event handler error', async () => { + events.on('CursorHold', async () => { + throw new Error('error') + }) + let fn = jest.fn() + nvim.emit('request', 'CocAutocmd', ['CursorHold'], { + send: fn + }) + await wait(100) + expect(fn).toBeCalled() + }) + + it('should not throw when plugin method not found', async () => { + let fn = jest.fn() + nvim.emit('request', 'NotExists', [], { + send: fn + }) + await wait(100) + expect(fn).toBeCalled() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/chars.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/chars.test.ts new file mode 100644 index 00000000..022549e7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/chars.test.ts @@ -0,0 +1,74 @@ +import { CancellationTokenSource } from 'vscode-languageserver-protocol' +import { Chars } from '../../model/chars' + +describe('chars keyword option', () => { + it('should match @', () => { + let chars = new Chars('@') + expect(chars.isKeywordChar('a')).toBe(true) + expect(chars.isKeywordChar('z')).toBe(true) + expect(chars.isKeywordChar('A')).toBe(true) + expect(chars.isKeywordChar('Z')).toBe(true) + expect(chars.isKeywordChar('\u205f')).toBe(false) + }) + + it('should match code range', () => { + let chars = new Chars('48-57') + expect(chars.isKeywordChar('0')).toBe(true) + expect(chars.isKeywordChar('9')).toBe(true) + }) + + it('should match @-@', () => { + let chars = new Chars('@-@') + expect(chars.isKeywordChar('@')).toBe(true) + }) + + it('should match single code', () => { + let chars = new Chars('58') + expect(chars.isKeywordChar(':')).toBe(true) + }) + + it('should match single character', () => { + let chars = new Chars('_') + expect(chars.isKeywordChar('_')).toBe(true) + }) +}) + +describe('chars addKeyword', () => { + it('should add keyword', () => { + let chars = new Chars('_') + chars.addKeyword(':') + expect(chars.isKeywordChar(':')).toBe(true) + }) +}) + +describe('chars change keyword', () => { + it('should change keyword', () => { + let chars = new Chars('_') + chars.setKeywordOption(':') + expect(chars.isKeywordChar(':')).toBe(true) + expect(chars.isKeywordChar('_')).toBe(false) + }) +}) + +describe('chars match keywords', () => { + it('should match keywords', async () => { + let chars = new Chars('@') + let source = new CancellationTokenSource() + let res = await chars.matchLines(['foo bar'], 3, source.token) + expect(Array.from(res)).toEqual(['foo', 'bar']) + }) + + it('should consider unicode character as word', async () => { + let chars = new Chars('@') + let res = await chars.matchLines(['blackкофе'], 3) + expect(Array.from(res)).toEqual(['blackкофе']) + }) +}) + +describe('chars isKeyword', () => { + it('should check isKeyword', () => { + let chars = new Chars('@') + expect(chars.isKeyword('foo')).toBe(true) + expect(chars.isKeyword('f@')).toBe(false) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/configurations.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/configurations.test.ts new file mode 100644 index 00000000..e58a80c5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/configurations.test.ts @@ -0,0 +1,617 @@ +import fs from 'fs-extra' +import * as assert from 'assert' +import { ParseError } from 'jsonc-parser' +import os from 'os' +import path from 'path' +import { v1 as uuidv1 } from 'uuid' +import { URI } from 'vscode-uri' +import Configurations from '../../configuration' +import ConfigurationProxy from '../../configuration/shape' +import { convertErrors, removeFromValueTree, getChangedKeys, getConfigurationValue, getKeys, mergeConfigProperties, parseConfiguration, parseContentFromFile } from '../../configuration/util' +import { ConfigurationTarget, IConfigurationModel } from '../../types' +import { CONFIG_FILE_NAME, wait } from '../../util' +import { rmdir } from '../helper' + +const config = fs.readFileSync(path.join(__dirname, './settings.json'), 'utf8') +const workspaceConfigFile = path.resolve(__dirname, `../sample/.vim/${CONFIG_FILE_NAME}`) + +function getConfigurationModel(): IConfigurationModel { + let [, contents] = parseConfiguration(config) + return { contents } +} + +function U(fsPath: string): string { + return URI.file(fsPath).toString() +} + +function createConfigurations(): Configurations { + let userConfigFile = path.join(__dirname, './settings.json') + return new Configurations(userConfigFile) +} + +afterEach(() => { + global.__TEST__ = true +}) + +describe('ConfigurationProxy', () => { + it('should not throw when URI is not valid', async () => { + let proxy = new ConfigurationProxy({}) + proxy.modifyConfiguration(undefined, 'foo') + proxy.modifyConfiguration(URI.parse('ftp:///f'), 'foo') + }) + + it('should create file and parent folder when necessary', async () => { + let folder = path.join(os.tmpdir(), 'a') + if (fs.existsSync(folder)) { + let isFile = fs.statSync(folder).isFile() + if (isFile) { + fs.unlinkSync(folder) + } else { + rmdir(folder) + } + } + let uri = URI.file(path.join(os.tmpdir(), 'a/b/settings.json')) + let proxy = new ConfigurationProxy({}) + proxy.modifyConfiguration(uri, 'foo', true) + let content = fs.readFileSync(uri.fsPath, 'utf8') + expect(JSON.parse(content)).toEqual({ foo: true }) + rmdir(folder) + }) + + it('should get folder from resolver', async () => { + let proxy = new ConfigurationProxy({ + getWorkspaceFolder: (uri: string) => { + let fsPath = URI.parse(uri).fsPath + if (fsPath.startsWith(os.tmpdir())) { + return { uri: URI.file(os.tmpdir()).toString(), name: 'tmp' } + } + if (fsPath.startsWith(os.homedir())) { + return { uri: URI.file(os.homedir()).toString(), name: 'home' } + } + return undefined + }, + root: __dirname + }) + let uri = proxy.getWorkspaceConfig(URI.file(__filename).toString()) + expect(uri).toBeUndefined() + uri = proxy.getWorkspaceConfig(URI.file(path.join(os.tmpdir(), 'foo')).toString()) + expect(uri.fsPath.startsWith(os.tmpdir())).toBe(true) + uri = proxy.getWorkspaceConfig() + expect(uri.fsPath.startsWith(__dirname)).toBe(true) + uri = proxy.getWorkspaceConfig(URI.file(path.join(os.homedir(), 'tmp')).toString()) + expect(uri).toBeUndefined() + proxy = new ConfigurationProxy({}) + uri = proxy.getWorkspaceConfig(URI.file(path.join(os.tmpdir(), 'foo')).toString()) + expect(uri).toBeUndefined() + uri = proxy.getWorkspaceConfig() + expect(uri).toBeUndefined() + }) + + it('should update and remove configuration option', async () => { + let fsPath = path.join(os.tmpdir(), 'my-settings.json') + fs.writeFileSync(fsPath, '{"foo": false}') + let proxy = new ConfigurationProxy({}) + proxy.$updateConfigurationOption(ConfigurationTarget.Workspace, 'bar', true, { resource: URI.file(fsPath) }) + + let content = fs.readFileSync(fsPath, 'utf8') + expect(JSON.parse(content)).toEqual({ foo: false, bar: true }) + proxy.$removeConfigurationOption(ConfigurationTarget.Workspace, 'bar', { resource: URI.file(fsPath) }) + content = fs.readFileSync(fsPath, 'utf8') + expect(JSON.parse(content)).toEqual({ foo: false }) + fs.unlinkSync(fsPath) + }) +}) + +describe('parse configuration', () => { + it('should only split top level dot keys', () => { + let o = { 'x.y': 'foo' } + let [, contents] = parseConfiguration(JSON.stringify(o)) + expect(contents).toEqual({ x: { y: 'foo' } }) + let schema = { 'my.schema': { 'foo.bar': 1 } } + let [, obj] = parseConfiguration(JSON.stringify(schema)) + expect(obj).toEqual({ my: { schema: { 'foo.bar': 1 } } }) + }) + + it('should not parse uri properties', async () => { + let o: any = { + foo: { + 'bar://x': '', + 'file://y': '' + } + } + let [, contents] = parseConfiguration(JSON.stringify(o)) + expect(contents).toEqual({ + foo: { + 'bar://x': '', + 'file://y': '' + } + }) + }) + + it('should merge preperties', async () => { + let res = mergeConfigProperties({ + foo: 'bar', + "x.y.a": "x", + "x.y.b": "y", + "x.t": "z" + }) + expect(res).toEqual({ + foo: 'bar', x: { y: { a: 'x', b: 'y' }, t: 'z' } + }) + }) +}) + +describe('Configurations', () => { + describe('utils', () => { + it('removeFromValueTree: remove a non existing key', () => { + let target = { a: { b: 2 } } + + removeFromValueTree(target, 'c') + + assert.deepStrictEqual(target, { a: { b: 2 } }) + }) + + it('removeFromValueTree: remove a multi segmented key from an object that has only sub sections of the key', () => { + let target = { a: { b: 2 } } + + removeFromValueTree(target, 'a.b.c') + + assert.deepStrictEqual(target, { a: { b: 2 } }) + }) + + it('removeFromValueTree: remove a single segmented key', () => { + let target = { a: 1 } + + removeFromValueTree(target, 'a') + + assert.deepStrictEqual(target, {}) + }) + + it('removeFromValueTree: remove a single segmented key when its value is undefined', () => { + let target = { a: undefined } + + removeFromValueTree(target, 'a') + + assert.deepStrictEqual(target, {}) + }) + + it('removeFromValueTree: remove a multi segmented key when its value is undefined', () => { + let target = { a: { b: 1 } } + + removeFromValueTree(target, 'a.b') + + assert.deepStrictEqual(target, {}) + }) + + it('removeFromValueTree: remove a multi segmented key when its value is array', () => { + let target = { a: { b: [1] } } + + removeFromValueTree(target, 'a.b') + + assert.deepStrictEqual(target, {}) + }) + + it('removeFromValueTree: remove a multi segmented key first segment value is array', () => { + let target = { a: [1] } + + removeFromValueTree(target, 'a.0') + + assert.deepStrictEqual(target, { a: [1] }) + }) + + it('removeFromValueTree: remove when key is the first segment', () => { + let target = { a: { b: 1 } } + + removeFromValueTree(target, 'a') + + assert.deepStrictEqual(target, {}) + }) + + it('removeFromValueTree: remove a multi segmented key when the first node has more values', () => { + let target = { a: { b: { c: 1 }, d: 1 } } + + removeFromValueTree(target, 'a.b.c') + + assert.deepStrictEqual(target, { a: { d: 1 } }) + }) + + it('removeFromValueTree: remove a multi segmented key when in between node has more values', () => { + let target = { a: { b: { c: { d: 1 }, d: 1 } } } + + removeFromValueTree(target, 'a.b.c.d') + + assert.deepStrictEqual(target, { a: { b: { d: 1 } } }) + }) + + it('removeFromValueTree: remove a multi segmented key when the last but one node has more values', () => { + let target = { a: { b: { c: 1, d: 1 } } } + + removeFromValueTree(target, 'a.b.c') + + assert.deepStrictEqual(target, { a: { b: { d: 1 } } }) + }) + + it('should parse content from file', async () => { + let res = parseContentFromFile('') + expect(res).toEqual({ contents: {} }) + }) + + it('should convert errors', () => { + let errors: ParseError[] = [] + for (let i = 0; i < 17; i++) { + errors.push({ + error: i, + offset: 0, + length: 10 + }) + } + let res = convertErrors('file:///1', 'abc', errors) + expect(res.length).toBe(17) + }) + + it('should get all keys', () => { + let res = getKeys({ + foo: { + bar: 1, + from: { + to: 2 + } + }, + bar: [1, 2] + }) + expect(res).toEqual(['foo', 'foo.bar', 'foo.from', 'foo.from.to', 'bar']) + }) + + it('should get configuration value', () => { + let root = { + foo: { + bar: 1, + from: { + to: 2 + } + }, + bar: [1, 2] + } + let res = getConfigurationValue(root, 'foo.from.to', 1) + expect(res).toBe(2) + res = getConfigurationValue(root, 'foo.from', 1) + expect(res).toEqual({ to: 2 }) + }) + + it('should get changed keys #1', () => { + let res = getChangedKeys({ y: 2 }, { x: 1 }) + expect(res).toEqual(['x', 'y']) + }) + + it('should get changed keys #2', () => { + let res = getChangedKeys({ x: 1, c: { d: 4 } }, { x: 1, b: { x: 5 } }) + expect(res).toEqual(['b', 'b.x', 'c', 'c.d']) + }) + + it('should parse configurations', () => { + let { contents } = getConfigurationModel() + expect(contents.foo.bar).toBe(1) + expect(contents.bar.foo).toBe(2) + expect(contents.schema).toEqual({ 'https://example.com': '*.yaml' }) + }) + }) + + describe('addFolderFile()', () => { + it('should add folder as workspace configuration', () => { + let configurations = createConfigurations() + configurations.onDidChange(e => { + let affects = e.affectsConfiguration('coc') + expect(affects).toBe(true) + }) + configurations.addFolderFile(workspaceConfigFile) + let o = configurations.configuration.workspace.contents + expect(o.coc.preferences.rootPath).toBe('./src') + configurations.dispose() + }) + + it('should not add invalid folders', async () => { + let configurations = createConfigurations() + expect(configurations.addFolderFile('ab')).toBe(false) + let configFile = path.join(__dirname, 'settings.json') + expect(configurations.addFolderFile(configFile)).toBe(false) + configFile = path.join(os.homedir(), '.vim/coc-settings.json') + expect(configurations.addFolderFile(configFile)).toBe(false) + }) + + it('should resolve folder configuration when possible', async () => { + let configurations = createConfigurations() + expect(configurations.resolveFolderConfigution('test:///foo')).toBeUndefined() + expect(configurations.resolveFolderConfigution(URI.file(path.join(os.tmpdir(), 'foo')).toString())).toBeUndefined() + let fsPath = path.join(__dirname, `../sample/abc`) + expect(configurations.resolveFolderConfigution(URI.file(fsPath).toString())).toBeDefined() + fsPath = path.join(__dirname, `../sample/foo`) + expect(configurations.resolveFolderConfigution(URI.file(fsPath).toString())).toBeDefined() + }) + }) + + describe('getConfiguration()', () => { + it('should load default configurations', () => { + let conf = new Configurations() + expect(conf.defaults.contents.coc).toBeDefined() + let c = conf.getConfiguration('languageserver') + expect(c).toEqual({}) + expect(c.has('not_exists')).toBe(false) + conf.dispose() + }) + + it('should inspect configuration', async () => { + let conf = new Configurations() + let c = conf.getConfiguration('suggest') + let res = c.inspect('not_exists') + expect(res.defaultValue).toBeUndefined() + expect(res.globalValue).toBeUndefined() + expect(res.workspaceValue).toBeUndefined() + }) + + it('should update user config #1', () => { + let conf = new Configurations() + let fn = jest.fn() + conf.onDidChange(e => { + expect(e.affectsConfiguration('x')).toBe(true) + fn() + }) + conf.updateUserConfig({ x: 1 }) + let config = conf.configuration.user + expect(config.contents).toEqual({ x: 1 }) + expect(fn).toBeCalled() + }) + + it('should update user config #2', () => { + let conf = new Configurations() + conf.updateUserConfig({ x: 1 }) + conf.updateUserConfig({ x: undefined }) + let config = conf.configuration.user + expect(config.contents).toEqual({}) + }) + + it('should update workspace config #1', () => { + let conf = new Configurations() + conf.updateUserConfig({ foo: { bar: 1 } }) + let curr = conf.getConfiguration('foo') + curr.update('bar', 2, false) + curr = conf.getConfiguration('foo') + let n = curr.get('bar') + expect(n).toBe(2) + }) + + it('should update workspace config by create workspace folder settings', async () => { + let folder = path.join(os.tmpdir(), 'a') + let proxy = new ConfigurationProxy({ + getWorkspaceFolder: (uri: string) => { + let fsPath = URI.parse(uri).fsPath + if (fsPath.startsWith(folder)) { + return { uri: U(folder), name: 'tmp' } + } + return undefined + }, + root: __dirname + }) + let conf = new Configurations('', proxy) + let fn = jest.fn() + let resource = U(path.join(folder, 'foo')) + conf.onDidChange(e => { + if (e.affectsConfiguration('foo', resource.toString())) { + fn() + } + }) + global.__TEST__ = false + let curr = conf.getConfiguration(undefined, resource) + curr.update('foo', true) + expect(fn).toBeCalled() + let filepath = path.join(folder, '.vim/coc-settings.json') + let content = fs.readFileSync(filepath, 'utf8') + expect(JSON.parse(content)).toEqual({ foo: true }) + let res = conf.getConfiguration(undefined, resource) + expect(res.foo).toBe(true) + curr = conf.getConfiguration(undefined, resource) + curr.update('foo', undefined) + content = fs.readFileSync(filepath, 'utf8') + expect(JSON.parse(content)).toEqual({}) + rmdir(folder) + }) + + it('should handle errors', () => { + let tmpFile = path.join(os.tmpdir(), uuidv1()) + fs.writeFileSync(tmpFile, '{"x":', 'utf8') + let conf = new Configurations(tmpFile) + let errors = conf.errorItems + expect(errors.length > 1).toBe(true) + conf.dispose() + }) + + it('should change to new folder configuration', () => { + let conf = new Configurations() + conf.addFolderFile(workspaceConfigFile) + let configFile = path.join(__dirname, './settings.json') + conf.addFolderFile(configFile) + let file = path.resolve(__dirname, '../sample/tmp.js') + let fn = jest.fn() + conf.onDidChange(fn) + conf.setFolderConfiguration(URI.file(file).toString()) + let { contents } = conf.workspace + expect(contents.foo).toBeUndefined() + expect(fn).toBeCalled() + conf.dispose() + }) + + it('should get nested property', () => { + let config = createConfigurations() + let conf = config.getConfiguration('servers.c') + let res = conf.get('trace.server', '') + expect(res).toBe('verbose') + config.dispose() + }) + + it('should get user and workspace configuration', () => { + let userConfigFile = path.join(__dirname, './settings.json') + let configurations = new Configurations(userConfigFile) + let data = configurations.configuration.toData() + expect(data.user).toBeDefined() + expect(data.workspace).toBeDefined() + expect(data.defaults).toBeDefined() + let value = configurations.configuration.getValue() + expect(value.foo).toBeDefined() + expect(value.foo.bar).toBe(1) + configurations.dispose() + }) + + it('should override with new value', () => { + let configurations = createConfigurations() + configurations.configuration.defaults.setValue('foo', 1) + let { contents } = configurations.defaults + expect(contents.foo).toBe(1) + configurations.dispose() + }) + + it('should extends defaults', () => { + let configurations = createConfigurations() + configurations.extendsDefaults({ 'a.b': 1 }) + configurations.extendsDefaults({ 'a.b': 2 }) + let o = configurations.defaults.contents + expect(o.a.b).toBe(2) + configurations.dispose() + }) + + it('should update configuration', async () => { + let configurations = createConfigurations() + configurations.addFolderFile(workspaceConfigFile) + let fn = jest.fn() + configurations.onDidChange(e => { + expect(e.affectsConfiguration('foo')).toBe(true) + expect(e.affectsConfiguration('foo.bar')).toBe(true) + expect(e.affectsConfiguration('foo.bar', 'file://tmp/foo.js')).toBe(false) + fn() + }) + let config = configurations.getConfiguration('foo') + let o = config.get('bar') + expect(o).toBe(1) + config.update('bar', 6) + config = configurations.getConfiguration('foo') + expect(config.get('bar')).toBe(6) + expect(fn).toBeCalledTimes(1) + configurations.dispose() + }) + + it('should remove configuration', async () => { + let configurations = createConfigurations() + configurations.addFolderFile(workspaceConfigFile) + let fn = jest.fn() + configurations.onDidChange(e => { + expect(e.affectsConfiguration('foo')).toBe(true) + expect(e.affectsConfiguration('foo.bar')).toBe(true) + fn() + }) + let config = configurations.getConfiguration('foo') + let o = config.get('bar') + expect(o).toBe(1) + config.update('bar', null, true) + config = configurations.getConfiguration('foo') + expect(config.get('bar')).toBeUndefined() + expect(fn).toBeCalledTimes(1) + configurations.dispose() + }) + }) + + describe('watchFile', () => { + it('should watch user config file', async () => { + global.__TEST__ = false + let userConfigFile = path.join(os.tmpdir(), 'settings.json') + fs.writeFileSync(userConfigFile, '{"foo.bar": true}', { encoding: 'utf8' }) + let conf = new Configurations(userConfigFile) + await wait(20) + fs.writeFileSync(userConfigFile, '{"foo.bar": false}', { encoding: 'utf8' }) + await wait(150) + let c = conf.getConfiguration('foo') + let res = c.get('bar') + expect(res).toBe(false) + conf.dispose() + fs.unlinkSync(userConfigFile) + }) + + it('should watch workspace config file', async () => { + global.__TEST__ = false + let configFile = path.join(os.tmpdir(), '.vim/coc-settings.json') + fs.mkdirSync(path.join(os.tmpdir(), '.vim'), { recursive: true }) + fs.writeFileSync(configFile, '{"foo.bar": true}', { encoding: 'utf8' }) + let conf = new Configurations('', { + $updateConfigurationOption: () => {}, + $removeConfigurationOption: () => {}, + getWorkspaceConfig: () => { + return URI.file(configFile) + } + }) + let uri = U(path.join(os.tmpdir(), 'foo')) + let resolved = conf.resolveFolderConfigution(uri) + conf.setFolderConfiguration(uri) + expect(resolved).toBeDefined() + await wait(20) + fs.writeFileSync(configFile, '{"foo.bar": false}', { encoding: 'utf8' }) + await wait(150) + let c = conf.getConfiguration('foo') + let res = c.get('bar') + expect(res).toBe(false) + conf.dispose() + if (fs.existsSync(configFile)) fs.unlinkSync(configFile) + }) + }) + + describe('getFolderConfiguration()', () => { + it('should get folder configuration from uri', async () => { + let conf = new Configurations() + conf.cwd = os.tmpdir() + let res = conf.getFolderConfiguration('untitled:///1') + expect(res[0]).toBeUndefined() + conf = createConfigurations() + res = conf.getFolderConfiguration('untitled:///1') + expect(res[0]).toBeDefined() + }) + + it('should get folder configuration from file', async () => { + let conf = createConfigurations() + let fsPath = path.join(os.tmpdir(), 'a') + let res = conf.getFolderConfiguration(U(fsPath)) + expect(res[0]).toBeUndefined() + }) + + it('should not throw when workspace config not resolved', async () => { + let userConfigFile = path.join(__dirname, './settings.json') + let conf = new Configurations(userConfigFile, { + $updateConfigurationOption: () => {}, + $removeConfigurationOption: () => {}, + getWorkspaceConfig: () => { + return URI.file(userConfigFile) + } + }) + let fsPath = path.join(os.tmpdir(), 'a') + let c = conf.getConfiguration(undefined, U(fsPath)) + c.update('foo', false) + }) + }) + + describe('getWorkspaceConfigUri()', () => { + it('should get config uri for undefined resource', async () => { + let conf = createConfigurations() + let res = conf.getWorkspaceConfigUri() + expect(res).toBeDefined() + }) + + it('should not get config uri same as user config', async () => { + let userConfigFile = path.join(__dirname, './settings.json') + let conf = new Configurations(userConfigFile, { + $updateConfigurationOption: () => {}, + $removeConfigurationOption: () => {}, + getWorkspaceConfig: () => { + return URI.file(userConfigFile) + } + }) + let uri = U(__filename) + let res = conf.getWorkspaceConfigUri(uri) + expect(res).toBeUndefined() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/cursors.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/cursors.test.ts new file mode 100644 index 00000000..a52bf3a1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/cursors.test.ts @@ -0,0 +1,686 @@ +import { Neovim } from '@chemzqm/neovim' +import { Position, Range, TextEdit } from 'vscode-languageserver-types' +import Cursors from '../../cursors' +import CursorsSession, { surrondChanges } from '../../cursors/session' +import TextRange from '../../cursors/textRange' +import { getChange, getDelta, isSurrondChange, isTextChange, SurrondChange, TextChange } from '../../cursors/util' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +let cursors: Cursors +let ns: number + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + ns = await nvim.createNamespace('coc-cursors') + cursors = new Cursors(nvim) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + nvim.pauseNotification() + cursors.reset() + await nvim.resumeNotification() + await helper.reset() +}) + +async function rangeCount(): Promise { + let buf = await nvim.buffer + let markers = await helper.getMarkers(buf.id, ns) + return markers.length +} + +describe('cursors', () => { + describe('surrondChanges()', () => { + it('should check surrond changes', async () => { + expect(surrondChanges([], 0)).toBe(false) + expect(surrondChanges([{ offset: 1, add: 'f' }, { offset: 3, add: 'f' }], 0)).toBe(false) + }) + }) + + describe('getDelta()', () => { + it('should get delta count', async () => { + expect(getDelta({ prepend: [1, 'foo'], append: [1, 'bar'] })).toBe(4) + expect(getDelta({ offset: 0, remove: 2, insert: 'foo' })).toBe(1) + }) + }) + + describe('getChange()', () => { + it('should get surrond change', async () => { + const getText = (newText: string): string => { + let r = new TextRange(0, 0, 'foo') + let res = getChange(r, Range.create(0, 0, 0, 3), newText) as SurrondChange + expect(isSurrondChange(res)).toBe(true) + r.applySurrondChange(res) + return r.text + } + expect(getText('"foo"')).toBe('"foo"') + expect(getText('o')).toBe('o') + expect(getText('')).toBe('') + }) + + it('should get end change', async () => { + const getText = (character: number, newText: string) => { + let start = Position.create(0, character) + let r = new TextRange(0, 0, 'foo') + let res = getChange(r, Range.create(start, r.range.end), newText) as TextChange + expect(isTextChange(res)).toBe(true) + r.applyTextChange(res) + return r.text + } + expect(getText(3, 'bar')).toBe('foobar') + expect(getText(1, '')).toBe('f') + expect(getText(2, 'ba')).toBe('foba') + }) + + it('should get normal change', async () => { + const getText = (start: number, end: number, newText: string) => { + let r = new TextRange(0, 0, 'foo') + let res = getChange(r, Range.create(0, start, 0, end), newText) as TextChange + expect(isTextChange(res)).toBe(true) + r.applyTextChange(res) + return r.text + } + expect(getText(0, 0, 'a')).toBe('afoo') + expect(getText(0, 1, '')).toBe('oo') + expect(getText(0, 2, 'ba')).toBe('bao') + }) + }) + + describe('cancel()', () => { + it('should cancel cursors session', async () => { + cursors.cancel(999) + let doc = await workspace.document + cursors.cancel(doc.bufnr) + await nvim.call('setline', [1, ['a', 'b']]) + await nvim.call('cursor', [1, 1]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'position', 'n') + let activated = await cursors.isActivated() + expect(activated).toBe(true) + cursors.cancel(doc.bufnr) + activated = await cursors.isActivated() + expect(activated).toBe(false) + }) + }) + + describe('select()', () => { + it('should throw with unsupported kind', async () => { + let doc = await workspace.document + let fn = async () => { + await cursors.select(doc.bufnr, 'undefined', 'n') + } + await expect(fn()).rejects.toThrow(/not supported/) + }) + + it('should select by position', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['a', 'b']]) + await nvim.call('cursor', [1, 1]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'position', 'n') + await helper.wait(30) + let n = await rangeCount() + expect(n).toBe(1) + await nvim.setOption('virtualedit', 'onemore') + await nvim.call('cursor', [2, 2]) + await cursors.select(doc.bufnr, 'position', 'n') + n = await rangeCount() + expect(n).toBe(2) + await cursors.select(doc.bufnr, 'position', 'n') + n = await rangeCount() + expect(n).toBe(1) + }) + + it('should select by word', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo', 'bar']]) + await nvim.call('cursor', [1, 1]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'word', 'n') + let n = await rangeCount() + expect(n).toBe(1) + await nvim.call('cursor', [2, 2]) + await cursors.select(doc.bufnr, 'word', 'n') + n = await rangeCount() + expect(n).toBe(2) + await cursors.select(doc.bufnr, 'word', 'n') + n = await rangeCount() + expect(n).toBe(1) + }) + + it('should toggle select', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo', 'bar']]) + await nvim.call('cursor', [1, 1]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'word', 'n') + let n = await rangeCount() + expect(n).toBe(1) + await cursors.select(doc.bufnr, 'word', 'n') + n = await rangeCount() + expect(n).toBe(0) + let activated = await doc.buffer.getVar('coc_cursors_activated') + expect(activated).toBe(0) + }) + + it('should select last character', async () => { + let doc = await workspace.document + await nvim.setOption('virtualedit', 'onemore') + await nvim.call('setline', [1, ['}', '{']]) + await nvim.call('cursor', [1, 2]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'word', 'n') + let n = await rangeCount() + expect(n).toBe(1) + await nvim.call('cursor', [2, 1]) + await doc.synchronize() + await cursors.select(doc.bufnr, 'word', 'n') + n = await rangeCount() + expect(n).toBe(2) + }) + + it('should select by visual range', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['"foo"', '"bar"']]) + await nvim.call('cursor', [1, 1]) + await nvim.command('normal! vE') + await doc.synchronize() + await cursors.select(doc.bufnr, 'range', 'v') + let n = await rangeCount() + expect(n).toBe(1) + await nvim.call('cursor', [2, 1]) + await nvim.command('normal! vE') + await cursors.select(doc.bufnr, 'range', 'v') + n = await rangeCount() + expect(n).toBe(2) + await cursors.select(doc.bufnr, 'range', 'v') + n = await rangeCount() + expect(n).toBe(1) + }) + + it('should select visual blocks', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['let x = "foo"', 'let y = "bar"']]) + await doc.synchronize() + await nvim.call('cursor', [1, 1]) + await nvim.input('') + await nvim.input('je') + await cursors.select(doc.bufnr, 'range', '\x16') + let n = await rangeCount() + expect(n).toBe(2) + }) + + it('should select by operator', async () => { + await nvim.command('nmap x (coc-cursors-operator)') + await nvim.call('setline', [1, ['"short"', '"long"']]) + await nvim.call('cursor', [1, 2]) + await nvim.input('xa"') + await helper.wait(30) + await nvim.call('cursor', [2, 2]) + await nvim.input('xa"') + await helper.wait(30) + await nvim.command('nunmap x') + }) + }) + + describe('addRanges()', () => { + it('should add ranges', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo foo foo', 'bar bar']]) + await doc.synchronize() + let ranges = [ + Range.create(0, 0, 0, 3), + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + Range.create(1, 0, 1, 3), + Range.create(1, 4, 1, 7) + ] + await cursors.addRanges(ranges) + let n = await rangeCount() + expect(n).toBe(5) + }) + }) + + describe('validChange()', () => { + it('should check valid change', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo', 'foo', '']]) + await doc.synchronize() + let ranges = [ + Range.create(0, 0, 0, 3), + Range.create(1, 0, 1, 3), + ] + await cursors.addRanges(ranges) + let session = cursors.getSession(doc.bufnr) + expect(session.validChange(Range.create(0, 0, 1, 0), '')).toBe(false) + expect(session.validChange(Range.create(0, 0, 2, 0), '\n\n')).toBe(false) + expect(session.validChange(Range.create(1, 0, 1, 3), 'bar')).toBe(false) + }) + }) + + describe('onChange()', () => { + let session: CursorsSession + + function edit(sl: number, sc: number, el: number, ec: number, text: string): TextEdit { + let r = Range.create(sl, sc, el, ec) + return TextEdit.replace(r, text) + } + + async function assertEdits(edits: TextEdit[], characters: number[], line?: string) { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo foo foo', '']]) + await doc.synchronize() + let ranges = [ + Range.create(0, 0, 0, 3), + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + ] + await cursors.addRanges(ranges) + session = cursors.getSession(doc.bufnr) + let p = new Promise(resolve => { + let disposable = session.onDidUpdate(() => { + disposable.dispose() + resolve(undefined) + }) + void doc.applyEdits(edits) + }) + await p + if (line != null) { + expect(doc.getline(0)).toBe(line) + } + let arr: number[] = [] + session.currentRanges.forEach(r => { + arr.push(r.start.character, r.end.character) + }) + expect(arr).toEqual(characters) + session.cancel() + } + + it('should adjust on text insert', async () => { + await assertEdits([edit(0, 0, 0, 0, 'bar\n')], [0, 3, 4, 7, 8, 11]) + await assertEdits([edit(0, 0, 0, 0, 'b')], [0, 4, 5, 9, 10, 14], 'bfoo bfoo bfoo') + await assertEdits([edit(0, 1, 0, 1, 'b')], [0, 4, 5, 9, 10, 14], 'fboo fboo fboo') + await assertEdits([edit(0, 3, 0, 3, 'b')], [0, 4, 5, 9, 10, 14], 'foob foob foob') + await assertEdits([edit(0, 3, 0, 4, '\n')], [0, 3, 0, 3, 4, 7], 'foo') + await assertEdits([edit(1, 0, 1, 0, 'bar')], [0, 3, 4, 7, 8, 11]) + await nvim.call('setline', [1, ['foo foo foo', '']]) + await nvim.call('cursor', [1, 4]) + await assertEdits([edit(0, 8, 0, 8, 'b')], [0, 4, 5, 9, 10, 14], 'bfoo bfoo bfoo') + let col = await nvim.call('col', ['.']) + expect(col).toBe(5) + }) + + it('should adjust on text detete', async () => { + await assertEdits([edit(0, 2, 0, 3, '')], [0, 2, 3, 5, 6, 8], 'fo fo fo') + await assertEdits([edit(0, 3, 0, 4, '')], [0, 3, 3, 6, 7, 10], 'foofoo foo') + await assertEdits([edit(0, 4, 0, 7, '')], [0, 0, 1, 1, 2, 2], ' ') + await nvim.setLine('foo foo') + await nvim.call('cursor', [1, 4]) + await assertEdits([edit(0, 3, 0, 7, '')], [0, 3, 4, 7], 'foo foo') + await assertEdits([edit(0, 1, 0, 11, '')], [], 'f') + }) + + it('should adjust on text change', async () => { + await assertEdits([edit(0, 0, 0, 0, '"'), edit(0, 3, 0, 3, '"')], [0, 5, 6, 11, 12, 17], '"foo" "foo" "foo"') + await assertEdits([edit(0, 0, 0, 1, 'b')], [0, 3, 4, 7, 8, 11], 'boo boo boo') + await assertEdits([edit(0, 0, 0, 3, 'ba')], [0, 2, 3, 5, 6, 8], 'ba ba ba') + await nvim.call('setline', [1, ['', '']]) + await nvim.call('cursor', [2, 1]) + await assertEdits([edit(0, 4, 0, 5, 'ba')], [0, 4, 5, 9, 10, 14], 'baoo baoo baoo') + let col = await nvim.call('col', ['.']) + expect(col).toBe(1) + }) + + it('should adjust on undo & redo', async () => { + let doc = await workspace.document + let edits = [edit(0, 0, 0, 0, '"'), edit(0, 3, 0, 3, '"')] + await nvim.call('setline', [1, ['foo foo foo', '']]) + await doc.synchronize() + let ranges = [ + Range.create(0, 0, 0, 3), + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + ] + await cursors.addRanges(ranges) + session = cursors.getSession(doc.bufnr) + let p = new Promise(resolve => { + let disposable = session.onDidUpdate(() => { + disposable.dispose() + resolve(undefined) + }) + void doc.applyEdits(edits) + }) + await p + await nvim.command('undo') + await helper.wait(50) + expect(session.currentRanges).toEqual(ranges) + }) + + it('should highlight on empty content change', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['foo', '']]) + await doc.synchronize() + let ranges = [Range.create(0, 0, 0, 3)] + await cursors.addRanges(ranges) + session = cursors.getSession(doc.bufnr) + await nvim.call('setline', [1, ['foo', '']]) + await doc.synchronize() + let c = await rangeCount() + expect(c).toBe(1) + }) + }) + + describe('applyComposedEdit()', () => { + async function setup(): Promise { + let doc = await workspace.document + await nvim.call('setline', [1, ['bar foo foo', 'foo']]) + await doc.synchronize() + let session = cursors.createSession(doc) + session.addRanges([ + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + Range.create(1, 0, 1, 3), + ]) + return session + } + + it('should check change before first range', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['abc foob foob', 'foob']) + expect(res).toBe(false) + }) + + it('should check change of first range', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar foo foob', 'foob']) + expect(res).toBe(false) + }) + + it('should check delete exceed range', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar fofoo', 'foo']) + expect(res).toBe(false) + }) + + it('should check content prepend', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar bfoo bfoo', 'bfoo']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 8), + Range.create(0, 9, 0, 13), + Range.create(1, 0, 1, 4), + ]) + s = await setup() + doc = await workspace.document + res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar bfoo bfoo', 'xfoo']) + expect(res).toBe(false) + }) + + it('should check content insert', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar fboo fboo', 'fboo']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 8), + Range.create(0, 9, 0, 13), + Range.create(1, 0, 1, 4), + ]) + }) + + it('should check content append', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar foob foob', 'foob']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 8), + Range.create(0, 9, 0, 13), + Range.create(1, 0, 1, 4), + ]) + }) + + it('should check content detete #1', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar oo oo', 'oo']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 6), + Range.create(0, 7, 0, 9), + Range.create(1, 0, 1, 2), + ]) + }) + + it('should check content delete #2', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar ', '']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 4), + Range.create(0, 5, 0, 5), + Range.create(1, 0, 1, 0), + ]) + }) + + it('should check content delete #3', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar fo fo', 'fo']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 6), + Range.create(0, 7, 0, 9), + Range.create(1, 0, 1, 2), + ]) + }) + + it('should check content change #1', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar fa fa', 'fa']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 6), + Range.create(0, 7, 0, 9), + Range.create(1, 0, 1, 2), + ]) + }) + + it('should check content change #1', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar fa fa', 'fa']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 6), + Range.create(0, 7, 0, 9), + Range.create(1, 0, 1, 2), + ]) + }) + + it('should check content change #2', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar ab ab', 'ab']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 6), + Range.create(0, 7, 0, 9), + Range.create(1, 0, 1, 2), + ]) + }) + + it('should check content change #3', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar xfa xfa', 'xfa']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + Range.create(1, 0, 1, 3), + ]) + }) + + it('should check content change #4', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar xfao xfao', 'xfao']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 8), + Range.create(0, 9, 0, 13), + Range.create(1, 0, 1, 4), + ]) + }) + + it('should check surrond add', async () => { + let s = await setup() + let doc = await workspace.document + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar "foo" "foo"', '"foo"']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 9), + Range.create(0, 10, 0, 15), + Range.create(1, 0, 1, 5), + ]) + }) + + it('should check surrond remove', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['bar "foo" "foo"', '"foo"']]) + await doc.synchronize() + let s = cursors.createSession(doc) + s.addRanges([ + Range.create(0, 4, 0, 9), + Range.create(0, 10, 0, 15), + Range.create(1, 0, 1, 5), + ]) + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), ['bar foo foo', 'foo']) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 7), + Range.create(0, 8, 0, 11), + Range.create(1, 0, 1, 3), + ]) + }) + + it('should check surrond change', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['bar "foo" "foo"', '"foo"']]) + await doc.synchronize() + let s = cursors.createSession(doc) + s.addRanges([ + Range.create(0, 4, 0, 9), + Range.create(0, 10, 0, 15), + Range.create(1, 0, 1, 5), + ]) + let res = s.applyComposedEdit(doc.textDocument.lines.slice(), [`bar 'foo' 'foo'`, `'foo'`]) + expect(res).toBe(true) + expect(s.currentRanges).toEqual([ + Range.create(0, 4, 0, 9), + Range.create(0, 10, 0, 15), + Range.create(1, 0, 1, 5), + ]) + }) + }) + + describe('key mappings', () => { + async function setup(): Promise { + let doc = await workspace.document + await nvim.call('setline', [1, ['a', 'b', 'c']]) + await doc.synchronize() + let session = cursors.createSession(doc) + session.addRanges([ + Range.create(0, 0, 0, 1), + Range.create(1, 0, 1, 1), + Range.create(2, 0, 2, 1), + ]) + } + + async function hasKeymap(key): Promise { + let buf = await nvim.buffer + let keymaps = await buf.getKeymap('n') as any + return keymaps.find(o => o.lhs == key) != null + } + + it('should setup cancel keymap', async () => { + await setup() + let count = await rangeCount() + expect(count).toBe(3) + await nvim.input('') + await helper.wait(50) + count = await rangeCount() + expect(count).toBe(0) + let has = await hasKeymap('') + expect(has).toBe(false) + }) + + it('should next key wrapscan', async () => { + await setup() + await nvim.call('cursor', [1, 1]) + const next = async (line: number, character: number) => { + await nvim.input('') + await helper.wait(30) + let cursor = await nvim.call('coc#cursor#position') + expect(cursor).toEqual([line, character]) + } + await next(1, 0) + await next(2, 0) + await next(0, 0) + }) + + it('should previous key wrapscan', async () => { + await setup() + await nvim.call('cursor', [3, 1]) + const prev = async (line: number, character: number) => { + await nvim.input('') + await helper.wait(30) + let cursor = await nvim.call('coc#cursor#position') + expect(cursor).toEqual([line, character]) + } + await prev(1, 0) + await prev(0, 0) + await prev(2, 0) + }) + + it('should next key no wrapscan', async () => { + helper.updateConfiguration('cursors.wrapscan', false) + await setup() + await nvim.call('cursor', [3, 1]) + const next = async (line: number, character: number) => { + await nvim.input('') + await helper.wait(50) + let cursor = await nvim.call('coc#cursor#position') + expect(cursor).toEqual([line, character]) + } + await next(2, 0) + }) + + it('should previous key no wrapscan', async () => { + helper.updateConfiguration('cursors.wrapscan', false) + await setup() + await nvim.call('cursor', [1, 1]) + const prev = async (line: number, character: number) => { + await nvim.input('') + await helper.wait(30) + let cursor = await nvim.call('coc#cursor#position') + expect(cursor).toEqual([line, character]) + } + await prev(0, 0) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/db.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/db.test.ts new file mode 100644 index 00000000..a948293d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/db.test.ts @@ -0,0 +1,60 @@ +import DB from '../../model/db' +import path from 'path' + +let db: DB +beforeAll(async () => { + db = new DB(path.join(__dirname, 'db.json')) +}) + +afterAll(async () => { + db.destroy() +}) + +afterEach(async () => { + db.clear() +}) + +describe('DB', () => { + + test('db.exists()', async () => { + let exists = db.exists('a.b') + expect(exists).toBe(false) + db.push('a.b', { foo: 1 }) + exists = db.exists('a.b.foo') + expect(exists).toBe(true) + }) + + test('db.fetch()', async () => { + let res = await db.fetch('x') + expect(res).toBeUndefined() + db.push('x', 1) + res = await db.fetch('x') + expect(res).toBe(1) + db.push('x', { foo: 1 }) + res = await db.fetch('x') + expect(res).toEqual({ foo: 1 }) + }) + + test('db.delete()', async () => { + db.push('foo.bar', 1) + db.delete('foo.bar') + let exists = db.exists('foo.bar') + expect(exists).toBe(false) + }) + + test('db.push()', async () => { + db.push('foo.x', 1) + db.push('foo.y', '2') + db.push('foo.z', true) + db.push('foo.n', null) + db.push('foo.o', { x: 1 }) + let res = db.fetch('foo') + expect(res).toEqual({ + x: 1, + y: '2', + z: true, + n: null, + o: { x: 1 } + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts new file mode 100644 index 00000000..6204c2dc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts @@ -0,0 +1,348 @@ +import helper from '../helper' +import { Neovim } from '@chemzqm/neovim' +import { DiagnosticBuffer } from '../../diagnostic/buffer' +import { Range, DiagnosticSeverity, Diagnostic, DiagnosticTag, Position, TextEdit } from 'vscode-languageserver-types' +import workspace from '../../workspace' + +let nvim: Neovim +const config: any = { + autoRefresh: true, + checkCurrentLine: false, + locationlistUpdate: true, + enableSign: true, + enableHighlightLineNumber: true, + enableMessage: 'always', + messageTarget: 'echo', + messageDelay: 250, + refreshOnInsertMode: false, + virtualTextSrcId: 99, + virtualText: false, + virtualTextCurrentLineOnly: true, + virtualTextPrefix: " ", + virtualTextLines: 3, + virtualTextLineSeparator: " \\ ", + displayByAle: false, + level: DiagnosticSeverity.Hint, + signPriority: 11, + errorSign: '>>', + warningSign: '>>', + infoSign: '>>', + hintSign: '>>', + filetypeMap: { + default: '' + }, +} + +async function createDiagnosticBuffer(): Promise { + let doc = await workspace.document + return new DiagnosticBuffer(nvim, doc, config, () => { + // noop + }) +} + +function createDiagnostic(msg: string, range?: Range, severity?: DiagnosticSeverity, tags?: DiagnosticTag[]): Diagnostic & { collection: string } { + range = range ? range : Range.create(0, 0, 0, 1) + return Object.assign(Diagnostic.create(range, msg, severity || DiagnosticSeverity.Error, 999, 'test'), { collection: 'test', tags }) +} + +let ns: number +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + ns = await nvim.createNamespace('coc-diagnostic') +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('diagnostic buffer', () => { + describe('refresh()', () => { + it('should add signs', async () => { + let diagnostics = [createDiagnostic('foo'), createDiagnostic('bar')] + let buf = await createDiagnosticBuffer() + buf.addSigns('a', diagnostics) + await helper.wait(30) + let res = await nvim.call('sign_getplaced', [buf.bufnr, { group: 'CocDiagnostica' }]) + let signs = res[0].signs + expect(signs).toBeDefined() + expect(signs[0].name).toBe('CocError') + }) + + it('should filter sign by signLevel', async () => { + config.signLevel = DiagnosticSeverity.Error + let range = Range.create(0, 0, 0, 3) + let diagnostics = [createDiagnostic('foo', range, DiagnosticSeverity.Warning), createDiagnostic('bar', range, DiagnosticSeverity.Warning)] + let buf = await createDiagnosticBuffer() + buf.addSigns('a', diagnostics) + await helper.wait(30) + let res = await nvim.call('sign_getplaced', [buf.bufnr, { group: 'CocDiagnostica' }]) + config.signLevel = undefined + let signs = res[0].signs + expect(signs).toBeDefined() + expect(signs.length).toBe(0) + }) + + it('should set diagnostic info', async () => { + let r = Range.create(0, 1, 0, 2) + let diagnostics = [ + createDiagnostic('foo', r, DiagnosticSeverity.Error), + createDiagnostic('bar', r, DiagnosticSeverity.Warning), + createDiagnostic('foo', r, DiagnosticSeverity.Hint), + createDiagnostic('bar', r, DiagnosticSeverity.Information) + ] + let buf = await createDiagnosticBuffer() + await buf.update('', diagnostics) + let buffer = await nvim.buffer + let res = await buffer.getVar('coc_diagnostic_info') + expect(res).toEqual({ + lnums: [1, 1, 1, 1], + information: 1, + hint: 1, + warning: 1, + error: 1 + }) + }) + + it('should add highlight', async () => { + let buf = await createDiagnosticBuffer() + let doc = workspace.getDocument(buf.bufnr) + await nvim.setLine('abc') + await doc.patchChange(true) + nvim.pauseNotification() + buf.updateHighlights('', [ + createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Error), + createDiagnostic('bar', Range.create(0, 0, 0, 1), DiagnosticSeverity.Warning) + ]) + await nvim.resumeNotification() + let markers = await helper.getExtmarkers(buf.bufnr, ns) + expect(markers).toEqual([ + [0, 0, 0, 1, 'CocWarningHighlight'], + [0, 0, 0, 1, 'CocErrorHighlight'] + ]) + nvim.pauseNotification() + buf.updateHighlights('', []) + await nvim.resumeNotification() + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any[] + expect(res.length).toBe(0) + }) + + it('should add deprecated highlight', async () => { + let diagnostic = createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Information, [DiagnosticTag.Deprecated]) + let buf = await createDiagnosticBuffer() + let doc = workspace.getDocument(buf.bufnr) + await nvim.setLine('foo') + await doc.patchChange(true) + nvim.pauseNotification() + buf.updateHighlights('', [diagnostic]) + await nvim.resumeNotification() + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, {}]) as [number, number, number][] + expect(res.length).toBe(1) + }) + + it('should not refresh for empty diagnostics', async () => { + let buf: any = await createDiagnosticBuffer() + let fn = jest.fn() + buf.refresh = () => { + fn() + } + buf.update('c', []) + expect(fn).toBeCalledTimes(0) + }) + + it('should refresh when content changes is empty', async () => { + let diagnostic = createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Error) + let buf = await createDiagnosticBuffer() + let doc = workspace.getDocument(buf.bufnr) + await nvim.setLine('foo') + doc._forceSync() + nvim.pauseNotification() + buf.updateHighlights('', [diagnostic]) + await nvim.resumeNotification() + await nvim.setLine('foo') + await doc.patchChange(true) + doc._forceSync() + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(1) + }) + }) + + describe('showVirtualText()', () => { + beforeEach(async () => { + config.virtualText = true + config.virtualTextSrcId = await nvim.createNamespace('diagnostics-virtualText') + }) + afterEach(() => { + config.virtualText = false + config.virtualTextCurrentLineOnly = true + config.virtualTextAlignRight = false + config.virtualTextWinCol = null + config.virtualTextLevel = null + }) + + it('should show virtual text on current line', async () => { + let diagnostic = createDiagnostic('foo') + let buf = await createDiagnosticBuffer() + let diagnostics = [diagnostic] + await buf.update('', diagnostics) + let ns = config.virtualTextSrcId + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(1) + let texts = res[0][3].virt_text + expect(texts[0]).toEqual([' foo', 'CocErrorVirtualText']) + }) + + it('should show virtual text align right', async () => { + config.virtualTextAlignRight = true + let diagnostic = createDiagnostic('foo') + let buf = await createDiagnosticBuffer() + let diagnostics = [diagnostic] + await buf.update('', diagnostics) + let ns = config.virtualTextSrcId + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(1) + let texts = res[0][3].virt_text + expect(texts[0]).toEqual([' foo', 'CocErrorVirtualText']) + }) + + it('should show virtual text at window column', async () => { + config.virtualTextWinCol = 90 + let diagnostic = createDiagnostic('foo') + let buf = await createDiagnosticBuffer() + let diagnostics = [diagnostic] + await buf.update('', diagnostics) + let ns = config.virtualTextSrcId + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(1) + let texts = res[0][3].virt_text + expect(texts[0]).toEqual([' foo', 'CocErrorVirtualText']) + }) + + it('should virtual text on all lines', async () => { + config.virtualTextCurrentLineOnly = false + let buf = await createDiagnosticBuffer() + let diagnostics = [ + createDiagnostic('foo', Range.create(0, 0, 0, 1)), + createDiagnostic('bar', Range.create(1, 0, 1, 1)), + ] + await buf.update('', diagnostics) + let ns = config.virtualTextSrcId + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(2) + }) + + it('should filter by virtualTextLevel', async () => { + config.virtualTextLevel = DiagnosticSeverity.Error + let buf = await createDiagnosticBuffer() + let diagnostics = [ + createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Error), + createDiagnostic('bar', Range.create(1, 0, 1, 1), DiagnosticSeverity.Warning), + ] + await buf.update('', diagnostics) + let ns = config.virtualTextSrcId + let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any + expect(res.length).toBe(1) + }) + }) + + describe('updateLocationList()', () => { + beforeEach(async () => { + config.locationlistUpdate = true + }) + afterEach(() => { + config.locationlistUpdate = false + }) + + it('should update location list', async () => { + let buf = await createDiagnosticBuffer() + await nvim.call('setloclist', [0, [], 'r', { title: 'Diagnostics of coc', items: [] }]) + await buf.update('a', [createDiagnostic('foo')]) + let res = await nvim.eval(`getloclist(bufwinid(${buf.bufnr}))`) as any[] + expect(res.length).toBe(1) + expect(res[0].text).toBe('[test 999] foo [E]') + }) + }) + + describe('clear()', () => { + let config = workspace.getConfiguration('diagnostic') + beforeEach(() => { + config.update('virtualText', true) + }) + afterEach(() => { + config.update('virtualText', false) + }) + + it('should clear all diagnostics', async () => { + let diagnostic = createDiagnostic('foo') + let buf = await createDiagnosticBuffer() + let diagnostics = [diagnostic] + await buf.update('', diagnostics) + await helper.wait(50) + buf.clear() + await helper.wait(50) + let buffer = await nvim.buffer + let res = await buffer.getVar("coc_diagnostic_info") + expect(res == null).toBe(true) + }) + }) + + describe('isEnabled()', () => { + it('should return false when buffer disposed', async () => { + let buf = await createDiagnosticBuffer() + await nvim.command(`bd! ${buf.bufnr}`) + buf.dispose() + let res = await buf.isEnabled() + expect(res).toBe(false) + let arr = buf.getHighlightItems([]) + expect(arr.length).toBe(0) + }) + }) + + describe('getHighlightItems()', () => { + it('should get highlights', async () => { + let buf = await createDiagnosticBuffer() + let doc = workspace.getDocument(workspace.bufnr) + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar')]) + let diagnostics = [ + createDiagnostic('one', Range.create(0, 0, 0, 1), DiagnosticSeverity.Warning), + createDiagnostic('one', Range.create(0, 1, 0, 2), DiagnosticSeverity.Warning), + createDiagnostic('two', Range.create(0, 0, 2, 3), DiagnosticSeverity.Error), + createDiagnostic('three', Range.create(1, 0, 1, 2), DiagnosticSeverity.Hint), + ] + diagnostics[0].tags = [DiagnosticTag.Unnecessary] + diagnostics[1].tags = [DiagnosticTag.Deprecated] + let res = buf.getHighlightItems(diagnostics) + expect(res.length).toBe(5) + expect(res.map(o => o.hlGroup)).toEqual([ + 'CocUnusedHighlight', + 'CocErrorHighlight', + 'CocDeprecatedHighlight', + 'CocHintHighlight', + 'CocErrorHighlight' + ]) + }) + }) + + describe('getDiagnostics()', () => { + it('should get sorted diagnostics', async () => { + let buf = await createDiagnosticBuffer() + let diagnostics = [ + createDiagnostic('three', Range.create(0, 1, 0, 2), DiagnosticSeverity.Error), + createDiagnostic('one', Range.create(0, 0, 0, 2), DiagnosticSeverity.Warning), + createDiagnostic('two', Range.create(0, 0, 0, 2), DiagnosticSeverity.Error), + ] + diagnostics[0].tags = [DiagnosticTag.Unnecessary] + await buf.reset({ + x: diagnostics, + y: [createDiagnostic('four', Range.create(0, 0, 0, 2), DiagnosticSeverity.Error)] + }) + let res = buf.getDiagnosticsAt(Position.create(0, 1), false) + let arr = res.map(o => o.message) + expect(arr).toEqual(['four', 'two', 'three', 'one']) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts new file mode 100644 index 00000000..1aab60d9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts @@ -0,0 +1,101 @@ +import DiagnosticCollection from '../../diagnostic/collection' +import { Diagnostic, Range } from 'vscode-languageserver-types' + +function createDiagnostic(msg: string, range?: Range): Diagnostic { + range = range ? range : Range.create(0, 0, 0, 1) + return Diagnostic.create(range, msg) +} + +describe('diagnostic collection', () => { + + it('should create collection', () => { + let collection = new DiagnosticCollection('test') + expect(collection.name).toBe('test') + }) + + it('should set diagnostic with uri', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + collection.set(uri, [diagnostic]) + expect(collection.get(uri).length).toBe(1) + collection.set(uri, []) + expect(collection.get(uri).length).toBe(0) + }) + + it('should clear diagnostics with null as diagnostics', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + collection.set(uri, [diagnostic]) + expect(collection.get(uri).length).toBe(1) + collection.set(uri, null) + expect(collection.get(uri).length).toBe(0) + }) + + it('should clear diagnostics with undefined as diagnostics in entries', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let entries: [string, Diagnostic[] | null][] = [ + ['file:1', [diagnostic]], + ['file:1', undefined] + ] + let uri = 'file:///1' + collection.set(entries) + expect(collection.get(uri).length).toBe(0) + }) + + it('should set diagnostics with entries', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + let other = 'file:///2' + let entries: [string, Diagnostic[]][] = [ + [uri, [diagnostic]], + [other, [diagnostic]], + [uri, [createDiagnostic('other')]] + ] + collection.set(entries) + expect(collection.get(uri).length).toBe(2) + expect(collection.get(other).length).toBe(1) + }) + + it('should delete diagnostics for uri', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + collection.set(uri, [diagnostic]) + collection.delete(uri) + expect(collection.get(uri).length).toBe(0) + }) + + it('should clear all diagnostics', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + let fn = jest.fn() + collection.set(uri, [diagnostic]) + collection.onDidDiagnosticsChange(fn) + collection.clear() + expect(collection.get(uri).length).toBe(0) + expect(fn).toBeCalledTimes(1) + }) + + it('should call for every uri with diagnostics', () => { + let collection = new DiagnosticCollection('test') + let diagnostic = createDiagnostic('error') + let uri = 'file:///1' + let other = 'file:///2' + let entries: [string, Diagnostic[]][] = [ + [uri, [diagnostic]], + [other, [diagnostic]], + [uri, [createDiagnostic('other')]] + ] + collection.set(entries) + let arr: string[] = [] + collection.forEach(uri => { + arr.push(uri) + }) + expect(arr).toEqual([uri, other]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts new file mode 100644 index 00000000..522ab951 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts @@ -0,0 +1,677 @@ +import { Neovim } from '@chemzqm/neovim' +import os from 'os' +import path from 'path' +import { Diagnostic, DiagnosticSeverity, DiagnosticTag, Location, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import manager from '../../diagnostic/manager' +import { getNameFromSeverity, severityLevel } from '../../diagnostic/util' +import Document from '../../model/document' +import window from '../../window' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +function createDiagnostic(msg: string, range?: Range, severity?: DiagnosticSeverity): Diagnostic { + range = range ? range : Range.create(0, 0, 0, 1) + return Diagnostic.create(range, msg, severity || DiagnosticSeverity.Error) +} + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + manager.reset() + await helper.reset() +}) + +async function createDocument(name?: string): Promise { + let doc = await helper.createDocument(name) + let collection = manager.create('test') + let diagnostics: Diagnostic[] = [] + await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], { + start: 0, + end: -1, + strictIndexing: false + }) + await doc.synchronize() + diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error)) + diagnostics.push(createDiagnostic('warning', Range.create(0, 5, 0, 6), DiagnosticSeverity.Warning)) + diagnostics.push(createDiagnostic('information', Range.create(1, 0, 1, 1), DiagnosticSeverity.Information)) + diagnostics.push(createDiagnostic('hint', Range.create(1, 2, 1, 3), DiagnosticSeverity.Hint)) + diagnostics.push(createDiagnostic('error', Range.create(2, 0, 2, 2), DiagnosticSeverity.Error)) + collection.set(doc.uri, diagnostics) + return doc +} + +describe('diagnostic manager', () => { + describe('setLocationlist()', () => { + it('should set location list', async () => { + let doc = await createDocument() + await manager.setLocationlist(doc.bufnr) + let res = await nvim.call('getloclist', [doc.bufnr]) as any[] + expect(res.length).toBeGreaterThan(2) + helper.updateConfiguration('diagnostic.locationlistLevel', 'error') + await manager.setLocationlist(doc.bufnr) + res = await nvim.call('getloclist', [doc.bufnr]) as any[] + expect(res.length).toBe(2) + }) + + it('should throw when diagnostic disabled', async () => { + helper.updateConfiguration('diagnostic.enable', false) + let fn = async () => { + let bufnr = await nvim.call('bufnr', ['%']) + await manager.setLocationlist(bufnr) + } + await expect(fn()).rejects.toThrow(/not enabled/) + }) + + it('should throw when buffer not attached', async () => { + await nvim.command(`vnew +setl\\ buftype=nofile`) + let doc = await workspace.document + let fn = async () => { + await manager.setLocationlist(doc.bufnr) + } + await expect(fn()).rejects.toThrow(/not/) + }) + }) + + describe('events', () => { + it('should delay refresh when buffer visible', async () => { + let doc = await helper.createDocument() + await helper.edit() + let collection = manager.create('foo') + let diagnostics: Diagnostic[] = [] + await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], { + start: 0, + end: -1, + strictIndexing: false + }) + await doc.synchronize() + diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error)) + collection.set(doc.uri, diagnostics) + await helper.wait(20) + let buf = doc.buffer + let val = await buf.getVar('coc_diagnostic_info') as any + expect(val == null).toBe(true) + let ns = await nvim.createNamespace('coc-diagnosticfoo') + let markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBe(0) + await nvim.command(`b ${buf.id}`) + await helper.waitFor('eval', ['empty(get(b:,"coc_diagnostic_info",{}))'], 0) + }) + + it('should delay refresh on InsertLeave', async () => { + let doc = await workspace.document + await nvim.input('i') + let collection = manager.create('foo') + let diagnostics: Diagnostic[] = [] + await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], { + start: 0, + end: -1, + strictIndexing: false + }) + await doc.synchronize() + diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error)) + collection.set(doc.uri, diagnostics) + await helper.wait(30) + let buf = doc.buffer + let val = await buf.getVar('coc_diagnostic_info') as any + expect(val == null).toBe(true) + let ns = await nvim.createNamespace('coc-diagnosticfoo') + let markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBe(0) + await nvim.input('') + await helper.wait(30) + markers = await buf.getExtMarks(ns, 0, -1) + expect(markers.length).toBe(1) + }) + + it('should show diagnostic virtual text on CursorMoved', async () => { + let config = workspace.getConfiguration('diagnostic') + config.update('virtualText', true) + config.update('virtualTextCurrentLineOnly', true) + let doc = await createDocument() + await helper.wait(30) + let lnum = await nvim.call('line', ['.']) + let markers = await doc.buffer.getExtMarks(manager.config.virtualTextSrcId, 0, -1, { details: true }) + expect(markers.length).toBe(2) + expect(markers[0][1]).toBe(lnum - 1) + expect(markers[1][1]).toBe(lnum - 1) + await manager.toggleDiagnosticBuffer(doc.bufnr) + await nvim.call('cursor', [1, 3]) + await helper.wait(30) + markers = await doc.buffer.getExtMarks(manager.config.virtualTextSrcId, 0, -1, { details: true }) + expect(markers.length).toBe(0) + }) + }) + + describe('refresh()', () => { + it('should refresh on buffer create', async () => { + let uri = URI.file(path.join(path.dirname(__dirname), 'doc')).toString() + let fn = jest.fn() + let disposable = manager.onDidRefresh(() => { + fn() + }) + let collection = manager.create('tmp') + let diagnostic = createDiagnostic('My Error') + collection.set(uri, [diagnostic]) + let doc = await helper.createDocument('doc') + await helper.wait(30) + let val = await doc.buffer.getVar('coc_diagnostic_info') as any + expect(fn).toBeCalled() + expect(val).toBeDefined() + expect(val.error).toBe(1) + collection.dispose() + disposable.dispose() + }) + }) + + describe('toggleDiagnostic()', () => { + it('should toggle diagnostics for all buffer', async () => { + let doc = await createDocument() + await helper.wait(50) + manager.toggleDiagnostic() + await helper.wait(50) + let val = await doc.buffer.getVar('coc_diagnostic_info') as any + expect(val).toBe(null) + manager.toggleDiagnostic() + await helper.wait(50) + val = await doc.buffer.getVar('coc_diagnostic_info') as any + expect(val).toBeDefined() + expect(val.error).toBe(2) + }) + }) + + describe('getDiagnosticList()', () => { + it('should get all diagnostics', async () => { + await createDocument() + let collection = manager.create('test') + let fsPath = await createTmpFile('foo') + let doc = await helper.createDocument(fsPath) + let diagnostics: Diagnostic[] = [] + diagnostics.push(createDiagnostic('error', Range.create(0, 0, 0, 1), DiagnosticSeverity.Error)) + diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 3), DiagnosticSeverity.Warning)) + collection.set(doc.uri, diagnostics) + let list = await manager.getDiagnosticList() + expect(list).toBeDefined() + expect(list.length).toBeGreaterThanOrEqual(5) + expect(list[0].severity).toBe('Error') + expect(list[1].severity).toBe('Error') + expect(list[2].severity).toBe('Error') + }) + + it('should filter diagnostics by configuration', async () => { + let config = workspace.getConfiguration('diagnostic') + config.update('level', 'warning') + config.update('showUnused', false) + config.update('showDeprecated', false) + let doc = await createDocument() + let diagnostics = manager.getDiagnostics(doc.uri)['test'] + diagnostics[0].tags = [DiagnosticTag.Unnecessary] + diagnostics[2].tags = [DiagnosticTag.Deprecated] + let list = await manager.getDiagnosticList() + expect(list.length).toBe(3) + let res = manager.getDiagnostics(doc.uri)['test'] + expect(res.length).toBe(1) + let ranges = manager.getSortedRanges(doc.uri) + expect(ranges.length).toBe(3) + }) + }) + + describe('preview()', () => { + it('should not throw with empty diagnostics', async () => { + await manager.preview() + let tabpage = await nvim.tabpage + let wins = await tabpage.windows + expect(wins.length).toBe(1) + }) + + it('should open preview window', async () => { + await createDocument() + await nvim.call('cursor', [1, 3]) + await manager.preview() + let res = await nvim.call('coc#window#find', ['&previewwindow', 1]) + expect(res).toBeDefined() + }) + }) + + describe('setConfigurationErrors()', () => { + it('should set configuration errors', async () => { + let doc = await workspace.document + let errors = [{ + location: Location.create(doc.uri, Range.create(0, 0, 1, 0)), + message: 'foo', + }, { + location: Location.create(doc.uri, Range.create(1, 0, 2, 0)), + message: 'bar', + }] + manager.setConfigurationErrors(errors) + await helper.wait(50) + let res = manager.getDiagnostics(doc.uri) + expect(res.config.length).toBe(2) + manager.setConfigurationErrors() + await helper.wait(50) + res = manager.getDiagnostics(doc.uri) + expect(res.config).toBeUndefined() + }) + }) + + describe('create()', () => { + it('should create diagnostic collection', async () => { + let doc = await workspace.document + let collection = manager.create('test') + collection.set(doc.uri, [createDiagnostic('foo')]) + await helper.wait(50) + let info = await doc.buffer.getVar('coc_diagnostic_info') + expect(info).toBeDefined() + await nvim.command('bd!') + await helper.wait(50) + }) + }) + + describe('getSortedRanges()', () => { + it('should get sorted ranges of document', async () => { + let doc = await workspace.document + await nvim.call('setline', [1, ['a', 'b', 'c']]) + let collection = manager.create('test') + let diagnostics: Diagnostic[] = [] + diagnostics.push(createDiagnostic('x', Range.create(0, 0, 0, 1))) + diagnostics.push(createDiagnostic('y', Range.create(0, 1, 0, 2))) + diagnostics.push(createDiagnostic('z', Range.create(1, 0, 1, 2))) + collection.set(doc.uri, diagnostics) + let ranges = manager.getSortedRanges(doc.uri) + expect(ranges[0]).toEqual(Range.create(0, 0, 0, 1)) + expect(ranges[1]).toEqual(Range.create(0, 1, 0, 2)) + expect(ranges[2]).toEqual(Range.create(1, 0, 1, 2)) + ranges = manager.getSortedRanges(doc.uri, 'error') + expect(ranges.length).toBe(3) + expect(manager.getSortedRanges(doc.uri, 'warning').length).toBe(0) + }) + }) + + describe('getDiagnosticsInRange', () => { + it('should get diagnostics in range', async () => { + let doc = await workspace.document + let collection = manager.create('test') + let diagnostics: Diagnostic[] = [] + await doc.buffer.setLines(['foo bar foo bar', 'foo bar'], { + start: 0, + end: -1, + strictIndexing: false + }) + await doc.synchronize() + diagnostics.push(createDiagnostic('a', Range.create(0, 0, 0, 1))) + diagnostics.push(createDiagnostic('b', Range.create(0, 2, 0, 3))) + diagnostics.push(createDiagnostic('c', Range.create(1, 0, 1, 2))) + collection.set(doc.uri, diagnostics) + let res = manager.getDiagnosticsInRange(doc.textDocument, Range.create(0, 0, 0, 3)) + expect(res.length).toBe(2) + }) + }) + + describe('getCurrentDiagnostics', () => { + it('should get diagnostics under cursor', async () => { + let config = workspace.getConfiguration('diagnostic') + await createDocument() + let diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBe(0) + await nvim.call('cursor', [1, 4]) + diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBe(1) + config.update('checkCurrentLine', true) + await nvim.call('cursor', [1, 2]) + diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBe(2) + }) + + it('should get empty diagnostic at end of line', async () => { + let doc = await workspace.document + await nvim.setLine('foo') + doc.forceSync() + await nvim.command('normal! $') + let diagnostic = Diagnostic.create(Range.create(0, 3, 1, 0), 'error', DiagnosticSeverity.Error) + let collection = manager.create('empty') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.bufnr) + let diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBeGreaterThanOrEqual(1) + expect(diagnostics[0].message).toBe('error') + collection.dispose() + await manager.refreshBuffer(99) + }) + + it('should get diagnostic next to end of line', async () => { + let doc = await workspace.document + await nvim.setLine('foo') + doc.forceSync() + await nvim.command('normal! $') + let diagnostic = Diagnostic.create(Range.create(0, 3, 0, 4), 'error', DiagnosticSeverity.Error) + let collection = manager.create('empty') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.bufnr) + let diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBeGreaterThanOrEqual(1) + expect(diagnostics[0].message).toBe('error') + collection.dispose() + }) + + it('should get diagnostic with empty range at end of line', async () => { + let doc = await workspace.document + await nvim.setLine('foo') + doc.forceSync() + await nvim.command('normal! $') + let diagnostic = Diagnostic.create(Range.create(0, 3, 1, 0), 'error', DiagnosticSeverity.Error) + let collection = manager.create('empty') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.bufnr) + let diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBeGreaterThanOrEqual(1) + expect(diagnostics[0].message).toBe('error') + collection.dispose() + }) + + it('should get diagnostic pass end of the buffer lines', async () => { + let doc = await workspace.document + await nvim.setLine('foo') + doc.forceSync() + await nvim.command('normal! ^') + let diagnostic = Diagnostic.create(Range.create(1, 0, 1, 0), 'error', DiagnosticSeverity.Error) + let collection = manager.create('empty') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.bufnr) + let diagnostics = await manager.getCurrentDiagnostics() + expect(diagnostics.length).toBeGreaterThanOrEqual(1) + expect(diagnostics[0].message).toBe('error') + collection.dispose() + }) + + }) + + describe('jumpRelated', () => { + it('should does nothing when no diagnostic exists', async () => { + let doc = await workspace.document + await nvim.call('cursor', [1, 1]) + await manager.jumpRelated() + let bufnr = await nvim.eval('bufnr("%")') + expect(bufnr).toBe(doc.bufnr) + }) + + it('should does nothing when no related information exists', async () => { + let doc = await createDocument() + await nvim.call('cursor', [1, 4]) + await manager.jumpRelated() + let bufnr = await nvim.eval('bufnr("%")') + expect(bufnr).toBe(doc.bufnr) + }) + + it('should jump to related position', async () => { + let doc = await workspace.document + let range = Range.create(0, 0, 0, 10) + let location = Location.create(URI.file(__filename).toString(), range) + let diagnostic = Diagnostic.create(range, 'msg', DiagnosticSeverity.Error, 1000, 'test', + [{ location, message: 'test' }]) + let collection = manager.create('positions') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.uri) + await nvim.call('cursor', [1, 1]) + await manager.jumpRelated() + await helper.wait(100) + let bufname = await nvim.call('bufname', '%') + expect(bufname).toMatch('diagnosticManager') + }) + + it('should open location list', async () => { + let doc = await workspace.document + let range = Range.create(0, 0, 0, 10) + let diagnostic = Diagnostic.create(range, 'msg', DiagnosticSeverity.Error, 1000, 'test', + [{ + location: Location.create(URI.file(__filename).toString(), Range.create(1, 0, 1, 10)), + message: 'foo' + }, { + location: Location.create(URI.file(__filename).toString(), Range.create(2, 0, 2, 10)), + message: 'bar' + }]) + let collection = manager.create('positions') + collection.set(doc.uri, [diagnostic]) + await manager.refreshBuffer(doc.uri) + await nvim.call('cursor', [1, 1]) + await manager.jumpRelated() + await helper.waitFor('bufname', ['%'], 'list:///location') + await nvim.input('') + }) + }) + + describe('jumpPrevious & jumpNext', () => { + it('should jump to previous', async () => { + let doc = await createDocument() + await nvim.command('normal! G$') + let ranges = manager.getSortedRanges(doc.uri) + ranges.reverse() + for (let i = 0; i < ranges.length; i++) { + await manager.jumpPrevious() + let pos = await window.getCursorPosition() + expect(pos).toEqual(ranges[i].start) + } + await manager.jumpPrevious() + }) + + it('should jump to next', async () => { + let doc = await createDocument() + await nvim.call('cursor', [0, 0]) + let ranges = manager.getSortedRanges(doc.uri) + for (let i = 0; i < ranges.length; i++) { + await manager.jumpNext() + let pos = await window.getCursorPosition() + expect(pos).toEqual(ranges[i].start) + } + await manager.jumpNext() + }) + + it('should not throw for buffer not attached', async () => { + await nvim.command('edit foo | setl buftype=nofile') + let doc = await workspace.document + expect(doc.attached).toBe(false) + await manager.jumpNext() + await manager.jumpPrevious() + }) + + it('should respect wrapscan', async () => { + await createDocument() + await nvim.command('setl nowrapscan') + await nvim.command('normal! G$') + await manager.jumpNext() + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 3, character: 2 }) + await nvim.command('normal! gg0') + await manager.jumpPrevious() + pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 0 }) + }) + }) + + describe('diagnostic configuration', () => { + it('should use filetype map from config', async () => { + let config = workspace.getConfiguration('diagnostic') + config.update('filetypeMap', { default: 'bufferType' }) + config.update('messageDelay', 10) + let doc = await createDocument('foo.js') + await nvim.setLine('foo') + await doc.synchronize() + let collection = manager.getCollectionByName('test') + let diagnostic = createDiagnostic('99', Range.create(0, 0, 0, 3), DiagnosticSeverity.Error) + diagnostic.codeDescription = { + href: 'http://www.example.com' + } + let diagnostics = [diagnostic] + collection.set(doc.uri, diagnostics) + await nvim.call('cursor', [1, 2]) + await manager.echoMessage(false) + let win = await helper.getFloat() + let bufnr = await nvim.call('winbufnr', [win.id]) + let buf = nvim.createBuffer(bufnr) + let lines = await buf.lines + expect(lines.join('\n')).toMatch('www.example.com') + }) + + it('should show floating window on cursor hold', async () => { + let config = workspace.getConfiguration('diagnostic') + config.update('messageTarget', 'float') + config.update('messageDelay', 10) + await createDocument() + await nvim.call('cursor', [1, 3]) + await nvim.command('doautocmd CursorHold') + let winid = await helper.waitFloat() + let bufnr = await nvim.call('nvim_win_get_buf', winid) as number + let buf = nvim.createBuffer(bufnr) + let lines = await buf.lines + expect(lines.join('\n')).toMatch('error') + }) + + it('should filter diagnostics by messageLevel', async () => { + let config = workspace.getConfiguration('diagnostic') + config.update('messageLevel', 'error') + config.update('messageTarget', 'echo') + await createDocument() + await nvim.call('cursor', [1, 6]) + await manager.echoMessage(false) + let line = await helper.getCmdline() + expect(line.indexOf('warning')).toBe(-1) + }) + + it('should echo messages on CursorHold', async () => { + await createDocument() + await helper.wait(10) + let config = workspace.getConfiguration('diagnostic') + config.update('messageTarget', 'echo') + config.update('messageDelay', 1) + await nvim.call('cursor', [1, 3]) + await helper.wait(50) + let line = await helper.getCmdline() + expect(line).toMatch('error') + }) + + it('should show diagnostics of current line', async () => { + helper.updateConfiguration('diagnostic.checkCurrentLine', true) + helper.updateConfiguration('diagnostic.messageDelay', 1) + await createDocument() + await nvim.call('cursor', [1, 3]) + let winid = await helper.waitFloat() + let win = nvim.createWindow(winid) + let buf = await win.buffer + let lines = await buf.lines + expect(lines.length).toBe(3) + }) + + it('should filter diagnostics by level', async () => { + helper.updateConfiguration('diagnostic.level', 'warning') + let doc = await createDocument() + let diagnosticsMap = manager.getDiagnostics(doc.uri) + for (let diagnostics of Object.values(diagnosticsMap)) { + for (let diagnostic of diagnostics) { + expect(diagnostic.severity != DiagnosticSeverity.Hint).toBe(true) + expect(diagnostic.severity != DiagnosticSeverity.Information).toBe(true) + } + } + }) + + it('should send ale diagnostic items', async () => { + helper.updateConfiguration('diagnostic.displayByAle', true) + let content = ` + function! MockAleResults(bufnr, collection, items) + let g:collection = a:collection + let g:items = a:items + endfunction + ` + let file = await createTmpFile(content) + await nvim.command(`source ${file}`) + await createDocument() + await helper.wait(50) + let items = await nvim.getVar('items') as any[] + expect(Array.isArray(items)).toBe(true) + expect(items.length).toBeGreaterThan(0) + await nvim.command('bd!') + await helper.wait(50) + items = await nvim.getVar('items') as any[] + expect(items).toEqual([]) + }) + }) + + describe('severityLevel & getNameFromSeverity', () => { + it('should get severity level', () => { + expect(severityLevel('hint')).toBe(DiagnosticSeverity.Hint) + expect(severityLevel('error')).toBe(DiagnosticSeverity.Error) + expect(severityLevel('warning')).toBe(DiagnosticSeverity.Warning) + expect(severityLevel('information')).toBe(DiagnosticSeverity.Information) + expect(severityLevel('')).toBe(DiagnosticSeverity.Hint) + }) + + it('should get severity name', () => { + expect(getNameFromSeverity(null as any)).toBe('CocError') + }) + }) + + describe('toggleDiagnosticBuffer', () => { + it('should not throw when bufnr is invliad or disabled', async () => { + let doc = await workspace.document + await manager.toggleDiagnosticBuffer(99) + helper.updateConfiguration('diagnostic.enable', false) + await manager.toggleDiagnosticBuffer(doc.bufnr) + }) + + it('should toggle diagnostics for buffer', async () => { + let doc = await createDocument() + // required to wait refresh finish + await helper.wait(50) + await manager.toggleDiagnosticBuffer(doc.bufnr) + let buf = nvim.createBuffer(doc.bufnr) + let res = await buf.getVar('coc_diagnostic_info') as any + expect(res == null).toBe(true) + await manager.toggleDiagnosticBuffer(doc.bufnr) + await helper.wait(50) + res = await buf.getVar('coc_diagnostic_info') as any + expect(res.error).toBe(2) + }) + }) + + describe('refresh', () => { + let config = workspace.getConfiguration('diagnostic') + beforeEach(() => { + config.update('autoRefresh', false) + }) + + it('should refresh by bufnr', async () => { + let doc = await createDocument() + let buf = nvim.createBuffer(doc.bufnr) + let res = await buf.getVar('coc_diagnostic_info') as any + // should not refresh + expect(res == null).toBe(true) + manager.refresh(doc.bufnr) + await helper.wait(50) + res = await buf.getVar('coc_diagnostic_info') as any + expect(res?.error).toBe(2) + manager.refresh(99) + }) + + it('should refresh all buffers', async () => { + let uris = ['one', 'two'].map(s => URI.file(path.join(os.tmpdir(), s)).toString()) + await workspace.loadFiles(uris) + let collection = manager.create('tmp') + collection.set([[uris[0], [createDiagnostic('Error one')]], [uris[1], [createDiagnostic('Error two')]]]) + manager.refresh() + await helper.wait(50) + let bufnrs = [workspace.getDocument(uris[0]).bufnr, workspace.getDocument(uris[1]).bufnr] + for (let bufnr of bufnrs) { + let buf = nvim.createBuffer(bufnr) + let res = await buf.getVar('coc_diagnostic_info') as any + expect(res?.error).toBe(1) + } + collection.dispose() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/dialog.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/dialog.test.ts new file mode 100644 index 00000000..eb9954e9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/dialog.test.ts @@ -0,0 +1,60 @@ +import { Neovim } from '@chemzqm/neovim' +import Dialog, { DialogButton } from '../../model/dialog' +import helper from '../helper' + +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('Dialog module', () => { + it('should show dialog', async () => { + let dialog = new Dialog(nvim, { content: '你好' }) + await dialog.show({}) + let winid = await dialog.winid + let win = nvim.createWindow(winid) + let width = await win.width + expect(width).toBe(4) + await nvim.call('coc#float#close', [winid]) + }) + + it('should invoke callback with index -1', async () => { + let callback = jest.fn() + let dialog = new Dialog(nvim, { content: '你好', callback }) + await dialog.show({}) + let winid = await dialog.winid + await nvim.call('coc#float#close', [winid]) + await helper.wait(50) + expect(callback).toHaveBeenCalledWith(-1) + }) + + it('should invoke callback on click', async () => { + let callback = jest.fn() + let buttons: DialogButton[] = [{ + index: 0, + text: 'yes' + }, { + index: 1, + text: 'no' + }] + let dialog = new Dialog(nvim, { content: '你好', buttons, callback }) + await dialog.show({}) + let winid = await dialog.winid + let btnwin = await nvim.call('coc#float#get_related', [winid, 'buttons']) + await nvim.call('win_gotoid', [btnwin]) + await nvim.call('cursor', [2, 1]) + await nvim.call('coc#float#nvim_float_click', []) + await helper.wait(50) + expect(callback).toHaveBeenCalledWith(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/document.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/document.test.ts new file mode 100644 index 00000000..968de9a8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/document.test.ts @@ -0,0 +1,712 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from '@chemzqm/neovim/lib/api/Buffer' +import fs from 'fs' +import path from 'path' +import { Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import events from '../../events' +import Document from '../../model/document' +import { computeLinesOffsets, LinesTextDocument } from '../../model/textdocument' +import { disposeAll } from '../../util' +import { applyEdits, filterSortEdits } from '../../util/textedit' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim + +function createTextDocument(lines: string[]): LinesTextDocument { + return new LinesTextDocument('file://a', 'txt', 1, lines, 1, true) +} + +async function setLines(doc: Document, lines: string[]): Promise { + let edit = TextEdit.insert(Position.create(0, 0), lines.join('\n')) + await doc.applyEdits([edit]) +} + +describe('LinesTextDocument', () => { + it('should apply edits', async () => { + let textDocument = new LinesTextDocument('', '', 1, [ + 'use std::io::Result;' + ], 1, true) + // 1234567890 + let edits = [ + { range: { start: { line: 0, character: 7 }, end: { line: 0, character: 11 } }, newText: "" }, + { range: { start: { line: 0, character: 13 }, end: { line: 0, character: 19 } }, newText: "io" }, + { range: { start: { line: 0, character: 19 }, end: { line: 0, character: 19 } }, newText: "::" }, + { + range: { start: { line: 0, character: 19 }, end: { line: 0, character: 19 } }, newText: "{Result, Error}" + } + ] + edits = filterSortEdits(textDocument, edits) + let res = applyEdits(textDocument, edits) + expect(res).toEqual(['use std::io::{Result, Error};']) + }) + + it('should get length', async () => { + let doc = createTextDocument(['foo']) + expect(doc.length).toBe(4) + expect(doc.getText().length).toBe(4) + expect(doc.length).toBe(4) + }) + + it('should getText by range', async () => { + let doc = createTextDocument(['foo', 'bar']) + expect(doc.getText(Range.create(0, 0, 0, 1))).toBe('f') + expect(doc.getText(Range.create(0, 0, 1, 0))).toBe('foo\n') + }) + + it('should work when eol enabled', async () => { + let doc = createTextDocument(['foo', 'bar']) + expect(doc.lineCount).toBe(3) + let content = doc.getText() + expect(content).toBe('foo\nbar\n') + content = doc.getText(Range.create(0, 0, 0, 3)) + expect(content).toBe('foo') + let textLine = doc.lineAt(0) + expect(textLine.text).toBe('foo') + textLine = doc.lineAt(Position.create(0, 3)) + expect(textLine.text).toBe('foo') + let pos = doc.positionAt(4) + expect(pos).toEqual({ line: 1, character: 0 }) + content = doc.getText(Range.create(0, 0, 0, 3)) + expect(content).toBe('foo') + let offset = doc.offsetAt(Position.create(0, 4)) + expect(offset).toBe(4) + offset = doc.offsetAt(Position.create(2, 1)) + expect(offset).toBe(8) + expect(doc.end).toEqual(Position.create(2, 0)) + }) + + it('should throw for invalid line', async () => { + let doc = createTextDocument(['foo', 'bar']) + let fn = () => { + doc.lineAt(-1) + } + expect(fn).toThrow(Error) + fn = () => { + doc.lineAt(3) + } + expect(fn).toThrow(Error) + }) + + it('should work when eol disabled', async () => { + let doc = new LinesTextDocument('file://a', 'txt', 1, ['foo'], 1, false) + expect(doc.getText()).toBe('foo') + expect(doc.lineCount).toBe(1) + expect(doc.end).toEqual(Position.create(0, 3)) + }) +}) + +describe('computeLinesOffsets()', () => { + it('should computeLinesOffsets', async () => { + expect(computeLinesOffsets(['foo'], true)).toEqual([0, 4]) + expect(computeLinesOffsets(['foo'], false)).toEqual([0]) + }) +}) + +describe('TextLine', () => { + it('should work with line not last one', async () => { + let doc = createTextDocument(['foo', 'bar']) + let textLine = doc.lineAt(0) + expect(textLine.lineNumber).toBe(0) + expect(textLine.text).toBe('foo') + expect(textLine.range).toEqual(Range.create(0, 0, 0, 3)) + expect(textLine.rangeIncludingLineBreak).toEqual(Range.create(0, 0, 1, 0)) + expect(textLine.isEmptyOrWhitespace).toBe(false) + }) + + it('should work with last line', async () => { + let doc = createTextDocument(['foo', 'bar']) + let textLine = doc.lineAt(2) + let r = textLine.rangeIncludingLineBreak + expect(textLine.rangeIncludingLineBreak).toEqual(Range.create(2, 0, 2, 0)) + }) +}) + +describe('Document', () => { + beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + }) + + afterAll(async () => { + await helper.shutdown() + }) + + afterEach(async () => { + await helper.reset() + }) + + describe('properties', () => { + it('should parse iskeyword of character range', async () => { + await nvim.setOption('iskeyword', 'a-z,A-Z,48-57,_') + let opt = await nvim.getOption('iskeyword') + expect(opt).toBe('a-z,A-Z,48-57,_') + }) + + it('should get word range', async () => { + let doc = await workspace.document + await nvim.setLine('foo bar') + await doc.synchronize() + let range = doc.getWordRangeAtPosition({ line: 0, character: 0 }) + expect(range).toEqual(Range.create(0, 0, 0, 3)) + range = doc.getWordRangeAtPosition({ line: 0, character: 3 }) + expect(range).toBeNull() + range = doc.getWordRangeAtPosition({ line: 0, character: 4 }) + expect(range).toEqual(Range.create(0, 4, 0, 7)) + range = doc.getWordRangeAtPosition({ line: 0, character: 7 }) + expect(range).toBeNull() + }) + + it('should check has changed', async () => { + let doc = await workspace.document + expect(doc.hasChanged).toBe(false) + await nvim.setLine('foo bar') + await helper.waitValue(() => { + return doc.hasChanged + }, false) + }) + + it('should get symbol ranges', async () => { + let doc = await workspace.document + await nvim.setLine('foo bar foo') + let ranges = doc.getSymbolRanges('foo') + expect(ranges.length).toBe(2) + }) + + it('should get localify bonus', async () => { + let assertBonus = async (lines: string[], position: Position, words: string[], limit?: number) => { + let doc = await helper.createDocument() + await doc.buffer.setLines(lines, { start: 0, end: -1, strictIndexing: false }) + await doc.patchChange() + let res = doc.getLocalifyBonus(position, position, limit) + for (let word of words) { + expect(res.has(word)).toBe(true) + } + } + await assertBonus( + ['context content clearTimeout', '', 'product confirm'], + Position.create(1, 0), + ['confirm', 'clearTimeout'] + ) + await assertBonus( + ['context content clearTimeout', '', 'product confirm', 'word', 'workspace', 'words'], + Position.create(2, 1), + ['confirm'], + 50 + ) + await assertBonus( + ['context content clearTimeout', '', 'product confirm', 'word', 'workspace', 'words'], + Position.create(2, 1), + ['confirm'], + 30 + ) + await assertBonus( + ['context content clearTimeout', '', 'product confirm'], + Position.create(0, 7), + ['confirm', 'clearTimeout'] + ) + }) + + it('should get current line', async () => { + let doc = await workspace.document + await setLines(doc, ['first line', 'second line']) + let line = doc.getline(1, true) + expect(line).toBe('second line') + line = doc.getline(0, false) + expect(line).toBe('first line') + }) + + it('should get variable form buffer', async () => { + await nvim.command('autocmd BufNewFile,BufRead * let b:coc_variable = 1') + let doc = await helper.createDocument() + let val = doc.getVar('variable') + expect(val).toBe(1) + }) + + it('should attach change events', async () => { + let doc = await workspace.document + await nvim.setLine('abc') + await doc.synchronize() + let content = doc.getDocumentContent() + expect(content.indexOf('abc')).toBe(0) + }) + + it('should not attach change events when b:coc_enabled is false', async () => { + nvim.command('edit t|let b:coc_enabled = 0', true) + let doc = await workspace.document + let val = doc.getVar('enabled', 0) + expect(val).toBe(0) + await nvim.setLine('abc') + await doc.synchronize() + let content = doc.getDocumentContent() + expect(content.indexOf('abc')).toBe(-1) + }) + + it('should get lineCount, previewwindow, winid', async () => { + let doc = await workspace.document + let { lineCount, winid, previewwindow } = doc + expect(lineCount).toBe(1) + expect(winid != -1).toBe(true) + expect(previewwindow).toBe(false) + }) + + it('should set filetype', async () => { + let doc = await workspace.document + doc.setFiletype('javascript.jsx') + expect(doc.filetype).toBe('javascriptreact') + doc.setFiletype('typescript.jsx') + expect(doc.filetype).toBe('typescriptreact') + doc.setFiletype('typescript.tsx') + expect(doc.filetype).toBe('typescriptreact') + doc.setFiletype('tex') + expect(doc.filetype).toBe('latex') + doc.setFiletype('foo') + expect(doc.filetype).toBe('foo') + }) + }) + + describe('applyEdits()', () => { + it('should simple applyEdits', async () => { + let doc = await workspace.document + let edits: TextEdit[] = [] + edits.push({ + range: Range.create(0, 0, 0, 0), + newText: 'a\n' + }) + edits.push({ + range: Range.create(0, 0, 0, 0), + newText: 'b\n' + }) + let edit = await doc.applyEdits(edits) + let content = doc.getDocumentContent() + expect(content).toBe('a\nb\n\n') + await doc.applyEdits([edit]) + expect(doc.getDocumentContent()).toEqual('\n') + }) + + it('should return revert edit', async () => { + let doc = await workspace.document + let edit = await doc.applyEdits([TextEdit.replace(Range.create(0, 0, 0, 0), 'foo')]) + expect(doc.getDocumentContent()).toBe('foo\n') + edit = await doc.applyEdits([edit]) + expect(doc.getDocumentContent()).toBe('\n') + edit = await doc.applyEdits([edit]) + expect(doc.getDocumentContent()).toBe('foo\n') + }) + + it('should apply merged edits', async () => { + let doc = await workspace.document + await nvim.setLine('foo') + await doc.patchChange() + let edits: TextEdit[] = [] + edits.push({ + range: Range.create(0, 0, 0, 3), + newText: '' + }) + edits.push({ + range: Range.create(0, 0, 0, 0), + newText: 'bar' + }) + let edit = await doc.applyEdits(edits) + let line = await nvim.line + expect(line).toBe('bar') + await doc.applyEdits([edit]) + expect(doc.getDocumentContent()).toBe('foo\n') + }) + + it('should apply textedit exceed end', async () => { + let doc = await workspace.document + let edits: TextEdit[] = [] + edits.push({ + range: Range.create(0, 0, 999999, 99999), + newText: 'foo\n' + }) + await doc.applyEdits(edits) + let content = doc.getDocumentContent() + expect(content).toBe('foo\n') + }) + + it('should move cursor', async () => { + await nvim.input('ia') + await helper.wait(30) + let doc = await workspace.document + let edits: TextEdit[] = [] + edits.push({ + range: Range.create(0, 0, 0, 1), + newText: 'foo' + }) + await doc.applyEdits(edits, false, true) + let cursor = await nvim.call('getcurpos') as number[] + expect(cursor[1]).toBe(1) + expect(cursor[2]).toBe(4) + }) + + it('should applyEdits with range not sorted', async () => { + let doc = await workspace.document + await doc.buffer.setLines([ + 'aa', + 'bb', + 'cc', + 'dd' + ], { start: 0, end: -1, strictIndexing: false }) + await doc.patchChange() + let edits = [ + { range: { start: { line: 3, character: 0 }, end: { line: 3, character: 1 } }, newText: "" }, + { range: { start: { line: 0, character: 2 }, end: { line: 1, character: 0 } }, newText: "" }, + ] + await doc.applyEdits(edits) + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(['aabb', 'cc', 'd']) + }) + + it('should applyEdits with insert as same position', async () => { + let doc = await workspace.document + await doc.buffer.setLines([ + 'foo' + ], { start: 0, end: -1, strictIndexing: false }) + await doc.patchChange() + let edits = [ + { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }, newText: 'aa' }, + { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }, newText: 'bb' }, + ] + await doc.applyEdits(edits) + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(['aabbfoo']) + }) + + it('should applyEdits with bad range', async () => { + let doc = await workspace.document + await doc.buffer.setLines([], { start: 0, end: -1, strictIndexing: false }) + await doc.patchChange() + let edits = [{ range: { start: { line: -1, character: -1 }, end: { line: -1, character: -1 } }, newText: 'foo' },] + await doc.applyEdits(edits) + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(['foo']) + }) + + it('should applyEdits with lines', async () => { + let doc = await workspace.document + await doc.buffer.setLines([ + 'aa', + 'bb', + 'cc', + 'dd' + ], { start: 0, end: -1, strictIndexing: false }) + await doc.patchChange() + let edits = [ + { range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } }, newText: "" }, + { range: { start: { line: 0, character: 2 }, end: { line: 1, character: 0 } }, newText: "" }, + ] + await doc.applyEdits(edits) + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(['abb', 'cc', 'dd']) + }) + + it('should applyEdits with changed lines', async () => { + let doc = await workspace.document + let buf = doc.buffer + const assertChange = async (sl, sc, el, ec, text, lines) => { + let r = Range.create(sl, sc, el, ec) + let edits = [TextEdit.replace(r, text)] + await doc.applyEdits(edits) + let curr = await buf.lines + expect(curr).toEqual(lines) + } + await nvim.setLine('a') + await doc.patchChange() + await assertChange(0, 1, 0, 1, '\nb', ['a', 'b']) + await assertChange(1, 0, 2, 0, 'c\n', ['a', 'c']) + await assertChange(1, 0, 2, 0, '', ['a']) + await assertChange(1, 0, 1, 0, 'b\nc\n', ['a', 'b', 'c']) + await assertChange(2, 0, 3, 0, 'e\n', ['a', 'b', 'e']) + }) + + it('should apply single textedit', async () => { + let doc = await workspace.document + let buf = doc.buffer + const assertChange = async (sl, sc, el, ec, text, lines) => { + let r = Range.create(sl, sc, el, ec) + let edits = [TextEdit.replace(r, text)] + await doc.applyEdits(edits) + let curr = await buf.lines + expect(curr).toEqual(lines) + } + await nvim.setLine('foo') + await doc.patchChange() + await assertChange(1, 0, 1, 0, 'bar', ['foo', 'bar']) + await assertChange(2, 0, 2, 0, 'do\n', ['foo', 'bar', 'do']) + await assertChange(2, 1, 3, 0, '', ['foo', 'bar', 'd']) + await assertChange(2, 0, 3, 0, 'if', ['foo', 'bar', 'if']) + await assertChange(2, 0, 2, 2, 'x', ['foo', 'bar', 'x']) + }) + }) + + describe('synchronize', () => { + it('should synchronize on lines change', async () => { + let document = await workspace.document + let doc = TextDocument.create('untitled:1', 'txt', 1, document.getDocumentContent()) + let disposables = [] + document.onDocumentChange(e => { + TextDocument.update(doc, e.contentChanges.slice(), 2) + }, null, disposables) + // document.on + await nvim.setLine('abc') + document.forceSync() + expect(doc.getText()).toBe('abc\n') + disposeAll(disposables) + }) + + it('should synchronize changes after applyEdits', async () => { + let document = await workspace.document + let doc = TextDocument.create('untitled:1', 'txt', 1, document.getDocumentContent()) + let disposables = [] + document.onDocumentChange(e => { + TextDocument.update(doc, e.contentChanges.slice(), e.textDocument.version) + }, null, disposables) + await nvim.setLine('abc') + await document.patchChange() + await document.applyEdits([TextEdit.insert({ line: 0, character: 0 }, 'd')]) + expect(doc.getText()).toBe('dabc\n') + disposeAll(disposables) + }) + + it('should consider empty lines', async () => { + let document = await workspace.document + await nvim.call('setline', [1, ['foo', 'bar']]) + await document.patchChange() + await nvim.command('normal! ggdG') + await nvim.call('append', [1, ['foo', 'bar']]) + await document.patchChange() + let lines = document.textDocument.lines + expect(lines).toEqual(['', 'foo', 'bar']) + }) + }) + + describe('recreate', () => { + async function assertDocument(fn: (doc: Document) => Promise): Promise { + let disposables: Disposable[] = [] + let fsPath = path.join(__dirname, 'document.txt') + fs.writeFileSync(fsPath, '{\nfoo\n}\n', 'utf8') + await helper.edit(fsPath) + let document = await workspace.document + document.forceSync() + let doc = TextDocument.create(document.uri, 'txt', document.version, document.getDocumentContent()) + let uri = doc.uri + workspace.onDidOpenTextDocument(e => { + if (e.uri == uri) { + doc = TextDocument.create(e.uri, 'txt', e.version, e.getText()) + } + }, null, disposables) + workspace.onDidCloseTextDocument(e => { + if (e.uri == doc.uri) doc = null + }, null, disposables) + workspace.onDidChangeTextDocument(e => { + TextDocument.update(doc, e.contentChanges.slice(), e.textDocument.version) + }, null, disposables) + await fn(document) + document = await workspace.document + document.forceSync() + let text = document.getDocumentContent() + expect(doc).toBeDefined() + expect(doc.getText()).toBe(text) + disposeAll(disposables) + fs.unlinkSync(fsPath) + } + + it('should synchronize after make changes', async () => { + await assertDocument(async () => { + await nvim.call('setline', [1, 'a']) + await nvim.call('setline', [2, 'b']) + }) + }) + + it('should synchronize after edit', async () => { + await assertDocument(async doc => { + let fsPath = URI.parse(doc.uri).fsPath + fs.writeFileSync(fsPath, '{\n}\n', 'utf8') + await nvim.command('edit') + await nvim.call('deletebufline', [doc.bufnr, 1]) + doc = await workspace.document + let content = doc.getDocumentContent() + expect(content).toBe('}\n') + }) + }) + + it('should synchronize after force edit', async () => { + await assertDocument(async doc => { + let fsPath = URI.parse(doc.uri).fsPath + fs.writeFileSync(fsPath, '{\n}\n', 'utf8') + await nvim.command('edit') + await nvim.call('deletebufline', [doc.bufnr, 1]) + doc = await workspace.document + let content = doc.getDocumentContent() + expect(content).toBe('}\n') + }) + }) + }) + + describe('getEndOffset', () => { + it('should getEndOffset #1', async () => { + let doc = await workspace.document + await setLines(doc, ['', '']) + let end = doc.getEndOffset(1, 1, false) + expect(end).toBe(2) + end = doc.getEndOffset(2, 1, false) + expect(end).toBe(1) + }) + + it('should getEndOffset #2', async () => { + let doc = await workspace.document + await setLines(doc, ['a', '']) + let end = doc.getEndOffset(1, 1, false) + expect(end).toBe(2) + }) + + it('should getEndOffset #3', async () => { + let doc = await workspace.document + await setLines(doc, ['a']) + let end = doc.getEndOffset(1, 2, false) + expect(end).toBe(1) + }) + + it('should getEndOffset #4', async () => { + let doc = await workspace.document + await setLines(doc, ['你好', '']) + let end = doc.getEndOffset(1, 1, false) + expect(end).toBe(3) + end = doc.getEndOffset(1, 1, true) + expect(end).toBe(4) + }) + }) + + describe('applyEdits', () => { + it('should synchronize content added', async () => { + let doc = await workspace.document + await nvim.setLine('foo f') + await doc.synchronize() + await nvim.command('normal! ^2l') + void nvim.input('ar') + await doc.applyEdits([{ + range: Range.create(0, 0, 0, 5), + newText: 'foo foo' + }]) + await helper.waitFor('getline', ['.'], 'foor foo') + }) + + it('should synchronize content delete', async () => { + let doc = await workspace.document + await doc.buffer.setLines(['foo f'], { start: 0, end: -1, strictIndexing: false }) + await doc.synchronize() + await nvim.command('normal! gg^2l') + await nvim.input('a') + await nvim.input('') + await helper.waitFor('getline', ['.'], 'fo f') + }) + }) + + describe('highlights', () => { + it('should add highlights to document', async () => { + let buf = await nvim.buffer + await buf.setLines(['你好', 'world'], { start: 0, end: -1, strictIndexing: false }) + let ranges = [ + Range.create(0, 0, 0, 2), + Range.create(1, 0, 1, 3) + ] + let ns = await nvim.createNamespace('coc-highlight') + nvim.pauseNotification() + buf.highlightRanges('highlight', 'Search', ranges) + await nvim.resumeNotification() + let markers = await helper.getMarkers(buf.id, ns) + expect(markers.length).toBe(2) + nvim.pauseNotification() + buf.clearNamespace('highlight') + await nvim.resumeNotification() + markers = await helper.getMarkers(buf.id, ns) + expect(markers.length).toBe(0) + }) + + it('should add/clear highlights of current window', async () => { + let buf = await nvim.buffer + await buf.setLines(['你好', 'world'], { start: 0, end: -1, strictIndexing: false }) + let win = await nvim.window + let ranges = [ + Range.create(0, 0, 0, 2), + Range.create(1, 0, 1, 3) + ] + let res = await win.highlightRanges('Search', ranges) + expect(res.length).toBe(2) + let matches = await nvim.call('getmatches', [win.id]) + expect(matches.length).toBe(2) + nvim.pauseNotification() + win.clearMatchGroup('Search') + await nvim.resumeNotification() + matches = await nvim.call('getmatches', [win.id]) + expect(matches.length).toBe(0) + }) + + it('should clear matches by ids', async () => { + let buf = await nvim.buffer + await buf.setLines(['你好', 'world'], { start: 0, end: -1, strictIndexing: false }) + let win = await nvim.window + let ranges = [ + Range.create(0, 0, 0, 2), + Range.create(1, 0, 1, 3) + ] + let ids = await win.highlightRanges('Search', ranges) + nvim.pauseNotification() + win.clearMatches(ids) + await nvim.resumeNotification() + let matches = await nvim.call('getmatches', [win.id]) + expect(matches.length).toBe(0) + }) + }) + + describe('onTextChange', () => { + async function createVimDocument(): Promise { + let doc = await workspace.document + doc.detach() + let opts = await nvim.call('coc#util#get_bufoptions', doc.bufnr) + let buf = nvim.createBuffer(doc.bufnr) + let env = Object.assign({ isVim: true }, workspace.env) + return new Document(buf, env, nvim, opts) + } + + it('should fetch lines on TextChanged', async () => { + let doc = await createVimDocument() + expect(doc.attached).toBe(true) + let disposable = events.on('TextChanged', (bufnr: number) => { + if (bufnr == doc.bufnr) doc.onTextChange('TextChanged') + }) + let p = new Promise(resolve => { + doc.onDocumentChange(() => { + resolve() + }) + }) + await nvim.setLine('foo') + await p + disposable.dispose() + let line = doc.getline(0) + expect(line).toBe('foo') + }) + + it('should update on insert change', async () => { + + let doc = await createVimDocument() + await nvim.setLine('foo') + let disposables: Disposable[] = [] + ;['TextChangedP', 'TextChangedI', 'TextChanged'].forEach(event => { + events.on(event as any, (bufnr: number, info) => { + if (bufnr === doc.bufnr) doc.onTextChange(event, info) + }, null, disposables) + }) + await nvim.input('o') + await nvim.input('f') + await nvim.input('') + await helper.waitPopup() + let line = doc.getline(1) + expect(line).toBe('f') + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/events.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/events.test.ts new file mode 100644 index 00000000..39574696 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/events.test.ts @@ -0,0 +1,128 @@ +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import events from '../../events' +import { disposeAll, wait } from '../../util' + +const disposables: Disposable[] = [] +afterEach(async () => { + disposeAll(disposables) +}) + +describe('register handler', () => { + it('should fire InsertEnter and InsertLeave when necessary', async () => { + let fn = jest.fn() + events.on('InsertEnter', fn, null, disposables) + events.on('InsertLeave', fn, null, disposables) + expect(events.insertMode).toBe(false) + await events.fire('CursorMovedI', [1, [1, 1]]) + expect(events.insertMode).toBe(true) + await events.fire('CursorMoved', [1, [1, 1]]) + expect(events.insertMode).toBe(false) + expect(fn).toBeCalledTimes(2) + }) + + it('should change pumvisible', async () => { + expect(events.pumvisible).toBe(false) + await events.fire('MenuPopupChanged', [{ + col: 6, + row: 2, + scrollbar: false, + completed_item: {}, + width: 20, + height: 12, + size: 12 + }]) + expect(events.pumAlignTop).toBe(false) + expect(events.pumvisible).toBe(true) + await events.fire('CompleteDone', [{}]) + expect(events.pumvisible).toBe(false) + }) + + it('should register single handler', async () => { + let fn = jest.fn() + let obj = {} + let disposable = events.on('BufEnter', fn, obj) + disposables.push(disposable) + await events.fire('BufEnter', ['a', 'b']) + expect(fn).toBeCalledWith('a', 'b') + }) + + it('should register multiple events', async () => { + let fn = jest.fn() + let disposable = events.on(['TaskExit', 'TaskStderr'], fn) + disposables.push(disposable) + await events.fire('TaskExit', []) + await events.fire('TaskStderr', []) + expect(fn).toBeCalledTimes(2) + }) + + it('should resolve after timeout', async () => { + let fn = (): Promise => new Promise(resolve => { + setTimeout(() => { + resolve() + }, 20) + }) + let disposable = events.on('FocusGained', fn, {}) + disposables.push(disposable) + let ts = Date.now() + await events.fire('FocusGained', []) + expect(Date.now() - ts >= 10).toBe(true) + }) + + it('should emit TextInsert after TextChangedI', async () => { + let arr: string[] = [] + events.on('TextInsert', () => { + arr.push('insert') + }, null, disposables) + events.on('TextChangedI', () => { + arr.push('change') + }, null, disposables) + await events.fire('InsertCharPre', ['i', 1]) + await events.fire('TextChangedI', [1, { + lnum: 1, + col: 2, + pre: 'i', + changedtick: 1, + line: 'i' + }]) + expect(events.lastChangeTs).toBeDefined() + await events.race(['TextInsert']) + expect(arr).toEqual(['change', 'insert']) + }) + + it('should race events', async () => { + let p = events.race(['InsertCharPre', 'TextChangedI', 'MenuPopupChanged']) + await events.fire('InsertCharPre', ['i', 1]) + await events.fire('TextChangedI', [1, { + lnum: 1, + col: 2, + pre: 'i', + changedtick: 1 + }]) + let res = await p + expect(res.name).toBe('InsertCharPre') + res = await events.race(['TextChanged'], 50) + expect(res).toBeUndefined() + }) + + it('should race same events', async () => { + let arr: any[] = [] + void events.race(['TextChangedI'], 200).then(res => { + arr.push(res) + }) + void events.race(['TextChangedI'], 200).then(res => { + arr.push(res) + }) + await events.fire('TextChangedI', [2, {}]) + expect(arr.length).toBe(2) + expect(arr.map(o => o.name)).toEqual(['TextChangedI', 'TextChangedI']) + }) + + it('should cancel race by CancellationToken', async () => { + let tokenSource = new CancellationTokenSource() + setTimeout(() => { + tokenSource.cancel() + }, 20) + let res = await events.race(['TextChanged'], tokenSource.token) + expect(res).toBeUndefined() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/extensions.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/extensions.test.ts new file mode 100644 index 00000000..d8eb4a08 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/extensions.test.ts @@ -0,0 +1,231 @@ +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import path from 'path' +import os from 'os' +import events from '../../events' +import extensions, { API, Extension } from '../../extensions' +import helper from '../helper' +import { v1 as uuidv1 } from 'uuid' + +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +jest.setTimeout(30000) + +describe('extensions', () => { + + it('should create root when it does not exist', async () => { + let root = path.join(os.tmpdir(), 'foo-bar') + let res = extensions.checkRoot(root) + expect(res).toBe(true) + expect(fs.existsSync(path.join(root, 'package.json'))).toBe(true) + let method = typeof fs['rmSync'] === 'function' ? 'rmSync' : 'rmdirSync' + fs[method](root, { recursive: true }) + }) + + it('should remove unexpted file', async () => { + let root = path.join(os.tmpdir(), 'foo-bar') + fs.writeFileSync(root, '') + let res = extensions.checkRoot(root) + expect(res).toBe(true) + expect(fs.existsSync(path.join(root, 'package.json'))).toBe(true) + let method = typeof fs['rmSync'] === 'function' ? 'rmSync' : 'rmdirSync' + fs[method](root, { recursive: true }) + }) + + it('should load global extensions', async () => { + let stat = extensions.getExtensionState('test') + expect(stat).toBe('activated') + }) + + it('should filter global extensions', async () => { + let res = extensions.filterGlobalExtensions(['test', 'foo']) + expect(res).toEqual(['foo']) + }) + + it('should load local extensions from &rtp', async () => { + let folder = path.resolve(__dirname, '../extensions/vim/local') + await nvim.command(`set runtimepath^=${folder}`) + await helper.wait(200) + let stat = extensions.getExtensionState('local') + expect(stat).toBe('activated') + }) + + it('should install/uninstall npm extension', async () => { + await extensions.installExtensions(['coc-omni']) + let folder = path.join(__dirname, '../extensions/coc-omni') + let exists = fs.existsSync(folder) + expect(exists).toBe(true) + await extensions.uninstallExtension(['coc-omni']) + exists = fs.existsSync(folder) + expect(exists).toBe(false) + }) + + it('should install/uninstall extension by url', async () => { + await extensions.installExtensions(['https://github.com/hollowtree/vscode-vue-snippets']) + let folder = path.join(__dirname, '../extensions/vue-snippets') + let exists = fs.existsSync(folder) + expect(exists).toBe(true) + await extensions.uninstallExtension(['vue-snippets']) + exists = fs.existsSync(folder) + expect(exists).toBe(false) + }) + + it('should install/uninstall extension by url with branch', async () => { + await extensions.installExtensions(['https://github.com/sdras/vue-vscode-snippets@main']) + let folder = path.join(__dirname, '../extensions/vue-vscode-snippets') + let exists = fs.existsSync(folder) + expect(exists).toBe(true) + await extensions.uninstallExtension(['vue-vscode-snippets']) + exists = fs.existsSync(folder) + expect(exists).toBe(false) + }) + + it('should get all extensions', () => { + let list = extensions.all + expect(Array.isArray(list)).toBe(true) + }) + + it('should get extensions stat', async () => { + let stats = await extensions.getExtensionStates() + expect(stats.length).toBeGreaterThan(0) + }) + + it('should toggle extension', async () => { + await extensions.toggleExtension('test') + let stat = extensions.getExtensionState('test') + expect(stat).toBe('disabled') + await extensions.toggleExtension('test') + stat = extensions.getExtensionState('test') + expect(stat).toBe('activated') + }) + + it('should reload extension', async () => { + await extensions.reloadExtension('test') + await helper.wait(100) + let stat = extensions.getExtensionState('test') + expect(stat).toBe('activated') + }) + + it('should has extension', () => { + let res = extensions.has('test') + expect(res).toBe(true) + }) + + it('should be activated', async () => { + let res = extensions.has('test') + expect(res).toBe(true) + }) + + it('should activate & deactivate extension', async () => { + await extensions.deactivate('test') + let stat = extensions.getExtensionState('test') + expect(stat).toBe('loaded') + await extensions.activate('test') + stat = extensions.getExtensionState('test') + expect(stat).toBe('activated') + }) + + it('should call extension API', async () => { + let res = await extensions.call('test', 'echo', ['5']) + expect(res).toBe('5') + let p: string = await extensions.call('test', 'asAbsolutePath', ['..']) + expect(p.endsWith('extensions')).toBe(true) + }) + + it('should get extension API', () => { + let res = extensions.getExtensionApi('test') as any + expect(typeof res.echo).toBe('function') + }) + + it('should load single file extension', async () => { + let filepath = path.join(__dirname, '../extensions/root.js') + await extensions.loadExtensionFile(filepath) + expect(extensions.has('single-root')).toBe(true) + }) +}) + +describe('extensions active events', () => { + + function createExtension(event: string): Extension { + let id = uuidv1() + let isActive = false + let packageJSON = { + name: id, + activationEvents: [event] + } + let ext = { + id, + packageJSON, + exports: void 0, + extensionPath: '', + activate: async () => { + isActive = true + } + } as any + Object.defineProperty(ext, 'isActive', { + get: () => isActive + }) + extensions.registerExtension(ext, () => { + isActive = false + }) + return ext + } + + it('should activate on language', async () => { + let ext = createExtension('onLanguage:javascript') + expect(ext.isActive).toBe(false) + await nvim.command('edit /tmp/a.js') + await nvim.command('setf javascript') + await helper.wait(100) + expect(ext.isActive).toBe(true) + ext = createExtension('onLanguage:javascript') + expect(ext.isActive).toBe(true) + }) + + it('should activate on command', async () => { + let ext = createExtension('onCommand:test.echo') + await events.fire('Command', ['test.echo']) + await helper.wait(30) + expect(ext.isActive).toBe(true) + }) + + it('should activate on workspace contains', async () => { + let ext = createExtension('workspaceContains:package.json') + let root = path.resolve(__dirname, '../../..') + await nvim.command(`edit ${path.join(root, 'file.js')}`) + await helper.wait(100) + expect(ext.isActive).toBe(true) + }) + + it('should activate on file system', async () => { + let ext = createExtension('onFileSystem:zip') + await nvim.command('edit zip:///a') + await helper.wait(30) + expect(ext.isActive).toBe(true) + ext = createExtension('onFileSystem:zip') + expect(ext.isActive).toBe(true) + }) +}) + +describe('extension properties', () => { + it('should get extensionPath', () => { + let ext = extensions.getExtension('test') + let p = ext.extension.extensionPath + expect(p.endsWith('test')).toBe(true) + }) + + it('should deactivate', async () => { + let ext = extensions.getExtension('test') + await ext.deactivate() + expect(ext.extension.isActive).toBe(false) + await extensions.activate('test') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/fetch.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/fetch.test.ts new file mode 100644 index 00000000..5f7d9ff0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/fetch.test.ts @@ -0,0 +1,86 @@ +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { parse } from 'url' +import download from '../../model/download' +import fetch, { getAgent } from '../../model/fetch' +import helper from '../helper' + +beforeAll(async () => { + await helper.setup() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('fetch', () => { + + it('should fetch json', async () => { + let res = await fetch('https://nodejs.org/dist/index.json') + expect(Array.isArray(res)).toBe(true) + }, 10000) + + it('should fetch buffer', async () => { + let res = await fetch('https://www.npmjs.com/', { buffer: true }) + expect(Buffer.isBuffer(res)).toBe(true) + }) + + it('should throw on request error', async () => { + let err + try { + await fetch('http://not_exists_org') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should report valid proxy', async () => { + let agent = getAgent(parse('http://google.com'), { proxyUrl: 'domain.com:1234' }) + expect(agent).toBe(null) + + agent = getAgent(parse('http://google.com'), { proxyUrl: 'https://domain.com:1234' }) + let proxy = (agent as any).proxy + expect(proxy.host).toBe('domain.com') + expect(proxy.port).toBe(1234) + + agent = getAgent(parse('http://google.com'), { proxyUrl: 'http://user:pass@domain.com:1234' }) + proxy = (agent as any).proxy + expect(proxy.host).toBe('domain.com') + expect(proxy.port).toBe(1234) + expect(proxy.auth).toBe('user:pass') + }) +}) + +describe('download', () => { + it('should download binary file', async () => { + let url = 'https://registry.npmjs.org/coc-pairs/-/coc-pairs-1.2.13.tgz' + let tmpFolder = await fs.mkdtemp(path.join(os.tmpdir(), 'coc-test')) + let res = await download(url, { dest: tmpFolder }) + expect(fs.existsSync(res)).toBe(true) + await fs.remove(tmpFolder) + }, 10000) + + it('should download tgz', async () => { + let url = 'https://registry.npmjs.org/coc-pairs/-/coc-pairs-1.2.13.tgz' + let tmpFolder = await fs.mkdtemp(path.join(os.tmpdir(), 'coc-test')) + await download(url, { dest: tmpFolder, extract: 'untar' }) + let file = path.join(tmpFolder, 'package.json') + expect(fs.existsSync(file)).toBe(true) + await fs.remove(tmpFolder) + }, 10000) + + it('should extract zip file', async () => { + let url = 'https://codeload.github.com/chemzqm/vimrc/zip/master' + let tmpFolder = await fs.mkdtemp(path.join(os.tmpdir(), 'coc-test')) + await download(url, { dest: tmpFolder, extract: 'unzip' }) + let folder = path.join(tmpFolder, 'vimrc-master') + expect(fs.existsSync(folder)).toBe(true) + await fs.remove(tmpFolder) + }, 30000) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/floatFactory.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/floatFactory.test.ts new file mode 100644 index 00000000..5fb2d1bf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/floatFactory.test.ts @@ -0,0 +1,254 @@ +import { Neovim } from '@chemzqm/neovim' +import FloatFactory from '../../model/floatFactory' +import snippetManager from '../../snippets/manager' +import { Documentation } from '../../types' +import helper from '../helper' + +let nvim: Neovim +let floatFactory: FloatFactory +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + floatFactory = new FloatFactory(nvim) +}) + +afterAll(async () => { + await helper.shutdown() + floatFactory.dispose() +}) + +afterEach(async () => { + floatFactory.close() + await helper.reset() +}) + +describe('FloatFactory', () => { + describe('show()', () => { + it('should show window', async () => { + expect(floatFactory.window).toBe(null) + expect(floatFactory.buffer).toBe(null) + expect(floatFactory.bufnr).toBe(0) + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f'.repeat(81) + }] + await floatFactory.show(docs, { rounded: true }) + expect(floatFactory.window).toBeDefined() + expect(floatFactory.buffer).toBeDefined() + let hasFloat = await nvim.call('coc#float#has_float') + expect(hasFloat).toBe(1) + await floatFactory.show([{ filetype: 'txt', content: '' }]) + expect(floatFactory.window).toBe(null) + }) + + it('should create window', async () => { + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f'.repeat(81) + }] + await floatFactory.create(docs) + expect(floatFactory.window).toBeDefined() + }) + + it('should catch error on create', async () => { + let fn = floatFactory.unbind + floatFactory.unbind = () => { + throw new Error('bad') + } + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f'.repeat(81) + }] + await floatFactory.show(docs) + floatFactory.unbind = fn + let msg = await helper.getCmdline() + expect(msg).toMatch('bad') + }) + + it('should show only one window', async () => { + await helper.edit() + await nvim.setLine('foo') + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await Promise.all([ + floatFactory.show(docs), + floatFactory.show(docs) + ]) + let count = 0 + let wins = await nvim.windows + for (let win of wins) { + let isFloat = await win.getVar('float') + if (isFloat) count++ + } + expect(count).toBe(1) + }) + + it('should close window when close called after create', async () => { + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f' + }] + let p = floatFactory.show(docs) + await helper.wait(10) + floatFactory.close() + await p + let activated = await floatFactory.activated() + expect(activated).toBe(false) + }) + + it('should not create on visual mode', async () => { + await helper.createDocument() + await nvim.call('cursor', [1, 1]) + await nvim.setLine('foo') + await nvim.command('normal! v$') + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f' + }] + await floatFactory.show(docs) + expect(floatFactory.window).toBe(null) + }) + + it('should allow select mode', async () => { + await helper.createDocument() + await snippetManager.insertSnippet('${1:foo}') + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await floatFactory.show(docs) + let { mode } = await nvim.mode + expect(mode).toBe('s') + await nvim.input('') + }) + }) + + describe('checkRetrigger', () => { + it('should check retrigger', async () => { + expect(floatFactory.checkRetrigger(99)).toBe(false) + let bufnr = await nvim.call('bufnr', ['%']) + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f' + }] + await floatFactory.show(docs) + expect(floatFactory.checkRetrigger(99)).toBe(false) + expect(floatFactory.checkRetrigger(bufnr)).toBe(true) + }) + }) + + describe('options', () => { + it('should config maxHeight and maxWidth', async () => { + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'f'.repeat(80) + '\nbar', + }] + await floatFactory.show(docs, { + maxWidth: 20, + maxHeight: 1 + }) + let win = floatFactory.window + expect(win).toBeDefined() + let width = await win.width + let height = await win.height + expect(width).toBe(19) + expect(height).toBe(1) + }) + + it('should set border, title, highlight, borderhighlight, cursorline', async () => { + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo\nbar' + }] + await floatFactory.show(docs, { + border: [1, 1, 1, 1], + title: 'title', + highlight: 'Pmenu', + borderhighlight: 'MoreMsg', + cursorline: true + }) + let activated = await floatFactory.activated() + expect(activated).toBe(true) + }) + + it('should respect prefer top', async () => { + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo\nbar' + }] + await nvim.call('append', [1, ['', '', '']]) + await nvim.command('exe 4') + await floatFactory.show(docs, { preferTop: true }) + let win = await helper.getFloat() + expect(win).toBeDefined() + let pos = await nvim.call('nvim_win_get_position', [win.id]) + expect(pos).toEqual([1, 0]) + }) + }) + + describe('events', () => { + it('should hide on BufEnter', async () => { + await helper.edit() + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await floatFactory.show(docs) + await nvim.command(`edit foo`) + await helper.waitFor('coc#float#has_float', [], 0) + }) + + it('should hide on CursorMoved', async () => { + await helper.createDocument() + await nvim.setLine('foo') + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await floatFactory.show(docs) + await helper.waitFloat() + await nvim.input('$') + await helper.waitFor('coc#float#has_float', [], 0) + }) + + it('should not hide when cursor position not changed', async () => { + await helper.edit() + await nvim.setLine('foo') + let cursor = await nvim.eval("[line('.'), col('.')]") + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await floatFactory.show(docs) + await nvim.call('cursor', [1, 2]) + await helper.wait(10) + await nvim.call('cursor', cursor) + await helper.wait(10) + await helper.waitFor('coc#float#has_float', [], 1) + }) + + it('should preserve float when autohide disable and not overlap with pum', async () => { + await helper.createDocument() + let buf = await nvim.buffer + await buf.setLines(['foo', '', '', '', 'f'], { start: 0, end: -1, strictIndexing: false }) + await nvim.call('cursor', [5, 2]) + await nvim.input('A') + let docs: Documentation[] = [{ + filetype: 'markdown', + content: 'foo' + }] + await floatFactory.show(docs, { + preferTop: true, + autoHide: false + }) + let activated = await floatFactory.activated() + expect(activated).toBe(true) + await nvim.input('') + await helper.waitPopup() + activated = await floatFactory.activated() + expect(activated).toBe(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/fs.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/fs.test.ts new file mode 100644 index 00000000..b542c22b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/fs.test.ts @@ -0,0 +1,216 @@ +import { findUp, checkFolder, isGitIgnored, readFileLine, readFileLines, writeFile, fixDriver, renameAsync, isParentFolder, parentDirs, inDirectory, getFileLineCount, sameFile, resolveRoot, statAsync } from '../../util/fs' +import path from 'path' +import fs from 'fs' +import os from 'os' + +describe('fs', () => { + describe('stat()', () => { + it('fs statAsync', async () => { + let res = await statAsync(__filename) + expect(res).toBeDefined + expect(res.isFile()).toBe(true) + }) + + it('fs statAsync #1', async () => { + let res = await statAsync(path.join(__dirname, 'file_not_exist')) + expect(res).toBeNull + }) + }) + + describe('checkFolder()', () => { + it('should check file in folder', async () => { + let cwd = process.cwd() + let res = await checkFolder(cwd, 'package.json') + expect(res).toBe(true) + res = await checkFolder(cwd, '**/schema.json') + expect(res).toBe(true) + res = await checkFolder(cwd, 'not_exists_fs') + expect(res).toBe(false) + res = await checkFolder(os.homedir(), 'not_exists_fs', 10) + expect(res).toBe(false) + }) + }) + + describe('renameAsync()', () => { + it('should rename file', async () => { + let filepath = path.join(os.tmpdir(), 'foo') + await writeFile(filepath, 'foo') + let dest = path.join(os.tmpdir(), 'bar') + await renameAsync(filepath, dest) + let exists = fs.existsSync(dest) + expect(exists).toBe(true) + fs.unlinkSync(dest) + }) + + it('should throw when file does not exist', async () => { + let err + try { + await renameAsync('/foo/bar', '/a') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + }) + + describe('getFileLineCount', () => { + it('should throw when file does not exist', async () => { + let err + try { + await getFileLineCount('/foo/bar') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + }) + + describe('sameFile', () => { + it('should be casesensitive', () => { + expect(sameFile('/a', '/A', false)).toBe(false) + }) + }) + + describe('readFileLine', () => { + it('should read line', async () => { + let res = await readFileLine(__filename, 1) + expect(res).toBeDefined() + }) + + it('should throw when file does not exist', async () => { + const fn = async () => { + await readFileLine(__filename + 'fooobar', 1) + } + await expect(fn()).rejects.toThrow(Error) + }) + }) + + describe('readFileLines', () => { + it('should throw when file does not exist', async () => { + const fn = async () => { + await readFileLines(__filename + 'fooobar', 0, 3) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should read lines', async () => { + let res = await readFileLines(__filename, 0, 1) + expect(res.length).toBe(2) + }) + }) + + describe('isGitIgnored()', () => { + it('should be not ignored', async () => { + let res = await isGitIgnored(__filename) + expect(res).toBeFalsy + }) + + it('should be ignored', async () => { + let res = await isGitIgnored('') + expect(res).toBe(false) + res = await isGitIgnored(path.join(os.tmpdir(), 'foo')) + expect(res).toBe(false) + res = await isGitIgnored(path.resolve(__dirname, '../lib/index.js.map')) + expect(res).toBe(false) + res = await isGitIgnored(__filename) + expect(res).toBe(false) + let filepath = path.join(os.tmpdir(), 'foo') + fs.writeFileSync(filepath, '', { encoding: 'utf8' }) + res = await isGitIgnored(filepath) + expect(res).toBe(false) + fs.unlinkSync(filepath) + }) + }) + + describe('inDirectory', () => { + it('should support wildcard', async () => { + let res = inDirectory(__dirname, ['**/file_not_exist.json']) + expect(res).toBe(false) + }) + }) + + describe('parentDirs', () => { + it('get parentDirs', () => { + let dirs = parentDirs('/a/b/c') + expect(dirs).toEqual(['/', '/a', '/a/b']) + }) + }) + + describe('isParentFolder', () => { + it('check parent folder', () => { + expect(isParentFolder('/a', '/a/b')).toBe(true) + expect(isParentFolder('/a/b', '/a/b/')).toBe(false) + expect(isParentFolder('/a/b', '/a/b')).toBe(false) + expect(isParentFolder('/a/b', '/a/b', true)).toBe(true) + expect(isParentFolder('//', '/', true)).toBe(true) + expect(isParentFolder('/a/b/', '/a/b/c', true)).toBe(true) + }) + }) + + describe('fixDriver', () => { + it('should fix driver', async () => { + expect(fixDriver('c:/foo', 'win32')).toBe('C:/foo') + }) + }) + + describe('resolveRoot', () => { + it('resolve root consider root path', () => { + let res = resolveRoot(__dirname, ['.git']) + expect(res).toMatch('coc.nvim') + }) + + it('should ignore glob pattern', () => { + let res = resolveRoot(__dirname, [path.basename(__filename)], undefined, false, false, ["**/__tests__/**"]) + expect(res).toBeFalsy() + }) + + it('should ignore glob pattern bottom up', () => { + let res = resolveRoot(__dirname, [path.basename(__filename)], undefined, true, false, ["**/__tests__/**"]) + expect(res).toBeFalsy() + }) + + it('should resolve from parent folders', () => { + let root = path.resolve(__dirname, '../extensions/snippet-sample') + let res = resolveRoot(root, ['package.json']) + expect(res.endsWith('coc.nvim')).toBe(true) + }) + + it('should resolve from parent folders with bottom-up method', () => { + let root = path.resolve(__dirname, '../extensions/snippet-sample') + let res = resolveRoot(root, ['package.json'], null, true) + expect(res.endsWith('extensions')).toBe(true) + }) + + it('should resolve to cwd', () => { + let root = path.resolve(__dirname, '../extensions/test/') + let res = resolveRoot(root, ['package.json'], root, false, true) + expect(res).toBe(root) + }) + + it('should resolve to root', () => { + let root = path.resolve(__dirname, '../extensions/test/') + let res = resolveRoot(root, ['package.json'], root, false, false) + expect(res).toBe(path.resolve(__dirname, '../../../')) + }) + + it('should not resolve to home', () => { + let res = resolveRoot(__dirname, ['.config'], undefined, false, false, [os.homedir()]) + expect(res != os.homedir()).toBeTruthy() + }) + }) + + describe('findUp', () => { + it('findUp by filename', () => { + let filepath = findUp('package.json', __dirname) + expect(filepath).toMatch('coc.nvim') + filepath = findUp('not_exists', __dirname) + expect(filepath).toBeNull() + }) + + it('findUp by filenames', async () => { + let filepath = findUp(['src'], __dirname) + expect(filepath).toMatch('coc.nvim') + }) + }) + +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/installer.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/installer.test.ts new file mode 100644 index 00000000..c06c1877 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/installer.test.ts @@ -0,0 +1,125 @@ +import { registryUrl, getInstallArguments, getDependencies, Installer } from '../../model/installer' +import { rmdir } from '../helper' +import workspace from '../../workspace' +import path from 'path' +import which from 'which' +import fs from 'fs-extra' +import os from 'os' + +const rcfile = path.join(os.tmpdir(), '.npmrc') + +describe('Installer', () => { + it('should get registry url', async () => { + fs.writeFileSync(rcfile, '', 'utf8') + expect(registryUrl()).toBe('https://registry.npmjs.org/') + fs.writeFileSync(rcfile, 'coc.nvim:registry=https://example.org', 'utf8') + expect(registryUrl()).toBe('https://example.org/') + fs.writeFileSync(rcfile, 'registry=https://example.org/', 'utf8') + expect(registryUrl()).toBe('https://example.org/') + if (fs.existsSync(rcfile)) { + fs.unlinkSync(rcfile) + } + }) + + it('should get install arguments', async () => { + expect(getInstallArguments('pnpm', 'https://github.com/')).toEqual(['install']) + expect(getInstallArguments('npm', '')).toEqual(['install', '--ignore-scripts', '--no-lockfile', '--production', '--legacy-peer-deps', '--no-global']) + expect(getInstallArguments('yarn', '')).toEqual(['install', '--ignore-scripts', '--no-lockfile', '--production', '--ignore-engines']) + }) + + it('should get dependencies', async () => { + expect(getDependencies('{}')).toEqual({}) + expect(getDependencies('')).toEqual({}) + expect(getDependencies('{"dependencies":{"foo": "0.0.1"}}')).toEqual({ foo: '0.0.1' }) + expect(getDependencies('{"dependencies":{"coc.nvim": "0.0.80"}}')).toEqual({}) + }) + + it('should parse name & version', async () => { + const getInfo = (def: string): { name?: string, version?: string } => { + let installer = new Installer(__dirname, 'npm', def) + return installer.info + } + expect(getInfo('https://github.com')).toEqual({ name: undefined, version: undefined }) + expect(getInfo('@yaegassy/coc-intelephense')).toEqual({ name: '@yaegassy/coc-intelephense', version: undefined }) + expect(getInfo('@yaegassy/coc-intelephense@1.0.0')).toEqual({ name: '@yaegassy/coc-intelephense', version: '1.0.0' }) + expect(getInfo('foo@1.0.0')).toEqual({ name: 'foo', version: '1.0.0' }) + }) + + it('should throw for url that not supported', async () => { + let installer = new Installer(__dirname, 'npm', 'https://example.com') + let fn = async () => { + await installer.getInfoFromUri() + } + await expect(fn()).rejects.toThrow(/not supported/) + }) + + it('should get info from url', async () => { + let installer = new Installer(__dirname, 'npm', 'https://github.com/sdras/vue-vscode-snippets@main') + let info = await installer.getInfoFromUri() + expect(info['dist.tarball']).toMatch(/main.tar.gz/) + }, 10000) + + it('should skip install & update for symbolic folder', async () => { + let tmpDir = path.join(os.tmpdir(), 'foo') + if (fs.existsSync(tmpDir)) { + fs.unlinkSync(tmpDir) + } + fs.symlinkSync(__dirname, tmpDir, 'dir') + let installer = new Installer(os.tmpdir(), 'npm', 'foo') + let res = await installer.doInstall({ name: 'foo' }) + expect(res).toBe(false) + let val = await installer.update() + expect(val).toBeUndefined() + fs.unlinkSync(tmpDir) + }) + + it('should skip update when current version is latest', async () => { + let dir = path.join(os.tmpdir(), 'coc-pairs') + let installer = new Installer(os.tmpdir(), 'npm', 'coc-pairs') + let info = await installer.getInfo() + fs.mkdirSync(dir) + fs.writeFileSync(path.join(dir, 'package.json'), `{"version": "${info.version}"}`, 'utf8') + let res = await installer.update() + expect(res).toBeUndefined() + rmdir(dir) + }, 20000) + + it('should skip update when version not satisfies', async () => { + let v = workspace.version + Object.assign(workspace, { version: '0.0.10' }) + let installer = new Installer(os.tmpdir(), 'npm', 'coc-pairs') + let dir = path.join(os.tmpdir(), 'coc-pairs') + fs.mkdirSync(dir, { recursive: true }) + let fn = async () => { + await installer.update() + } + await expect(fn()).rejects.toThrow(/please update/) + Object.assign(workspace, { version: v }) + rmdir(dir) + }) + + it('should update extension', async () => { + let installer = new Installer(os.tmpdir(), 'npm', 'coc-pairs') + let dir = path.join(os.tmpdir(), 'coc-pairs') + fs.mkdirSync(dir, { recursive: true }) + let res = await installer.update() + expect(res).toMatch(/coc-pairs/) + rmdir(dir) + }, 30000) + + it('should install extension with dependencies', async () => { + let npm: string + try { + npm = which.sync('pnpm') + } catch (e) { + npm = which.sync('npm') + } + // coc-html use typescript as dependencies + let installer = new Installer(os.tmpdir(), npm, 'coc-html') + await installer.install() + let folder = path.join(os.tmpdir(), 'coc-html') + expect(fs.existsSync(path.join(folder, 'node_modules/typescript/package.json'))).toBe(true) + fs.unlinkSync(path.join(os.tmpdir(), 'package.json')) + rmdir(folder) + }, 30000) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/memos.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/memos.test.ts new file mode 100644 index 00000000..1290a66b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/memos.test.ts @@ -0,0 +1,45 @@ +import Memos from '../../model/memos' +import os from 'os' +import path from 'path' +import fs from 'fs' + +let filepath = path.join(os.tmpdir(), 'test') +let memos: Memos +beforeEach(() => { + memos = new Memos(filepath) +}) + +afterEach(() => { + if (fs.existsSync(filepath)) { + fs.unlinkSync(filepath) + } +}) + +describe('Memos', () => { + it('should update and get', async () => { + let memo = memos.createMemento('x') + await memo.update('foo.bar', 'memo') + let res = memo.get('foo.bar') + expect(res).toBe('memo') + }) + + it('should get value for key if it does not exist', async () => { + let memo = memos.createMemento('y') + let res = memo.get('xyz') + expect(res).toBeUndefined() + }) + + it('should use defaultValue when it does not exist', async () => { + let memo = memos.createMemento('y') + let res = memo.get('f.o.o', 'default') + expect(res).toBe('default') + }) + + it('should update multiple values', async () => { + let memo = memos.createMemento('x') + await memo.update('foo', 'x') + await memo.update('bar', 'y') + expect(memo.get('foo')).toBe('x') + expect(memo.get('bar')).toBe('y') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/menu.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/menu.test.ts new file mode 100644 index 00000000..14d3d73f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/menu.test.ts @@ -0,0 +1,163 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource } from 'vscode-languageserver-protocol' +import Menu from '../../model/menu' +import helper from '../helper' + +let nvim: Neovim +let menu: Menu + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + menu.dispose() + await helper.reset() +}) + +describe('Menu', () => { + it('should cancel by ', async () => { + menu = new Menu(nvim, { items: [{ text: 'foo' }, { text: 'bar', disabled: true }] }) + let p = new Promise(resolve => { + menu.onDidClose(v => { + resolve(v) + }) + }) + await menu.show() + await helper.wait(30) + await nvim.input('') + let res = await p + expect(res).toBe(-1) + }) + + it('should cancel before float window shown', async () => { + let tokenSource: CancellationTokenSource = new CancellationTokenSource() + menu = new Menu(nvim, { items: [{ text: 'foo' }] }, tokenSource.token) + let p = new Promise(resolve => { + menu.onDidClose(v => { + resolve(v) + }) + }) + let promise = menu.show() + tokenSource.cancel() + await promise + let res = await p + expect(res).toBe(-1) + }) + + it('should support menu shortcut', async () => { + menu = new Menu(nvim, { items: [{ text: 'foo' }, { text: 'bar' }, { text: 'baba' }], shortcuts: true, title: 'Actions' }) + let p = new Promise(resolve => { + menu.onDidClose(v => { + resolve(v) + }) + }) + await menu.show() + await helper.wait(30) + await nvim.input('b') + let res = await p + expect(res).toBe(1) + }) + + it('should support content', async () => { + menu = new Menu(nvim, { items: [{ text: 'foo' }, { text: 'bar' }], content: 'content' }) + await menu.show() + let lines = await menu.buffer.lines + menu.dispose() + expect(lines[0]).toBe('content') + }) + + it('should select by CR', async () => { + menu = new Menu(nvim, { items: ['foo', 'bar'] }) + let p = new Promise(resolve => { + menu.onDidClose(v => { + resolve(v) + }) + }) + await menu.show() + await helper.wait(30) + await nvim.input('j') + await helper.wait(30) + await nvim.input('') + let res = await p + expect(res).toBe(1) + }) + + it('should show menu in center', async () => { + menu = new Menu(nvim, { items: ['foo', 'bar'], position: 'center' }) + await menu.show() + expect(menu.buffer).toBeDefined() + }) + + it('should ignore invalid index', async () => { + menu = new Menu(nvim, { items: ['foo', 'bar'] }) + await menu.show() + await helper.wait(30) + await nvim.input('0') + await helper.wait(30) + let exists = await nvim.call('coc#float#has_float', []) + expect(exists).toBe(1) + }) + + it('should select by index number', async () => { + menu = new Menu(nvim, { items: ['foo', 'bar'] }) + let p = new Promise(resolve => { + menu.onDidClose(v => { + resolve(v) + }) + }) + await menu.show() + await helper.wait(30) + await nvim.input('1') + let res = await p + expect(res).toBe(0) + }) + + it('should navigate by j, k, g & G', async () => { + menu = new Menu(nvim, { items: ['one', 'two', 'three'] }) + await menu.show() + await helper.wait(50) + let id = await nvim.call('GetFloatWin') + expect(id).toBeGreaterThan(0) + let win = nvim.createWindow(id) + await nvim.input('j') + await helper.wait(50) + let cursor = await win.cursor + expect(cursor[0]).toBe(2) + await nvim.input('k') + await helper.wait(50) + cursor = await win.cursor + expect(cursor[0]).toBe(1) + await nvim.input('G') + await helper.wait(50) + cursor = await win.cursor + expect(cursor[0]).toBe(3) + await nvim.input('g') + await helper.wait(50) + cursor = await win.cursor + expect(cursor[0]).toBe(1) + }) + + it('should select by numbers', async () => { + let selected: number + menu = new Menu(nvim, { items: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] }) + await menu.show() + let promise = new Promise(resolve => { + menu.onDidClose(n => { + selected = n + resolve(undefined) + }) + }) + await helper.wait(50) + await nvim.input('1') + await helper.wait(50) + await nvim.input('0') + await promise + expect(selected).toBe(9) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/mru.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/mru.test.ts new file mode 100644 index 00000000..6a820b6c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/mru.test.ts @@ -0,0 +1,43 @@ +import Mru from '../../model/mru' +import os from 'os' +import fs from 'fs' +import path from 'path' +const root = fs.mkdtempSync(path.join(os.tmpdir(), 'coc-mru-')) + +describe('Mru', () => { + + it('should load items', async () => { + let mru = new Mru('test', root) + await mru.clean() + let res = await mru.load() + expect(res.length).toBe(0) + res = mru.loadSync() + expect(res.length).toBe(0) + }) + + it('should add items', async () => { + let mru = new Mru('test', root) + await mru.add('a') + await mru.add('b') + let res = await mru.load() + expect(res.length).toBe(2) + await mru.clean() + }) + + it('should add when file it does not exist', async () => { + let mru = new Mru('test', root) + await mru.clean() + await mru.add('a') + let res = await mru.load() + expect(res).toEqual(['a']) + }) + + it('should remove item', async () => { + let mru = new Mru('test', root) + await mru.add('a') + await mru.remove('a') + let res = await mru.load() + expect(res.length).toBe(0) + await mru.clean() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/outputChannel.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/outputChannel.test.ts new file mode 100644 index 00000000..b7dec74c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/outputChannel.test.ts @@ -0,0 +1,82 @@ +import { Neovim } from '@chemzqm/neovim' +import OutputChannel from '../../model/outputChannel' +import { wait } from '../../util' +import helper from '../helper' + +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterEach(async () => { + await helper.reset() +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('OutputChannel', () => { + test('bad channel name', () => { + let err + try { + new OutputChannel('@', nvim) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + test('outputChannel.show(true)', async () => { + await nvim.setLine('foo') + let c = new OutputChannel('0', nvim) + let bufnr = (await nvim.buffer).id + c.show(true) + await helper.waitFor('bufnr', ['%'], bufnr) + }) + + test('outputChannel.show(false)', async () => { + let c = new OutputChannel('1', nvim) + let bufnr = (await nvim.buffer).id + c.show() + await wait(100) + let nr = (await nvim.buffer).id + expect(bufnr).toBeLessThan(nr) + }) + + test('outputChannel.appendLine()', async () => { + let c = new OutputChannel('2', nvim) + c.show() + await wait(100) + let buf = await nvim.buffer + c.appendLine('foo') + await helper.waitFor('eval', [`join(getbufline(${buf.id},1,'$'),'\n')`], /foo/) + }) + + test('outputChannel.append()', async () => { + let c = new OutputChannel('3', nvim) + c.show(false) + await wait(60) + c.append('foo') + c.append('bar') + await wait(50) + let buf = await nvim.buffer + await helper.waitFor('eval', [`join(getbufline(${buf.id},1,'$'),'\n')`], /foo/) + }) + + test('outputChannel.clear()', async () => { + let c = new OutputChannel('4', nvim) + c.show(false) + await wait(30) + let buf = await nvim.buffer + c.appendLine('foo') + c.appendLine('bar') + await wait(30) + c.clear() + await wait(30) + let lines = await buf.lines + let content = lines.join('') + expect(content).toBe('') + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/picker.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/picker.test.ts new file mode 100644 index 00000000..c772f7bd --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/picker.test.ts @@ -0,0 +1,161 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource } from 'vscode-languageserver-protocol' +import Picker from '../../model/picker' +import { QuickPickItem } from '../../types' +import helper from '../helper' + +let nvim: Neovim +let picker: Picker + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + if (picker) picker.dispose() + picker = undefined + await helper.reset() +}) + +const items: QuickPickItem[] = [{ label: 'foo' }, { label: 'bar' }] + +describe('Picker create', () => { + it('should show dialog with buttons', async () => { + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show({ pickerButtons: true }) + expect(winid).toBeDefined() + let id = await nvim.call('coc#float#get_related', [winid, 'buttons']) + expect(id).toBeGreaterThan(0) + let res = await nvim.call('sign_getplaced', [picker.buffer.id, { group: 'PopUpCocDialog' }]) + expect(res[0].signs).toBeDefined() + expect(res[0].signs[0].name).toBe('CocCurrentLine') + }) + + it('should cancel dialog when cancellation token requested', async () => { + let tokenSource = new CancellationTokenSource() + picker = new Picker(nvim, { title: 'title', items }, tokenSource.token) + let winid = await picker.show({ pickerButtons: true }) + expect(winid).toBeDefined() + tokenSource.cancel() + await helper.wait(50) + let res = await nvim.call('coc#float#valid', [winid]) + expect(res).toBe(0) + }) +}) + +describe('Picker key mappings', () => { + it('should toggle selection mouse click bracket', async () => { + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show() + await nvim.setVar('mouse_position', [winid, 1, 1]) + await nvim.input('') + await helper.wait(50) + let buf = picker.buffer + let lines = await buf.getLines({ start: 0, end: 1, strictIndexing: false }) + expect(lines[0]).toMatch(/^\[x\]/) + }) + + it('should change current line on mouse click label', async () => { + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show() + await nvim.setVar('mouse_position', [winid, 2, 4]) + await nvim.input('') + await helper.wait(50) + let buf = picker.buffer + let res = await nvim.call('sign_getplaced', [buf.id, { group: 'PopUpCocDialog' }]) + expect(res[0].signs).toBeDefined() + expect(res[0].signs[0].name).toBe('CocCurrentLine') + }) + + it('should cancel by ', async () => { + await helper.createDocument() + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show({ pickerButtons: true }) + expect(winid).toBeDefined() + let fn = jest.fn() + picker.onDidClose(fn) + await nvim.eval(`feedkeys("\\", 'in')`) + await helper.wait(200) + expect(fn).toBeCalledTimes(1) + }) + + it('should confirm by ', async () => { + await helper.createDocument() + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show({ pickerButtons: true }) + expect(winid).toBeDefined() + let fn = jest.fn() + picker.onDidClose(fn) + await nvim.input('') + await helper.wait(100) + await nvim.input('') + await nvim.command('redraw') + await helper.wait(200) + expect(fn).toBeCalledTimes(1) + }) + + it('should move cursor by j, k, g & G', async () => { + await helper.createDocument() + picker = new Picker(nvim, { title: 'title', items }) + function getSigns(): Promise { + return nvim.call('sign_getplaced', [picker.buffer.id, { group: 'PopUpCocDialog' }]) + } + let winid = await picker.show({ pickerButtons: true }) + await helper.waitFloat() + expect(winid).toBeDefined() + await nvim.input('j') + await helper.wait(100) + let res = await getSigns() + expect(res[0].signs[0].lnum).toBe(2) + await nvim.input('k') + await helper.wait(100) + res = await getSigns() + expect(res[0].signs[0].lnum).toBe(1) + await nvim.input('G') + await helper.wait(100) + res = await getSigns() + expect(res[0].signs[0].lnum).toBe(2) + await nvim.input('g') + await helper.wait(100) + res = await getSigns() + expect(res[0].signs[0].lnum).toBe(1) + }) + + it('should toggle selection by ', async () => { + await helper.createDocument() + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show({ pickerButtons: true }) + await helper.waitFloat() + expect(winid).toBeDefined() + let fn = jest.fn() + picker.onDidClose(fn) + await nvim.input('') + await helper.wait(300) + await nvim.command('redraw') + let lines = await nvim.call('getbufline', [picker.buffer.id, 1]) + expect(lines[0]).toMatch('[x]') + }) + + it('should scroll forward & backward', async () => { + await helper.createDocument() + let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'].map(s => { + return { label: s } + }) + picker = new Picker(nvim, { title: 'title', items }) + let winid = await picker.show({ maxHeight: 3 }) + expect(winid).toBeDefined() + await nvim.input('') + await helper.wait(100) + let info = await nvim.call('getwininfo', [winid]) + expect(info[0]).toBeDefined() + await nvim.input('') + await helper.wait(100) + info = await nvim.call('getwininfo', [winid]) + expect(info[0]).toBeDefined() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/plugin.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/plugin.test.ts new file mode 100644 index 00000000..d8d6beff --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/plugin.test.ts @@ -0,0 +1,48 @@ +import helper from '../helper' +import path from 'path' +import workspace from '../../workspace' +import { Neovim } from '@chemzqm/neovim' + +let nvim: Neovim + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +describe('help tags', () => { + it('should generate help tags', async () => { + let root = workspace.pluginRoot + let dir = await nvim.call('fnameescape', path.join(root, 'doc')) + let res = await nvim.call('execute', `helptags ${dir}`) as string + expect(res.length).toBe(0) + }) + + it('should return jumpable', async () => { + let jumpable = await helper.plugin.cocAction('snippetCheck', false, true) + expect(jumpable).toBe(false) + }) + + it('should show CocInfo', async () => { + await helper.doAction('showInfo') + let line = await nvim.line + expect(line).toMatch('version') + }) + + it('should ensure current document created', async () => { + await nvim.command('tabe tmp.js') + let res = await helper.plugin.cocAction('ensureDocument') + expect(res).toBe(true) + let bufnr = await nvim.call('bufnr', ['%']) + let doc = workspace.getDocument(bufnr) + expect(doc).toBeDefined() + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/quickpick.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/quickpick.test.ts new file mode 100644 index 00000000..4b6d827c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/quickpick.test.ts @@ -0,0 +1,325 @@ +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import { QuickPickItem } from '../../types' +import { disposeAll } from '../../util' +import events from '../../events' +import window from '../../window' +import workspace from '../../workspace' +import helper from '../helper' +export type Item = QuickPickItem | string + +let nvim: Neovim +let disposables: Disposable[] = [] + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('window', () => { + async function getTitleLine(): Promise { + let winids = await nvim.call('coc#float#get_float_win_list') as number[] + let winid = Math.min(...winids) + let id = await nvim.call('coc#float#get_related', [winid, 'border']) + let win = nvim.createWindow(id) + let buf = await win.buffer + let lines = await buf.lines + return lines[0] + } + + describe('showQuickPick', () => { + async function testQuickPick(items: Item[], canPickMany: boolean, cancel: boolean, res: any) { + let p = window.showQuickPick(items, { canPickMany }) + await helper.waitFloat() + await nvim.input('b') + if (canPickMany) { + await nvim.input('') + } + await helper.wait(50) + if (cancel) { + await nvim.input('') + } else { + await nvim.input('') + } + let result = await p + if (res == null) { + expect(result).toBe(res) + } else { + expect(res).toEqual(res) + } + } + + it('should throw when dialog not supported ', async () => { + Object.assign(workspace.env, { dialog: false }) + disposables.push({ + dispose: () => { + Object.assign(workspace.env, { dialog: true }) + } + }) + let fn = async () => { + await window.showQuickPick(['foo', 'bar']) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should resolve undefined when token cancelled', async () => { + let tokenSource = new CancellationTokenSource() + let token = tokenSource.token + tokenSource.cancel() + let res = await window.showQuickPick(['foo', 'bar'], undefined, token) + expect(res).toBeUndefined() + let release = await window.mutex.acquire() + tokenSource = new CancellationTokenSource() + token = tokenSource.token + let p = window.showQuickPick(['foo', 'bar'], undefined, token) + tokenSource.cancel() + release() + res = await p + expect(res).toBeUndefined() + }) + + it('should show quickfix with items or texts', async () => { + await testQuickPick(['foo', 'bar'], false, false, 'bar') + await testQuickPick(['foo', 'bar'], true, false, ['bar']) + await testQuickPick(['foo', 'bar'], false, true, undefined) + let items: QuickPickItem[] = [{ label: 'foo', description: 'desc' }, { label: 'bar', picked: true }] + await testQuickPick(items, false, false, { label: 'bar', picked: true }) + await testQuickPick(items, true, false, [{ label: 'bar', picked: true }]) + }) + + it('should use title option', async () => { + let p = window.showQuickPick(['foo', 'bar'], { title: 'title' }) + await helper.waitFloat() + let line = await getTitleLine() + expect(line).toMatch('title') + await nvim.input('') + await p + }) + + it('should match on description', async () => { + let items: QuickPickItem[] = [{ label: 'foo', description: 'desc' }, { label: 'bar', picked: true }] + let p = window.showQuickPick(items, { matchOnDescription: true }) + await helper.waitFloat() + await nvim.input('d') + await helper.wait(30) + await nvim.input('') + let res = await p + expect(res).toBeDefined() + }) + }) + + describe('createQuickPick', () => { + it('should throw when unable to open input window', async () => { + let fn = nvim.call + nvim.call = (...args: any) => { + if (args[0] === 'coc#dialog#create_prompt_win') return undefined + return fn.apply(nvim, args) + } + disposables.push(Disposable.create(() => { + nvim.call = fn + })) + let fun = async () => { + await window.createQuickPick({ + items: [{ label: 'foo' }, { label: 'bar' }], + }) + } + await expect(fun()).rejects.toThrow(/Unable to open/) + }) + + it('should throw when unable to open list window', async () => { + let fn = nvim.call + nvim.call = (...args: any) => { + if (args[0] === 'coc#dialog#create_list') return undefined + return fn.apply(nvim, args) + } + disposables.push(Disposable.create(() => { + nvim.call = fn + })) + let fun = async () => { + await window.createQuickPick({ + items: [{ label: 'foo' }, { label: 'bar' }], + }) + } + await expect(fun()).rejects.toThrow(/Unable to open/) + }) + + it('should respect initial value', async () => { + await window.createQuickPick({ + items: [{ label: 'foo' }, { label: 'bar' }], + value: 'value' + }) + let winids = await nvim.call('coc#float#get_float_win_list') as number[] + let winid = Math.min(...winids) + let buf = await (nvim.createWindow(winid)).buffer + let lines = await buf.lines + expect(lines[0]).toBe('value') + await nvim.input('') + }) + + it('should respect maxHeight', async () => { + await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + value: 'value', + maxHeight: 2 + }) + let winids = await nvim.call('coc#float#get_float_win_list') as number[] + let winid = Math.max(...winids) + let win = nvim.createWindow(winid) + let h = await win.height + expect(h).toBe(2) + await nvim.input('') + }) + + it('should scroll by and ', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + value: 'value', + maxHeight: 2 + }) + disposables.push(quickpick) + let winids = await nvim.call('coc#float#get_float_win_list') as number[] + let winid = Math.max(...winids) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + let info = await nvim.call('getwininfo', [winid]) + expect(info[0].topline).toBe(2) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + info = await nvim.call('getwininfo', [winid]) + expect(info[0].topline).toBe(1) + }) + + it('should change current line by and ', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + value: 'value', + maxHeight: 2 + }) + disposables.push(quickpick) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + expect(quickpick.currIndex).toBe(2) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + expect(quickpick.currIndex).toBe(0) + }) + + it('should toggle selected item by ', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + value: 'value', + maxHeight: 2 + }) + disposables.push(quickpick) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + await nvim.input('') + await helper.wait(30) + expect(quickpick.selectedItems.length).toBe(0) + }) + + it('should not handle events from other buffer', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + }) + disposables.push(quickpick) + await events.fire('BufWinLeave', [quickpick.buffer.id + 1]) + await events.fire('PromptKeyPress', [quickpick.buffer.id + 1, 'C-f']) + expect(quickpick.currIndex).toBe(0) + }) + + it('should respect configurations', async () => { + helper.updateConfiguration('dialog.maxWidth', 30) + helper.updateConfiguration('dialog.rounded', false) + helper.updateConfiguration('dialog.floatHighlight', 'Normal') + helper.updateConfiguration('dialog.floatBorderHighlight', 'Normal') + helper.updateConfiguration('dialog.maxHeight', 2) + await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }, { label: 'three' }], + value: 'value', + maxHeight: 2 + }) + let winids = await nvim.call('coc#float#get_float_win_list') as number[] + let winid = Math.max(...winids) + let win = nvim.createWindow(winid) + let h = await win.height + expect(h).toBe(2) + await nvim.input('') + }) + + it('should change title', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }], + title: 'from' + }) + disposables.push(quickpick) + quickpick.title = 'to' + await helper.wait(30) + expect(quickpick.title).toBe('to') + let line = await getTitleLine() + expect(line).toMatch(/to/) + }) + + it('should change loading', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }] + }) + disposables.push(quickpick) + quickpick.loading = true + expect(quickpick.loading).toBe(true) + quickpick.loading = false + expect(quickpick.loading).toBe(false) + }) + + it('should change items', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }, { label: 'two' }] + }) + disposables.push(quickpick) + quickpick.onDidChangeValue(val => { + if (val == '>') { + quickpick.items = [{ label: 'three' }] + } + }) + await nvim.input('>') + await helper.wait(30) + let lines = await quickpick.buffer.lines + expect(lines).toEqual(['three']) + }) + + it('should change activeItems', async () => { + let quickpick = await window.createQuickPick({ + items: [{ label: 'one' }] + }) + disposables.push(quickpick) + quickpick.onDidChangeValue(val => { + if (val == 'f') { + quickpick.activeItems = [{ label: 'foo', description: 'description' }, { label: 'foot' }] + } + }) + await nvim.input('f') + await helper.wait(30) + let lines = await quickpick.buffer.lines + expect(lines).toEqual(['foo description', 'foot']) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/regions.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/regions.test.ts new file mode 100644 index 00000000..7b913359 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/regions.test.ts @@ -0,0 +1,74 @@ +import Regions from '../../model/regions' + +describe('Regions', () => { + it('should add #1', async () => { + let r = new Regions() + r.add(1, 2) + r.add(1, 2) + expect(r.current).toEqual([1, 2]) + }) + + it('should add #2', async () => { + let r = new Regions() + r.add(3, 4) + r.add(1, 5) + expect(r.current).toEqual([1, 5]) + }) + + it('should add #3', async () => { + let r = new Regions() + r.add(2, 3) + r.add(1, 2) + expect(r.current).toEqual([1, 3]) + }) + + it('should add #4', async () => { + let r = new Regions() + r.add(2, 5) + r.add(3, 4) + expect(r.current).toEqual([2, 5]) + }) + + it('should add #5', async () => { + let r = new Regions() + r.add(3, 4) + r.add(1, 5) + expect(r.current).toEqual([1, 5]) + }) + + it('should add #6', async () => { + let r = new Regions() + r.add(1, 2) + r.add(3, 5) + expect(r.current).toEqual([1, 2, 3, 5]) + r.add(1, 8) + expect(r.current).toEqual([1, 8]) + }) + + it('should add #7', async () => { + let r = new Regions() + r.add(1, 2) + r.add(1, 5) + expect(r.current).toEqual([1, 5]) + r.add(9, 10) + r.add(5, 6) + expect(r.current).toEqual([1, 6, 9, 10]) + }) + + it('should check range', async () => { + let r = new Regions() + r.add(1, 2) + r.add(1, 5) + expect(r.has(3, 5)).toBe(true) + expect(r.has(3, 6)).toBe(false) + }) + + it('should merge spans', async () => { + expect(Regions.mergeSpans([[0, 1], [1, 2]])).toEqual([[0, 2]]) + expect(Regions.mergeSpans([[0, 1], [2, 3]])).toEqual([[0, 1], [2, 3]]) + expect(Regions.mergeSpans([[2, 3], [0, 1]])).toEqual([[2, 3], [0, 1]]) + expect(Regions.mergeSpans([[1, 4], [0, 5]])).toEqual([[0, 5]]) + expect(Regions.mergeSpans([[1, 4], [2, 3]])).toEqual([[1, 4]]) + expect(Regions.mergeSpans([[1, 2], [2, 3], [3, 4]])).toEqual([[1, 4]]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/sandbox/log.js b/sources_non_forked/coc.nvim/src/__tests__/modules/sandbox/log.js new file mode 100644 index 00000000..1aa95d8c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/sandbox/log.js @@ -0,0 +1,9 @@ +console.log('log') +console.debug('debug') +console.info('info') +console.error('error') +console.warn('warn') + +module.exports = () => { + return require('coc.nvim') +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/semanticTokensBuilder.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/semanticTokensBuilder.test.ts new file mode 100644 index 00000000..80fb0d58 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/semanticTokensBuilder.test.ts @@ -0,0 +1,80 @@ +import { SemanticTokensBuilder } from '../../model/semanticTokensBuilder' +import { Range, SemanticTokensLegend } from 'vscode-languageserver-protocol' + +function toArr(uint32Arr: ReadonlyArray): number[] { + const r = [] + for (let i = 0, len = uint32Arr.length; i < len; i++) { + r[i] = uint32Arr[i] + } + return r +} + +function deepStrictEqual(one: any, two: any): void { + expect(one).toEqual(two) +} + +describe('SemanticTokensBuilder', () => { + it('should build SemanticTokensBuilder simple', () => { + const builder = new SemanticTokensBuilder() + builder.push(1, 0, 5, 1, 1) + builder.push(1, 10, 4, 2, 2) + builder.push(2, 2, 3, 2, 2) + deepStrictEqual(toArr(builder.build().data), [ + 1, 0, 5, 1, 1, + 0, 10, 4, 2, 2, + 1, 2, 3, 2, 2 + ]) + }) + + it('should build SemanticTokensBuilder no modifier', () => { + const builder = new SemanticTokensBuilder() + builder.push(1, 0, 5, 1) + builder.push(1, 10, 4, 2) + builder.push(2, 2, 3, 2) + deepStrictEqual(toArr(builder.build().data), [ + 1, 0, 5, 1, 0, + 0, 10, 4, 2, 0, + 1, 2, 3, 2, 0 + ]) + }) + + it('should build SemanticTokensBuilder out of order 1', () => { + const builder = new SemanticTokensBuilder() + builder.push(2, 0, 5, 1, 1) + builder.push(2, 10, 1, 2, 2) + builder.push(2, 15, 2, 3, 3) + builder.push(1, 0, 4, 4, 4) + deepStrictEqual(toArr(builder.build().data), [ + 1, 0, 4, 4, 4, + 1, 0, 5, 1, 1, + 0, 10, 1, 2, 2, + 0, 5, 2, 3, 3 + ]) + }) + + it('SemanticTokensBuilder out of order 2', () => { + const builder = new SemanticTokensBuilder() + builder.push(2, 10, 5, 1, 1) + builder.push(2, 2, 4, 2, 2) + deepStrictEqual(toArr(builder.build().data), [ + 2, 2, 4, 2, 2, + 0, 8, 5, 1, 1 + ]) + }) + + test('SemanticTokensBuilder with legend', () => { + const legend: SemanticTokensLegend = { + tokenTypes: ['aType', 'bType', 'cType', 'dType'], + tokenModifiers: ['mod0', 'mod1', 'mod2', 'mod3', 'mod4', 'mod5'] + } + const builder = new SemanticTokensBuilder(legend) + builder.push(Range.create(1, 0, 1, 5), 'bType') + builder.push(Range.create(2, 0, 2, 4), 'cType', ['mod0', 'mod5']) + builder.push(Range.create(3, 0, 3, 3), 'dType', ['mod2', 'mod4']) + deepStrictEqual(toArr(builder.build().data), [ + 1, 0, 5, 1, 0, + 1, 0, 4, 2, 1 | (1 << 5), + 1, 0, 3, 3, (1 << 2) | (1 << 4) + ]) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/settings.json b/sources_non_forked/coc.nvim/src/__tests__/modules/settings.json new file mode 100644 index 00000000..55bb35f8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/settings.json @@ -0,0 +1,12 @@ +{ + "foo.bar": 1, + "bar.foo": 2, + "schema": { + "https://example.com": "*.yaml" + }, + "servers": { + "c": { + "trace.server": "verbose" + } + } +} \ No newline at end of file diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/sources.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/sources.test.ts new file mode 100644 index 00000000..c8be94fb --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/sources.test.ts @@ -0,0 +1,198 @@ +import { Disposable } from 'vscode-languageserver-protocol' +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import events from '../../events' +import sources from '../../sources' +import { ISource, SourceType } from '../../types' +import { disposeAll } from '../../util' +import helper from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + disposeAll(disposables) + await helper.reset() +}) + +describe('sources', () => { + it('should do document enter', async () => { + let fn = jest.fn() + let source: ISource = { + name: 'enter', + enable: true, + priority: 0, + sourceType: SourceType.Service, + triggerCharacters: [], + doComplete: () => Promise.resolve({ items: [] }), + onEnter: fn + } + disposables.push(sources.addSource(source)) + let buffer = await nvim.buffer + await events.fire('BufEnter', [buffer.id]) + expect(fn).toBeCalled() + }) + + it('should get sources by split filetypes', async () => { + disposables.push(sources.addSource({ + name: 'foo', + filetypes: ['foo'], + enable: true, + doComplete: () => Promise.resolve({ items: [] }), + })) + disposables.push(sources.addSource({ + name: 'bar', + filetypes: ['bar'], + enable: true, + doComplete: () => Promise.resolve({ items: [] }), + })) + let arr = sources.getNormalSources('foo.bar', 'file:///a') + let names = arr.map(s => s.name) + expect(names.includes('foo')).toBe(true) + expect(names.includes('bar')).toBe(true) + }) + + it('should return source states', () => { + let stats = sources.sourceStats() + expect(stats.length > 1).toBe(true) + }) + + it('should toggle source state', () => { + sources.toggleSource('around') + let s = sources.getSource('around') + expect(s.enable).toBe(false) + sources.toggleSource('around') + }) +}) + +describe('sources#has', () => { + + it('should has source', () => { + expect(sources.has('around')).toBe(true) + }) + + it('should not has source', () => { + expect(sources.has('NotExists')).toBe(false) + }) +}) + +describe('sources#refresh', () => { + it('should refresh if possible', async () => { + let fn = jest.fn() + let source: ISource = { + name: 'refresh', + enable: true, + priority: 0, + sourceType: SourceType.Service, + triggerCharacters: [], + doComplete: () => Promise.resolve({ items: [] }), + refresh: fn + } + disposables.push(sources.addSource(source)) + await sources.refresh('refresh') + expect(fn).toBeCalled() + }) + + it('should work if refresh not defined', async () => { + let source: ISource = { + name: 'refresh', + enable: true, + priority: 0, + sourceType: SourceType.Service, + triggerCharacters: [], + doComplete: () => Promise.resolve({ items: [] }) + } + disposables.push(sources.addSource(source)) + await sources.refresh('refresh') + }) +}) + +describe('sources#createSource', () => { + it('should create source', async () => { + disposables.push(sources.createSource({ + name: 'custom', + doComplete: () => Promise.resolve({ + items: [{ + word: 'custom' + }] + }) + })) + await helper.createDocument() + await nvim.input('i') + await helper.wait(30) + await nvim.input('c') + let visible = await helper.visible('custom', 'custom') + expect(visible).toBe(true) + }) + + it('should create vim source', async () => { + let folder = path.resolve(__dirname, '..') + await nvim.command(`set runtimepath+=${folder}`) + disposables.push({ + dispose: () => { + nvim.command(`set runtimepath-=${folder}`, true) + sources.removeSource('email') + } + }) + await helper.wait(100) + let exists = sources.has('email') + expect(exists).toBe(true) + await helper.createDocument() + await nvim.input('i') + await helper.wait(10) + await nvim.input('@') + await helper.visible('foo@gmail.com') + }) +}) + +describe('sources#getTriggerSources()', () => { + it('should filter by filetypes', async () => { + let source: ISource = { + name: 'test', + enable: true, + priority: 0, + filetypes: ['javascript'], + sourceType: SourceType.Service, + triggerCharacters: ['#'], + doComplete: () => Promise.resolve({ items: [] }) + } + disposables.push(sources.addSource(source)) + let res = sources.getTriggerSources('#', 'javascript', 'file:///tmp.js') + expect(res.find(o => o.name == 'test')).toBeDefined() + }) + + it('should filter by documentSelector', async () => { + let source: ISource = { + name: 'test', + enable: true, + priority: 0, + documentSelector: [{ language: 'javascript' }], + sourceType: SourceType.Service, + triggerCharacters: ['#'], + doComplete: () => Promise.resolve({ items: [] }) + } + disposables.push(sources.addSource(source)) + let res = sources.getTriggerSources('#', 'javascript', 'file:///tmp.js') + expect(res.find(o => o.name == 'test')).toBeDefined() + }) + + it('should filter disabled sources', async () => { + await nvim.setLine('foo bar ') + let buf = await nvim.buffer + await buf.setVar('coc_disabled_sources', ['around', 'buffer', 'file']) + await nvim.input('Af') + await helper.wait(30) + await nvim.input('/') + await helper.wait(100) + let visible = await nvim.call('pumvisible') + expect(visible).toBe(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/task.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/task.test.ts new file mode 100644 index 00000000..28846b31 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/task.test.ts @@ -0,0 +1,151 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterEach(() => { + disposeAll(disposables) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +describe('task test', () => { + it('should start task', async () => { + let task = workspace.createTask('sleep') + disposables.push(task) + let started = await task.start({ cmd: 'sleep', args: ['50'] }) + expect(started).toBe(true) + }) + + it('should stop task', async () => { + let task = workspace.createTask('sleep') + disposables.push(task) + await task.start({ cmd: 'sleep', args: ['50'] }) + await task.stop() + let running = await task.running + expect(running).toBe(false) + }) + + it('should emit exit event', async () => { + let fn = jest.fn() + let task = workspace.createTask('sleep') + disposables.push(task) + task.onExit(fn) + await task.start({ cmd: 'sleep', args: ['50'] }) + await helper.wait(10) + await task.stop() + expect(fn).toBeCalled() + }) + + it('should emit stdout event', async () => { + let file = await createTmpFile('echo foo') + let task = workspace.createTask('echo') + disposables.push(task) + let p = new Promise(resolve => { + let lines: string[] = [] + task.onStdout(stdout => { + lines.push(...stdout) + }) + task.onExit(() => { + resolve(lines) + }) + }) + await task.start({ cmd: '/bin/sh', args: [file] }) + let lines = await p + expect(lines).toEqual(['foo']) + }) + + it('should change environment variables', async () => { + let file = await createTmpFile('echo $NODE_ENV\necho $COC_NVIM_TEST') + let task = workspace.createTask('ENV') + disposables.push(task) + let lines: string[] = [] + task.onStdout(arr => { + lines.push(...arr) + }) + await task.start({ + cmd: '/bin/sh', + args: [file], + env: { + NODE_ENV: 'production', + COC_NVIM_TEST: 'yes' + } + }) + await new Promise(resolve => { + task.onExit(() => { + resolve() + }) + }) + expect(lines).toEqual(['production', 'yes']) + let res = await nvim.call('getenv', 'COC_NVIM_TEST') + expect(res).toBeNull() + }) + + it('should receive stdout lines as expected', async () => { + let file = await createTmpFile('echo 3\necho ""\necho 4') + let task = workspace.createTask('ENV') + let p = new Promise(resolve => { + let lines: string[] = [] + task.onStdout(arr => { + lines.push(...arr) + }) + task.onExit(() => { + resolve(lines) + }) + }) + await task.start({ cmd: '/bin/sh', args: [file] }) + let lines = await p + expect(lines).toEqual(['3', '', '4']) + task.dispose() + }) + + it('should emit stderr event', async () => { + let file = await createTmpFile('console.error("start\\n\\nend");') + let task = workspace.createTask('error') + disposables.push(task) + let p = new Promise(resolve => { + let lines: string[] = [] + task.onStderr(arr => { + lines.push(...arr) + }) + task.onExit(() => { + resolve(lines) + }) + }) + await task.start({ cmd: 'node', args: [file] }) + let lines = await p + expect(lines).toEqual(['start', '', 'end']) + }) + + it('should not receive event from other task', async () => { + let task1 = workspace.createTask('one') + disposables.push(task1) + let count = 0 + let cb = () => { + count++ + } + task1.onExit(cb) + task1.onStderr(cb) + task1.onStdout(cb) + let file = await createTmpFile('console.log("start");console.error("end");') + let task = workspace.createTask('error') + await task.start({ cmd: 'node', args: [file] }) + let promise = new Promise(resolve => { + task.onExit(() => { + resolve(undefined) + }) + }) + await promise + expect(count).toBe(0) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/terminal.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/terminal.test.ts new file mode 100644 index 00000000..9597c8b9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/terminal.test.ts @@ -0,0 +1,53 @@ +import { Neovim } from '@chemzqm/neovim' +import helper from '../helper' +import TerminalModel from '../../model/terminal' + +let nvim: Neovim +let terminal: TerminalModel +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + terminal = new TerminalModel('sh', [], nvim) + await terminal.start(__dirname, { COC_TERMINAL: `option '-term'` }) +}) + +afterAll(async () => { + terminal.dispose() + await helper.shutdown() +}) + +describe('terminal properties', () => { + it('should get name', () => { + let name = terminal.name + expect(name).toBe('sh') + }) + + it('should have correct cwd and env', async () => { + let bufnr = terminal.bufnr + terminal.sendText('echo $PWD') + await helper.wait(300) + let lines = await nvim.call('getbufline', [bufnr, 1, '$']) as string[] + expect(lines[0].trim().length).toBeGreaterThan(0) + terminal.sendText('echo $COC_TERMINAL') + await helper.wait(300) + lines = await nvim.call('getbufline', [bufnr, 1, '$']) as string[] + expect(lines.includes(`option '-term'`)).toBe(true) + }) + + it('should get pid', async () => { + let pid = await terminal.processId + expect(typeof pid).toBe('number') + }) + + it('should hide terminal window', async () => { + await terminal.hide() + let winnr = await nvim.call('bufwinnr', terminal.bufnr) + expect(winnr).toBe(-1) + }) + + it('should show terminal window', async () => { + await terminal.show() + let winnr = await nvim.call('bufwinnr', terminal.bufnr) + expect(winnr != -1).toBe(true) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/util.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/util.test.ts new file mode 100644 index 00000000..98c49275 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/util.test.ts @@ -0,0 +1,1111 @@ +import style from 'ansi-styles' +import * as assert from 'assert' +import { spawn } from 'child_process' +import fs from 'fs' +import path from 'path' +import vm from 'vm' +import { Color, Position, Range, SymbolKind, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { LinesTextDocument } from '../../model/textdocument' +import { concurrent, executable, getKeymapModifier, getUri, isRunning, runCommand, wait, watchFile } from '../../util' +import { ansiparse, parseAnsiHighlights } from '../../util/ansiparse' +import * as arrays from '../../util/array' +import * as color from '../../util/color' +import { getSymbolKind } from '../../util/convert' +import * as diff from '../../util/diff' +import * as factory from '../../util/factory' +import * as fuzzy from '../../util/fuzzy' +import * as fzy from '../../util/fzy' +import * as Is from '../../util/is' +import * as lodash from '../../util/lodash' +import { Mutex } from '../../util/mutex' +import * as objects from '../../util/object' +import * as positions from '../../util/position' +import { terminate } from '../../util/processes' +import { getMatchResult } from '../../util/score' +import * as strings from '../../util/string' +import * as textedits from '../../util/textedit' +import { filter } from '../../util/async' +import helper, { createTmpFile } from '../helper' +const createLogger = require('../../util/logger') + +function createTextDocument(lines: string[]): LinesTextDocument { + return new LinesTextDocument('file://a', 'txt', 1, lines, 1, true) +} + +function toEdit(sl, sc, el, ec, text): TextEdit { + return TextEdit.replace(Range.create(sl, sc, el, ec), text) +} + +describe('factory', () => { + const emptyLogger = { + log: () => {}, + info: () => {}, + error: () => {}, + debug: () => {}, + warn: () => {} + } + + it('should create logger', async () => { + let file = path.join(__dirname, 'sandbox/log.js') + let fn = jest.fn() + const sandbox = factory.createSandbox(file, { + log: () => { + fn() + }, + info: () => { + fn() + }, + error: () => { + fn() + }, + debug: () => { + fn() + }, + warn: () => { + fn() + } + }) + let res = vm.runInContext(` +console.log('log') +console.debug('debug') +console.info('info') +console.error('error') +console.warn('warn')`, sandbox) + expect(fn).toBeCalledTimes(5) + }) + + it('should not throw process.chdir', async () => { + let file = path.join(__dirname, 'sandbox/log.js') + const sandbox = factory.createSandbox(file, emptyLogger) + let res = vm.runInContext(`process.chdir()`, sandbox) + expect(res).toBeUndefined() + }) + + it('should throw with umask', async () => { + let file = path.join(__dirname, 'sandbox/log.js') + const sandbox = factory.createSandbox(file, emptyLogger) + let res = vm.runInContext(`process.umask()`, sandbox) + expect(typeof res).toBe('number') + let err + try { + res = vm.runInContext(`process.umask(18)`, sandbox) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should throw with process.exit', async () => { + let file = path.join(__dirname, 'sandbox/log.js') + const sandbox = factory.createSandbox(file, emptyLogger) + let err + try { + vm.runInContext(`process.exit()`, sandbox) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should hook require', async () => { + let filename = path.join(__dirname, 'sandbox/log.js') + const sandbox = factory.createSandbox(filename, emptyLogger) + let fn = factory.compileInSandbox(sandbox) + let obj: any = {} + fn.apply(obj, [`const {wait} = require('coc.nvim')\nmodule.exports = wait`, filename]) + expect(typeof obj.exports).toBe('function') + }) +}) + +describe('logger', () => { + it('should get log file', async () => { + let val = process.env.NVIM_COC_LOG_FILE + process.env.NVIM_COC_LOG_FILE = '' + let logger = createLogger('') + expect(logger.getLogFile()).toBeDefined() + process.env.XDG_RUNTIME_DIR = '' + expect(logger.getLogFile()).toBeDefined() + process.env.NVIM_COC_LOG_FILE = val + }) +}) + +describe('textedit', () => { + + function createEdit(uri: string): WorkspaceEdit { + let edit = TextEdit.insert(Position.create(0, 0), 'a') + let doc = { uri, version: null } + return { documentChanges: [TextDocumentEdit.create(doc, [edit])] } + } + + function addPosition(position: Position, line: number, character: number): Position { + return Position.create(position.line + line, position.character + character) + } + + test('getChangedPosition', () => { + const assertPosition = (start, edit, arr) => { + let res = textedits.getChangedPosition(start, edit) + expect(res).toEqual(Position.create(arr[0], arr[1])) + } + let pos = Position.create(0, 0) + assertPosition(pos, TextEdit.insert(pos, 'abc'), [0, 3]) + assertPosition(pos, TextEdit.insert(pos, 'a\nb\nc'), [2, 1]) + let edit = TextEdit.replace(Range.create(pos, Position.create(0, 3)), 'abc') + assertPosition(pos, edit, [0, 0]) + pos = Position.create(0, 1) + let r = Range.create(addPosition(pos, 0, -1), pos) + assertPosition(pos, TextEdit.replace(r, 'a\nb\n'), [2, -1]) + pos = Position.create(1, 3) + edit = TextEdit.replace(Range.create(Position.create(0, 1), Position.create(1, 0)), 'abc') + assertPosition(pos, edit, [-1, 4]) + }) + + test('getChangedLineCount', () => { + let pos = Position.create(5, 0) + let edits: TextEdit[] = [ + TextEdit.replace(Range.create(0, 1, 1, 0), ''), + TextEdit.replace(Range.create(2, 1, 3, 0), ''), + TextEdit.replace(Range.create(10, 1, 12, 0), 'foo'), + ] + expect(textedits.getChangedLineCount(pos, edits)).toBe(-2) + }) + + test('getPosition', () => { + let pos = Position.create(1, 3) + const assertChange = (rl, rc, el, ec, text, val): void => { + let edit = TextEdit.replace(Range.create(rl, rc, el, ec), text) + let res = textedits.getPosition(pos, edit) + expect(res).toEqual(val) + } + assertChange(0, 1, 1, 0, 'abc', Position.create(0, 7)) + assertChange(0, 1, 1, 1, 'abc', Position.create(0, 6)) + assertChange(0, 1, 1, 0, 'abc\n', Position.create(1, 3)) + assertChange(1, 1, 1, 2, '', Position.create(1, 2)) + }) + + test('getPositionFromEdits', async () => { + const assertEdits = (pos, edits, exp: [number, number]) => { + let res = textedits.getPositionFromEdits(pos, edits) + expect(res).toEqual(Position.create(exp[0], exp[1])) + } + let pos = Position.create(5, 1) + let edits: TextEdit[] = [ + TextEdit.replace(Range.create(0, 3, 1, 0), ''), + TextEdit.replace(Range.create(2, 4, 3, 0), ''), + TextEdit.replace(Range.create(3, 4, 4, 0), ''), + TextEdit.replace(Range.create(4, 1, 5, 0), ''), + TextEdit.replace(Range.create(6, 1, 6, 1), 'foo'), + ] + assertEdits(pos, edits, [1, 10]) + }) + + it('should check empty workspaceEdit', async () => { + let workspaceEdit: WorkspaceEdit = createEdit('untitled:/1') + expect(textedits.emptyWorkspaceEdit(workspaceEdit)).toBe(false) + expect(textedits.emptyWorkspaceEdit({ documentChanges: [] })).toBe(true) + }) + + it('should check empty TextEdit', async () => { + expect(textedits.emptyTextEdit(TextEdit.insert(Position.create(0, 0), ''))).toBe(true) + expect(textedits.emptyTextEdit(TextEdit.insert(Position.create(0, 0), 'a'))).toBe(false) + }) + + it('should get well formed edit', async () => { + let r = Range.create(1, 0, 0, 0) + let edit: TextEdit = { range: r, newText: 'foo' } + let res = textedits.getWellformedEdit(edit) + expect(res.range).toEqual(Range.create(0, 0, 1, 0)) + }) + + it('should check line count change', async () => { + let r = Range.create(0, 0, 0, 5) + let edit: TextEdit = { range: r, newText: 'foo' } + expect(textedits.lineCountChange(edit)).toBe(0) + edit = { range: Range.create(0, 0, 1, 0), newText: 'foo' } + expect(textedits.lineCountChange(edit)).toBe(-1) + }) + + it('should filter and sort textedits', async () => { + let doc = createTextDocument(['foo']) + expect(textedits.filterSortEdits(doc, [TextEdit.insert(Position.create(0, 0), 'a\r\nb')])).toEqual([ + TextEdit.insert(Position.create(0, 0), 'a\nb') + ]) + expect(textedits.filterSortEdits(doc, [TextEdit.replace(Range.create(0, 0, 0, 3), 'foo')])).toEqual([]) + expect(textedits.filterSortEdits(doc, [ + TextEdit.insert(Position.create(0, 1), 'b'), + TextEdit.insert(Position.create(0, 0), 'a'), + ])).toEqual([ + TextEdit.insert(Position.create(0, 0), 'a'), + TextEdit.insert(Position.create(0, 1), 'b'), + ]) + }) + + it('should merge textedits #1', async () => { + let edits = [toEdit(0, 0, 0, 0, 'foo'), toEdit(0, 1, 0, 1, 'bar')] + let lines = ['ab'] + let res = textedits.mergeTextEdits(edits, lines, ['fooabarb']) + expect(res).toEqual(toEdit(0, 0, 0, 1, 'fooabar')) + }) + + it('should merge textedits #2', async () => { + let edits = [toEdit(0, 0, 1, 0, 'foo\n')] + let lines = ['bar'] + let res = textedits.mergeTextEdits(edits, lines, ['foo']) + expect(res).toEqual(toEdit(0, 0, 1, 0, 'foo\n')) + }) + + it('should merge textedits #3', async () => { + let edits = [toEdit(0, 0, 0, 1, 'd'), toEdit(1, 0, 1, 1, 'e'), toEdit(2, 0, 3, 0, 'f\n')] + let lines = ['a', 'b', 'c'] + let res = textedits.mergeTextEdits(edits, lines, ['d', 'e', 'f']) + expect(res).toEqual(toEdit(0, 0, 3, 0, 'd\ne\nf\n')) + }) +}) + +describe('strings', () => { + it('should get case', async () => { + expect(strings.getCase('a'.charCodeAt(0))).toBe(1) + expect(strings.getCase('A'.charCodeAt(0))).toBe(2) + expect(strings.getCase('#'.charCodeAt(0))).toBe(0) + }) + + it('should get next word code', async () => { + function assertNext(text: string, index: number, res: [number, string] | undefined): void { + let arr = res === undefined ? undefined : [res[0], res[1].charCodeAt(0)] + let result = strings.getNextWord(fuzzy.getCharCodes(text), index) + expect(result).toEqual(arr) + } + assertNext('abc', 0, [0, 'a']) + assertNext('abc', 1, undefined) + assertNext('abC', 1, [2, 'C']) + }) + + it('should get character indexes', async () => { + expect(strings.getCharIndexes('abaca', 'a')).toEqual([0, 2, 4]) + expect(strings.getCharIndexes('abd', 'f')).toEqual([]) + }) + + it('should convert to lines', async () => { + expect(strings.contentToLines('foo', false)).toEqual(['foo']) + expect(strings.contentToLines('foo\n', true)).toEqual(['foo']) + }) + + it('should get parts', async () => { + let res = strings.rangeParts('foo bar', Range.create(0, 0, 0, 4)) + expect(res).toEqual(['', 'bar']) + res = strings.rangeParts('foo\nbar', Range.create(0, 1, 1, 1)) + expect(res).toEqual(['f', 'ar']) + res = strings.rangeParts('x\nfoo\nbar\ny', Range.create(0, 1, 2, 3)) + expect(res).toEqual(['x', '\ny']) + res = strings.rangeParts('foo\nbar', Range.create(1, 0, 1, 1)) + expect(res).toEqual(['foo\n', 'ar']) + }) + + it('should equalsIgnoreCase', () => { + expect(strings.equalsIgnoreCase('', '')).toBe(true) + expect(!strings.equalsIgnoreCase('', '1')).toBe(true) + expect(!strings.equalsIgnoreCase('1', '')).toBe(true) + expect(strings.equalsIgnoreCase('a', 'a')).toBe(true) + expect(strings.equalsIgnoreCase('abc', 'Abc')).toBe(true) + expect(strings.equalsIgnoreCase('abc', 'ABC')).toBe(true) + expect(strings.equalsIgnoreCase('Höhenmeter', 'HÖhenmeter')).toBe(true) + expect(strings.equalsIgnoreCase('ÖL', 'Öl')).toBe(true) + }) + + it('should check isWord', async () => { + expect(strings.isWord('_')).toBe(true) + expect(strings.isWord('0')).toBe(true) + }) + + it('should find index', () => { + expect(strings.indexOf('a,b,c', ',', 2)).toBe(3) + expect(strings.indexOf('a,b,c', ',', 1)).toBe(1) + expect(strings.indexOf('a,b,c', 't', 1)).toBe(-1) + }) + + it('should upperFirst', async () => { + expect(strings.upperFirst('')).toBe('') + expect(strings.upperFirst('abC')).toBe('AbC') + }) +}) + +describe('getSymbolKind()', () => { + it('should get symbol kind', async () => { + for (let i = 1; i <= 27; i++) { + expect(getSymbolKind(i as SymbolKind)).toBeDefined() + } + }) +}) + +describe('Is', () => { + it('should check array', async () => { + expect(Is.array(false)).toBe(false) + }) + + it('should check empty object', async () => { + expect(Is.emptyObject(false)).toBe(false) + expect(Is.emptyObject({})).toBe(true) + expect(Is.emptyObject({ x: 1 })).toBe(false) + }) + + it('should check typed array', async () => { + let arr = new Array(10) + arr.fill(1) + expect(Is.typedArray(arr, v => { + return v >= 0 + })).toBe(true) + }) +}) + +describe('lodash', () => { + it('should set defaults', async () => { + let res = lodash.defaults({ a: 1 }, { b: 2 }, { a: 3 }, null) + expect(res).toEqual({ a: 1, b: 2 }) + }) +}) + +describe('color', () => { + it('should check dark color', async () => { + expect(color.isDark(Color.create(0.03, 0.01, 0.01, 0))).toBe(true) + }) +}) + +describe('parseAnsiHighlights', () => { + function testColorHighlight(highlight: string, hlGroup: string, markdown = true) { + let text = `${style[highlight].open}text${style[highlight].close}` + let res = parseAnsiHighlights(text, markdown) + expect(res.highlights.length).toBeGreaterThan(0) + let o = res.highlights.find(o => o.hlGroup == hlGroup) + expect(o).toBeDefined() + } + + it('should parse foreground color', async () => { + testColorHighlight('yellow', 'CocMarkdownCode') + testColorHighlight('blue', 'CocMarkdownLink') + testColorHighlight('magenta', 'CocMarkdownHeader') + testColorHighlight('green', 'CocListFgGreen') + testColorHighlight('green', 'CocListFgGreen', false) + }) + + it('should parse background color', async () => { + let text = `${style.bgRed.open}text${style.bgRed.close}` + let res = parseAnsiHighlights(text, false) + expect(res.highlights.length).toBeGreaterThan(0) + expect(res.highlights[0].hlGroup).toBe('CocListBgRed') + }) + + it('should parse foreground and background', async () => { + let text = `${style.bgRed.open}${style.blue.open}text${style.blue.close}${style.bgRed.close}` + let res = parseAnsiHighlights(text, true) + expect(res.highlights.length).toBeGreaterThan(0) + expect(res.highlights[0].hlGroup).toBe('CocListBlueRed') + }) + + it('should erase char', async () => { + let text = `foo\u0008bar` + let res = parseAnsiHighlights(text, true) + expect(res.line).toBe('fobar') + text = `${style.bgRed.open}foo${style.bgRed.close}\u0008bar` + res = parseAnsiHighlights(text, true) + expect(res.line).toBe('fobar') + text = `${style.bgRed.open}f${style.bgRed.close}\u0008bar` + res = parseAnsiHighlights(text, true) + expect(res.line).toBe('bar') + }) + + it('should not throw for bad control character', async () => { + let text = '\x1bafoo' + let res = parseAnsiHighlights(text) + expect(res.line).toBeDefined() + text = '\x1b[33;44mabc\x1b[33,44m' + res = parseAnsiHighlights(text) + expect(res.line).toBe('abc') + }) +}) + +describe('Arrays', () => { + + it('distinct()', () => { + function compare(a: string): string { + return a + } + + assert.deepStrictEqual(arrays.distinct(['32', '4', '5'], compare), ['32', '4', '5']) + assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '4'], compare), ['32', '4', '5']) + assert.deepStrictEqual(arrays.distinct(['32', 'constructor', '5', '1'], compare), ['32', 'constructor', '5', '1']) + assert.deepStrictEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), ['32', 'constructor', 'proto']) + assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5']) + }) + + it('tail()', () => { + assert.strictEqual(arrays.tail([1, 2, 3]), 3) + }) + + it('intersect()', () => { + assert.ok(!arrays.intersect([1, 2, 3], [4, 5])) + }) + + it('group()', () => { + let res = arrays.group([1, 2, 3, 4, 5], 3) + assert.deepStrictEqual(res, [[1, 2, 3], [4, 5]]) + }) + + it('groupBy()', () => { + let res = arrays.groupBy([0, 0, 3, 4], v => v != 0) + assert.deepStrictEqual(res, [[3, 4], [0, 0]]) + }) + + it('lastIndex()', () => { + let res = arrays.lastIndex([1, 2, 3], x => x < 3) + assert.strictEqual(res, 1) + }) + + it('flatMap()', () => { + let objs: { [key: string]: number[] }[] = [{ x: [1, 2] }, { y: [3, 4] }, { z: [5, 6] }] + function values(item: { [key: string]: number[] }): number[] { + return Object.keys(item).reduce((p, c) => p.concat(item[c]), []) + } + let res = arrays.flatMap(objs, values) + assert.deepStrictEqual(res, [1, 2, 3, 4, 5, 6]) + }) + + it('addSortedArray()', () => { + expect(arrays.addSortedArray('a', ['d', 'e'])).toEqual(['a', 'd', 'e']) + expect(arrays.addSortedArray('f', ['d', 'e'])).toEqual(['d', 'e', 'f']) + expect(arrays.addSortedArray('d', ['d', 'e'])).toEqual(['d', 'e']) + expect(arrays.addSortedArray('e', ['d', 'f'])).toEqual(['d', 'e', 'f']) + }) +}) + +describe('Position', () => { + function addPosition(position: Position, line: number, character: number): Position { + return Position.create(position.line + line, position.character + character) + } + + test('samePosition', () => { + let pos = Position.create(0, 0) + expect(positions.samePosition(pos, Position.create(0, 0))).toBe(true) + }) + + test('rangeInRange', () => { + let pos = Position.create(0, 0) + let r = Range.create(pos, pos) + expect(positions.rangeInRange(r, r)).toBe(true) + expect(positions.rangeInRange(r, Range.create(addPosition(pos, 1, 0), pos))).toBe(false) + expect(positions.rangeInRange(Range.create(0, 1, 0, 1), Range.create(0, 0, 0, 1))).toBe(true) + }) + + test('rangeOverlap', () => { + let r = Range.create(0, 0, 0, 0) + expect(positions.rangeOverlap(r, Range.create(0, 0, 0, 0))).toBe(false) + expect(positions.rangeOverlap(Range.create(0, 0, 0, 10), Range.create(0, 1, 0, 2))).toBe(true) + expect(positions.rangeOverlap(Range.create(0, 0, 0, 1), Range.create(0, 1, 0, 2))).toBe(false) + expect(positions.rangeOverlap(Range.create(0, 1, 0, 2), Range.create(0, 0, 0, 1))).toBe(false) + expect(positions.rangeOverlap(Range.create(0, 0, 0, 1), Range.create(0, 2, 0, 3))).toBe(false) + }) + + test('rangeAdjacent', () => { + let r = Range.create(1, 1, 1, 2) + expect(positions.rangeAdjacent(r, Range.create(0, 0, 0, 0))).toBe(false) + expect(positions.rangeAdjacent(r, Range.create(1, 1, 1, 3))).toBe(false) + expect(positions.rangeAdjacent(r, Range.create(0, 0, 1, 1))).toBe(true) + expect(positions.rangeAdjacent(r, Range.create(1, 2, 1, 4))).toBe(true) + }) + + test('positionInRange', () => { + let pos = Position.create(0, 0) + let r = Range.create(pos, pos) + expect(positions.positionInRange(pos, r)).toBe(0) + }) + + test('comparePosition', () => { + let pos = Position.create(0, 0) + expect(positions.comparePosition(pos, pos)).toBe(0) + }) + + test('should get start end position by content', () => { + expect(positions.getEnd(Position.create(0, 0), 'foo')).toEqual({ line: 0, character: 3 }) + expect(positions.getEnd(Position.create(0, 1), 'foo\nbar')).toEqual({ line: 1, character: 3 }) + }) + + test('isSingleLine', () => { + let pos = Position.create(0, 0) + let r = Range.create(pos, pos) + expect(positions.isSingleLine(r)).toBe(true) + }) + + test('toValidRange', () => { + expect(positions.toValidRange(Range.create(1, 0, 0, 1))).toEqual(Range.create(0, 1, 1, 0)) + expect(positions.toValidRange({ + start: { line: -1, character: -1 }, + end: { line: -1, character: -1 }, + })).toEqual(Range.create(0, 0, 0, 0)) + }) + +}) + +describe('match result', () => { + it('should match empty text', async () => { + expect(getMatchResult('', 'foo')).toEqual({ score: 0 }) + }) + + it('should match empty query', async () => { + expect(getMatchResult('foo', '')).toEqual({ score: 1 }) + }) + + it('should respect filename #1', () => { + let res = getMatchResult('/coc.nvim/coc.txt', 'coc', 'coc.txt') + expect(res).toEqual({ score: 4, matches: [10, 11, 12] }) + }) + + it('should respect filename #2', () => { + let res = getMatchResult('/coc.nvim/Coc.txt', 'coc', 'Coc.txt') + expect(res).toEqual({ score: 3.5, matches: [10, 11, 12] }) + }) + + it('should respect filename #3', () => { + let res = getMatchResult('/coc.nvim/cdoxc.txt', 'coc', 'cdoxc.txt') + expect(res).toEqual({ score: 3, matches: [10, 12, 14] }) + }) + + it('should respect filename #4', () => { + let res = getMatchResult('/coc.nvim/fileName.txt', 'namt', 'fileName.txt') + expect(res).toEqual({ score: 3.5, matches: [14, 15, 16, 19] }) + }) + + it('should respect path start', () => { + let res = getMatchResult('/foob/baxr/xyz', 'fbx') + expect(res).toEqual({ score: 3, matches: [1, 6, 11] }) + }) + + it('should find fuzzy result', () => { + let res = getMatchResult('foobarzyx', 'fbx') + expect(res).toEqual({ score: 2, matches: [0, 3, 8] }) + }) + + it('should find fuzzy result #1', () => { + let res = getMatchResult('LICENSES/preferred/MIT', 'lsit') + expect(res).toEqual({ score: 1.4, matches: [0, 5, 20, 21] }) + expect(getMatchResult('foo', 'Fo')).toEqual({ score: 1.5, matches: [0, 1] }) + }) + + it('should find fuzzy result #2', async () => { + let res = getMatchResult('_api', 'AP') + expect(res).toEqual({ score: 0.8, matches: [1, 2] }) + res = getMatchResult('_api', 'API') + expect(res).toEqual({ score: 1.3, matches: [1, 2, 3] }) + }) +}) + +describe('utility', () => { + + it('should not throw for invalid ms', async () => { + await wait(-1) + }) + + it('should get uri for unknown buftype', async () => { + let res = getUri('foo', 3, '', false) + expect(res).toBe('unknown:3') + }) + + it('should watch file', async () => { + let filepath = await createTmpFile('my file') + let called = false + let disposable = watchFile(filepath, () => { + called = true + }) + await wait(10) + fs.writeFileSync(filepath, 'new file', 'utf8') + await helper.waitValue(() => { + return called + }, true) + disposable.dispose() + }) + + it('should check executable', async () => { + let res = executable('command_not_exists') + expect(res).toBe(false) + }) + + it('should check isRunning', async () => { + expect(isRunning(process.pid)).toBe(true) + }) + + it('should run command with timeout', async () => { + let err + try { + await runCommand('sleep 2', { cwd: __dirname }, 0.01) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should throw on command error', async () => { + let err + try { + await runCommand('command_not_exists', { cwd: __dirname }) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should resolve concurrent with empty task', async () => { + let fn = jest.fn() + await concurrent([], fn, 3) + expect(fn).toBeCalledTimes(0) + }) + + it('should run concurrent', async () => { + let res: number[] = [] + let fn = (n: number): Promise => { + return new Promise(resolve => { + setTimeout(() => { + res.push(n) + resolve() + }, n * 10) + }) + } + let arr = [5, 4, 3, 6, 8] + let ts = Date.now() + await concurrent(arr, fn, 3) + let dt = Date.now() - ts + expect(dt).toBeGreaterThanOrEqual(100) + expect(res).toEqual([3, 4, 5, 6, 8]) + }) + + it('should getKeymapModifier', async () => { + expect(getKeymapModifier('i')).toBe('') + expect(getKeymapModifier('s')).toBe('') + expect(getKeymapModifier('x')).toBe('') + expect(getKeymapModifier('t' as any)).toBe('') + }) +}) + +describe('score test', () => { + + it('fzy#score', async () => { + let a = fzy.score("amuser", "app/models/user.rb") + let b = fzy.score("amuser", "app/models/customer.rb") + expect(a).toBeGreaterThan(b) + }) + + it('fzy#positions', async () => { + let arr = fzy.positions("amuser", "app/models/user.rb") + expect(arr).toEqual([0, 4, 11, 12, 13, 14]) + }) + + it('fzy#groupPositions', async () => { + let arr = fzy.groupPositions([1, 2, 3, 6, 7, 10]) + expect(arr).toEqual([[1, 4], [6, 8], [10, 11]]) + }) +}) + +describe('fuzzy match test', () => { + it('should be fuzzy match', () => { + let needle = 'aBc' + let codes = fuzzy.getCharCodes(needle) + expect(fuzzy.fuzzyMatch(codes, 'abc')).toBeFalsy + expect(fuzzy.fuzzyMatch(codes, 'ab')).toBeFalsy + expect(fuzzy.fuzzyMatch(codes, 'addbdd')).toBeFalsy + expect(fuzzy.fuzzyMatch(codes, 'abbbBc')).toBeTruthy + expect(fuzzy.fuzzyMatch(codes, 'daBc')).toBeTruthy + expect(fuzzy.fuzzyMatch(codes, 'ABCz')).toBeTruthy + }) + + it('should be fuzzy for character', () => { + expect(fuzzy.fuzzyChar('a', 'a')).toBeTruthy + expect(fuzzy.fuzzyChar('a', 'A')).toBeTruthy + expect(fuzzy.fuzzyChar('z', 'z')).toBeTruthy + expect(fuzzy.fuzzyChar('z', 'Z')).toBeTruthy + expect(fuzzy.fuzzyChar('A', 'a')).toBeFalsy + expect(fuzzy.fuzzyChar('A', 'A')).toBeTruthy + expect(fuzzy.fuzzyChar('Z', 'z')).toBeFalsy + expect(fuzzy.fuzzyChar('Z', 'Z')).toBeTruthy + }) +}) + +describe('object test', () => { + it('mixin should recursive', () => { + let res = objects.mixin({ a: { b: 1 } }, { a: { c: 2 }, d: 3 }) + expect(res.a.b).toBe(1) + expect(res.a.c).toBe(2) + expect(res.d).toBe(3) + res = objects.mixin({}, true) + expect(res).toEqual({}) + res = objects.mixin({ x: 1 }, { x: 2 }, false) + expect(res).toEqual({ x: 1 }) + }) + + it('should deep clone', async () => { + let re = new RegExp('a', 'g') + expect(objects.deepClone(re)).toBe(re) + }) + + it('should not deep freeze', async () => { + objects.deepFreeze(false) + objects.deepFreeze(true) + }) + + it('should check equals', async () => { + expect(objects.equals(false, 1)).toBe(false) + expect(objects.equals([1], {})).toBe(false) + expect(objects.equals([1, 2], [1, 3])).toBe(false) + }) + + it('should check empty object', async () => { + expect(objects.isEmpty({})).toBe(true) + expect(objects.isEmpty([])).toBe(true) + expect(objects.isEmpty(null)).toBe(true) + expect(objects.isEmpty({ x: 1 })).toBe(false) + }) +}) + +describe('ansiparse', () => { + it('ansiparse #1', () => { + let str = '\u001b[33mText\u001b[mnormal' + let res = ansiparse(str) + expect(res).toEqual([{ + foreground: 'yellow', text: 'Text' + }, { + text: 'normal' + }]) + }) + + it('ansiparse #2', () => { + let str = '\u001b[33m\u001b[mText' + let res = ansiparse(str) + expect(res).toEqual([ + { foreground: 'yellow', text: '' }, + { text: 'Text' }]) + }) + + it('ansiparse #3', () => { + let str = 'this.\u001b[0m\u001b[31m\u001b[1mhistory\u001b[0m.add()' + let res = ansiparse(str) + expect(res[1]).toEqual({ + foreground: 'red', + bold: true, text: 'history' + }) + }) +}) + +describe('Mutex', () => { + it('mutex run in serial', async () => { + let lastTs: number + let fn = () => new Promise(resolve => { + if (lastTs) { + let dt = Date.now() - lastTs + expect(dt).toBeGreaterThanOrEqual(2) + } + lastTs = Date.now() + setTimeout(() => { + resolve() + }, 3) + }) + let mutex = new Mutex() + await Promise.all([ + mutex.use(fn), + mutex.use(fn), + mutex.use(fn) + ]) + }) + + it('mutex run after job finish', async () => { + let count = 0 + let fn = () => new Promise(resolve => { + count = count + 1 + setTimeout(() => { + resolve() + }, 10) + }) + let mutex = new Mutex() + await mutex.use(fn) + await helper.wait(1) + await mutex.use(fn) + expect(count).toBe(2) + }) + + it('should release on reject', async () => { + let mutex = new Mutex() + let err + try { + await mutex.use(() => { + return Promise.reject(new Error('err')) + }) + } catch (e) { + err = e + } + expect(err).toBeDefined() + expect(mutex.busy).toBe(false) + }) +}) + +describe('terminate', () => { + it('should terminate process', async () => { + let cwd = process.cwd() + let child = spawn('sleep', ['10'], { cwd, detached: true }) + let res = terminate(child, cwd) + await helper.wait(60) + expect(res).toBe(true) + expect(child.connected).toBe(false) + terminate(child, cwd) + }) +}) + +describe('diff', () => { + describe('diff lines', () => { + function diffLines(oldStr: string, newStr: string): diff.ChangedLines { + let oldLines = oldStr.split('\n') + return diff.diffLines(oldLines, newStr.split('\n'), oldLines.length - 2) + } + + it('should get textedit without cursor', () => { + let res = diff.getTextEdit(['a', 'b'], ['a', 'b']) + expect(res).toBeUndefined() + res = diff.getTextEdit(['a', 'b'], ['a', 'b'], Position.create(0, 0)) + expect(res).toBeUndefined() + res = diff.getTextEdit(['a', 'b'], ['a', 'b', 'c']) + expect(res).toEqual(toEdit(2, 0, 2, 0, 'c\n')) + res = diff.getTextEdit(['a', 'b', 'c'], ['a']) + expect(res).toEqual(toEdit(1, 0, 3, 0, '')) + res = diff.getTextEdit(['a', 'b'], ['a', 'd']) + expect(res).toEqual(toEdit(1, 0, 2, 0, 'd\n')) + res = diff.getTextEdit(['a', 'b'], ['a', 'd', 'e']) + expect(res).toEqual(toEdit(1, 0, 2, 0, 'd\ne\n')) + res = diff.getTextEdit(['a', 'b', 'e'], ['a', 'd', 'e']) + expect(res).toEqual(toEdit(1, 0, 2, 0, 'd\n')) + res = diff.getTextEdit(['a', 'b', 'e'], ['e']) + expect(res).toEqual(toEdit(0, 0, 2, 0, '')) + res = diff.getTextEdit(['a', 'b', 'e'], ['d', 'c', 'a', 'b', 'e']) + expect(res).toEqual(toEdit(0, 0, 0, 0, 'd\nc\n')) + res = diff.getTextEdit(['a', 'b'], ['a', 'b', '']) + expect(res).toEqual(toEdit(2, 0, 2, 0, '\n')) + res = diff.getTextEdit(['a', 'b'], ['a', 'b', '', '']) + expect(res).toEqual(toEdit(2, 0, 2, 0, '\n\n')) + }) + + it('should get textedit for single line change', async () => { + let res = diff.getTextEdit(['foo', 'c'], ['', 'c'], Position.create(0, 0), false) + expect(res).toEqual(toEdit(0, 0, 0, 3, '')) + res = diff.getTextEdit([''], ['foo'], Position.create(0, 0), false) + expect(res).toEqual(toEdit(0, 0, 0, 0, 'foo')) + res = diff.getTextEdit(['foo bar'], ['foo r'], Position.create(0, 4), false) + expect(res).toEqual(toEdit(0, 4, 0, 6, '')) + res = diff.getTextEdit(['f'], ['foo f'], Position.create(0, 0), false) + expect(res).toEqual(toEdit(0, 0, 0, 0, 'foo ')) + res = diff.getTextEdit([' foo '], [' bar '], Position.create(0, 0), false) + expect(res).toEqual(toEdit(0, 1, 0, 4, 'bar')) + res = diff.getTextEdit(['foo'], ['bar'], Position.create(0, 0), true) + expect(res).toEqual(toEdit(0, 0, 0, 3, 'bar')) + res = diff.getTextEdit(['aa'], ['aaaa'], Position.create(0, 1), true) + expect(res).toEqual(toEdit(0, 0, 0, 0, 'aa')) + }) + + it('should diff changed lines', () => { + let res = diffLines('a\n', 'b\n') + expect(res).toEqual({ start: 0, end: 1, replacement: ['b'] }) + }) + + it('should diff added lines', () => { + let res = diffLines('a\n', 'a\nb\n') + expect(res).toEqual({ + start: 1, + end: 1, + replacement: ['b'] + }) + }) + + it('should diff remove lines', () => { + let res = diffLines('a\n\n', 'a\n') + expect(res).toEqual({ + start: 1, + end: 2, + replacement: [] + }) + }) + + it('should diff remove multiple lines', () => { + let res = diffLines('a\n\n\n', 'a\n') + expect(res).toEqual({ + start: 1, + end: 3, + replacement: [] + }) + }) + + it('should diff removed line', () => { + let res = diffLines('a\n\n\nb', 'a\n\nb') + expect(res).toEqual({ + start: 2, + end: 3, + replacement: [] + }) + }) + + it('should reduce changed lines', async () => { + let res = diff.diffLines(['a', 'b', 'c'], ['a', 'b', 'c', 'd'], 0) + expect(res).toEqual({ + start: 3, + end: 3, + replacement: ['d'] + }) + }) + }) + + describe('patch line', () => { + it('should patch line', () => { + let res = diff.patchLine('foo', 'bar foo bar') + expect(res.length).toBe(7) + expect(res).toBe(' foo') + }) + }) + + describe('should get text edits', () => { + + function applyEdits(oldStr: string, newStr: string): void { + let doc = TextDocument.create('untitled://1', 'markdown', 0, oldStr) + let change = diff.getChange(doc.getText(), newStr) + let start = doc.positionAt(change.start) + let end = doc.positionAt(change.end) + let edit: TextEdit = { + range: { start, end }, + newText: change.newText + } + let res = TextDocument.applyEdits(doc, [edit]) + expect(res).toBe(newStr) + } + + it('should get diff for comments ', async () => { + let oldStr = '/*\n *\n * \n' + let newStr = '/*\n *\n *\n * \n' + let doc = TextDocument.create('untitled://1', 'markdown', 0, oldStr) + let change = diff.getChange(doc.getText(), newStr, 1) + let start = doc.positionAt(change.start) + let end = doc.positionAt(change.end) + let edit: TextEdit = { + range: { start, end }, + newText: change.newText + } + let res = TextDocument.applyEdits(doc, [edit]) + expect(res).toBe(newStr) + }) + + it('should return null for same content', () => { + let change = diff.getChange('', '') + expect(change).toBeNull() + change = diff.getChange('abc', 'abc') + expect(change).toBeNull() + }) + + it('should get diff for added', () => { + applyEdits('1\n2', '1\n2\n3\n4') + }) + + it('should get diff for added #0', () => { + applyEdits('\n\n', '\n\n\n') + }) + + it('should get diff for added #1', () => { + applyEdits('1\n2\n3', '5\n1\n2\n3') + }) + + it('should get diff for added #2', () => { + applyEdits('1\n2\n3', '1\n2\n4\n3') + }) + + it('should get diff for added #3', () => { + applyEdits('1\n2\n3', '4\n1\n2\n3\n5') + }) + + it('should get diff for added #4', () => { + applyEdits(' ', ' ') + }) + + it('should get diff for replace', () => { + applyEdits('1\n2\n3\n4\n5', '1\n5\n3\n6\n7') + }) + + it('should get diff for replace #1', () => { + applyEdits('1\n2\n3\n4\n5', '1\n5\n3\n6\n7') + }) + + it('should get diff for remove #0', () => { + applyEdits('1\n2\n3\n4', '1\n4') + }) + + it('should get diff for remove #1', () => { + applyEdits('1\n2\n3\n4', '1') + }) + + it('should get diff for remove #2', () => { + applyEdits(' ', ' ') + }) + + it('should prefer cursor position for change', async () => { + let res = diff.getChange(' int n', ' n', 0) + expect(res).toEqual({ start: 1, end: 5, newText: '' }) + res = diff.getChange(' int n', ' n') + expect(res).toEqual({ start: 0, end: 4, newText: '' }) + }) + + it('should prefer next line for change', async () => { + let res = diff.getChange('a\nb', 'a\nc\nb') + expect(res).toEqual({ start: 2, end: 2, newText: 'c\n' }) + applyEdits('a\nb', 'a\nc\nb') + }) + + it('should prefer previous line for change', async () => { + let res = diff.getChange('\n\na', '\na') + expect(res).toEqual({ start: 0, end: 1, newText: '' }) + }) + + it('should consider cursor', () => { + let res = diff.getChange('\n\n\n', '\n\n\n\n', 1) + expect(res).toEqual({ start: 2, end: 2, newText: '\n' }) + }) + + it('should get minimal diff', () => { + let res = diff.getChange('foo\nbar', 'fab\nbar', 2) + expect(res).toEqual({ start: 1, end: 3, newText: 'ab' }) + }) + }) + + function blockMilliseconds(ms: number): void { + let ts = Date.now() + let i = 0 + // eslint-disable-next-line no-constant-condition + while (true) { + if (Date.now() - ts > ms) { + break + } + i++ + } + } + + describe('async', () => { + it('should do async filter', async () => { + await filter([{ label: 'a' }, { label: 'b' }, { label: 'c' }], v => { + return { code: v.label.charCodeAt(0) } + }, (items, done) => { + expect(items.length).toBe(3) + expect(done).toBe(true) + }) + let n = 0 + let res: string[] = [] + let finished: boolean + await filter(['a', 'b', 'c'], () => { + blockMilliseconds(30) + return true + }, (items, done) => { + n++ + res.push(...items) + finished = done + }) + expect(n).toBe(3) + expect(res).toEqual(['a', 'b', 'c']) + expect(finished).toEqual(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/window.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/window.test.ts new file mode 100644 index 00000000..3e59338e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/window.test.ts @@ -0,0 +1,722 @@ +import { Buffer, Neovim } from '@chemzqm/neovim' +import { HighlightItem } from '@chemzqm/neovim/lib/api/Buffer' +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { Disposable, Emitter } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import commands from '../../commands' +import events from '../../events' +import languages from '../../languages' +import { TreeItem, TreeItemCollapsibleState } from '../../tree' +import { MessageLevel } from '../../types' +import { disposeAll } from '../../util' +import window from '../../window' +import workspace from '../../workspace' +import extensions from '../../extensions' +import Notification from '../../model/notification' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] + +interface FileNode { + filepath: string + isFolder?: boolean +} + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +beforeEach(() => { + helper.updateConfiguration('coc.preferences.enableMessageDialog', true) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('window', () => { + describe('functions', () => { + it('should get offset', async () => { + let buf = await nvim.buffer + await nvim.call('setline', [buf.id, ['bar', 'foo']]) + await nvim.call('cursor', [2, 2]) + let n = await window.getOffset() + expect(n).toBe(5) + }) + + it('should selected range', async () => { + await nvim.setLine('foobar') + await nvim.command('normal! viw') + await nvim.eval(`feedkeys("\\", 'in')`) + let range = await window.getSelectedRange('v') + expect(range).toEqual({ start: { line: 0, character: 0 }, end: { line: 0, character: 6 } }) + }) + + it('should run terminal command', async () => { + let res = await window.runTerminalCommand('ls', __dirname) + expect(res.success).toBe(true) + }) + + it('should open temimal buffer', async () => { + let bufnr = await window.openTerminal('ls', { autoclose: false, keepfocus: false }) + let curr = await nvim.eval('bufnr("%")') + expect(curr).toBe(bufnr) + let buftype = await nvim.eval('&buftype') + expect(buftype).toBe('terminal') + }) + + it('should create outputChannel', () => { + let channel = window.createOutputChannel('channel') + expect(channel.name).toBe('channel') + }) + + it('should create TreeView instance', async () => { + let emitter = new Emitter() + let removed = false + let treeView = window.createTreeView('files', { + treeDataProvider: { + onDidChangeTreeData: emitter.event, + getChildren: root => { + if (root) return undefined + if (removed) return [{ filepath: '/foo/a', isFolder: true }] + return [{ filepath: '/foo/a', isFolder: true }, { filepath: '/foo/b.js' }] + }, + getTreeItem: (node: FileNode) => { + let { filepath, isFolder } = node + return new TreeItem(URI.file(filepath), isFolder ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None) + }, + } + }) + disposables.push(emitter) + disposables.push(treeView) + await treeView.show() + let filetype = await nvim.eval('&filetype') + expect(filetype).toBe('coctree') + }) + + it('should show outputChannel', async () => { + window.createOutputChannel('channel') + window.showOutputChannel('channel') + let buf = await nvim.buffer + let name = await buf.name + expect(name).toMatch('channel') + }) + + it('should not show none exists channel', async () => { + let buf = await nvim.buffer + let bufnr = buf.id + window.showOutputChannel('NONE') + await helper.wait(20) + buf = await nvim.buffer + expect(buf.id).toBe(bufnr) + }) + + it('should get cursor position', async () => { + await nvim.setLine(' ') + await nvim.call('cursor', [1, 3]) + let pos = await window.getCursorPosition() + expect(pos).toEqual({ + line: 0, + character: 2 + }) + }) + + it('should moveTo position in insert mode', async () => { + await nvim.setLine('foo') + await nvim.input('i') + await window.moveTo({ line: 0, character: 3 }) + let col = await nvim.call('col', '.') + expect(col).toBe(4) + let virtualedit = await nvim.getOption('virtualedit') + expect(virtualedit).toBe('') + }) + + it('should choose quickpick', async () => { + let p = window.showQuickpick(['a', 'b']) + await helper.wait(50) + await nvim.input('1') + await nvim.input('') + let res = await p + expect(res).toBe(0) + }) + + it('should cancel quickpick', async () => { + let p = window.showQuickpick(['a', 'b']) + await helper.wait(50) + await nvim.input('') + let res = await p + expect(res).toBe(-1) + }) + + it('should show prompt', async () => { + let p = window.showPrompt('prompt') + await helper.wait(50) + await nvim.input('y') + let res = await p + expect(res).toBe(true) + }) + + it('should show dialog', async () => { + let dialog = await window.showDialog({ content: 'foo' }) + let winid = await dialog.winid + expect(winid).toBeDefined() + expect(winid).toBeGreaterThan(1000) + }) + + it('should show menu', async () => { + let p = window.showMenuPicker(['a', 'b', 'c'], 'choose item') + await helper.wait(50) + let exists = await nvim.call('coc#float#has_float', []) + expect(exists).toBe(1) + await nvim.input('2') + let res = await p + expect(res).toBe(1) + }) + + it('should return select items for picker', async () => { + let curr = await nvim.call('win_getid') + let p = window.showPickerDialog(['foo', 'bar'], 'select') + await helper.waitFloat() + await helper.wait(30) + await nvim.input(' ') + await nvim.input('') + let res = await p + let winid = await nvim.call('win_getid') + expect(winid).toBe(curr) + expect(res).toEqual(['foo']) + }) + + it('should throw when workspace folder does not exist', async () => { + helper.updateConfiguration('coc.preferences.rootPatterns', []) + await nvim.command('enew') + let err + try { + await window.openLocalConfig() + } catch (e) { + err = e + } + expect(err).toBeDefined() + await nvim.command(`e ${path.join(os.tmpdir(), 'a')}`) + err + try { + await window.openLocalConfig() + } catch (e) { + err = e + } + expect(err).toBeDefined() + await nvim.command(`e t.md`) + await nvim.command('setf markdown') + err + try { + await window.openLocalConfig() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should open local config', async () => { + let dir = path.join(os.tmpdir(), '.vim') + if (fs.existsSync(dir)) { + fs.emptyDirSync(dir) + fs.rmdirSync(dir) + } + if (!fs.existsSync(path.join(os.tmpdir(), '.git'))) { + fs.mkdirSync(path.join(os.tmpdir(), '.git')) + } + await helper.edit(path.join(os.tmpdir(), 't')) + let root = workspace.root + expect(root).toBe(os.tmpdir()) + let p = window.openLocalConfig() + await helper.wait(50) + await nvim.input('y') + await p + let bufname = await nvim.call('bufname', ['%']) + expect(bufname).toMatch('coc-settings.json') + }) + + describe('should get messageLevel', () => { + helper.updateConfiguration('coc.preferences.messageLevel', 'error') + let level = window.messageLevel + expect(level).toBe(MessageLevel.Error) + helper.updateConfiguration('coc.preferences.messageLevel', 'warning') + level = window.messageLevel + expect(level).toBe(MessageLevel.Warning) + }) + }) + + describe('window input', () => { + it('should request input', async () => { + let winid = await nvim.call('win_getid') + let p = window.requestInput('Name') + await helper.wait(50) + await nvim.input('bar') + let res = await p + let curr = await nvim.call('win_getid') + expect(curr).toBe(winid) + expect(res).toBe('bar') + }) + + it('should return empty string when input empty', async () => { + let p = window.requestInput('Name') + await helper.wait(30) + await nvim.input('') + let res = await p + expect(res).toBe('') + }) + + it('should emit change event', async () => { + let input = await window.createInputBox('', '', {}) + disposables.push(input) + let curr: string + input.onDidChange(text => { + curr = text + }) + await nvim.input('abc') + await helper.waitValue((() => { + return curr + }), 'abc') + input.title = 'foo' + expect(input.title).toBe('foo') + input.loading = true + expect(input.loading).toBe(true) + input.borderhighlight = 'WarningMsg' + expect(input.borderhighlight).toBe('WarningMsg') + }) + + it('should not check bufnr for events', async () => { + let input = await window.createInputBox('', undefined, {}) + disposables.push(input) + let bufnr = input.bufnr + let called = false + input.onDidChange(() => { + called = true + }) + await events.fire('BufWinLeave', [bufnr + 1]) + await events.fire('PromptInsert', ['', bufnr + 1]) + await events.fire('TextChangedI', [bufnr + 1, { + lnum: 1, + col: 1, + line: '', + changedtick: 0, + pre: '' + }]) + expect(called).toBe(false) + expect(input.bufnr).toBeDefined() + expect(input.dimension).toBeDefined() + }) + }) + + describe('window showMessage', () => { + async function ensureNotification(idx: number): Promise { + let ids = await nvim.call('coc#float#get_float_win_list') + expect(ids.length).toBe(1) + let win = nvim.createWindow(ids[0]) + let kind = await win.getVar('kind') + expect(kind).toBe('notification') + let bufnr = await nvim.call('winbufnr', [win.id]) + await events.fire('FloatBtnClick', [bufnr, idx]) + } + it('should echo lines', async () => { + await window.echoLines(['a', 'b']) + let ch = await nvim.call('screenchar', [79, 1]) + let s = String.fromCharCode(ch) + expect(s).toBe('a') + }) + + it('should echo multiple lines with truncate', async () => { + await window.echoLines(['a', 'b', 'd', 'e'], true) + let ch = await nvim.call('screenchar', [79, 1]) + let s = String.fromCharCode(ch) + expect(s).toBe('a') + }) + + it('should show messages', async () => { + window.showMessage('error', 'error') + window.showMessage('warning', 'warning') + window.showMessage('moremsg', 'more') + }) + + it('should show information message', async () => { + let p = window.showInformationMessage('information message', 'first', 'second') + await ensureNotification(0) + let res = await p + expect(res).toBe('first') + }) + + it('should show warning message', async () => { + let p = window.showWarningMessage('warning message', 'first', 'second') + await ensureNotification(1) + let res = await p + expect(res).toBe('second') + }) + + it('should show error message', async () => { + let p = window.showErrorMessage('error message', 'first', 'second') + await ensureNotification(0) + let res = await p + expect(res).toBe('first') + }) + + it('should prefer menu picker for notification message', async () => { + helper.updateConfiguration('notification.preferMenuPicker', true) + let p = window.showErrorMessage('error message', 'first', 'second') + await helper.waitFloat() + await nvim.input('1') + let res = await p + expect(res).toBe('first') + }) + }) + + describe('window parseSource()', () => { + it('should parse sour name', async () => { + expect(window.parseSource('\n\n')).toBeUndefined() + expect(window.parseSource(`\n\n${path.join(process.cwd(), 'a/b.js')}:1:1`)).toBe('coc.nvim') + expect(window.parseSource(`\n\n at Foo(${path.join(process.cwd(), 'a/b.js')}:1:1)`)).toBe('coc.nvim') + let info = extensions.getExtensionsInfo() + expect(window.parseSource(`\n\n${info[0].filepath}:1:1`)).toBe(info[0].name) + let filepath = path.join(info[0].directory, 'a/b/c.js') + expect(window.parseSource(`\n\n${filepath}:1:1`)).toBe(info[0].name) + }) + }) + + describe('window notifications', () => { + it('should show notification with options', async () => { + await window.showNotification({ + content: 'my notification', + title: 'title', + }) + let ids = await nvim.call('coc#float#get_float_win_list') + expect(ids.length).toBe(1) + let win = nvim.createWindow(ids[0]) + let kind = await win.getVar('kind') + expect(kind).toBe('notification') + let winid = await nvim.call('coc#float#get_related', [win.id, 'border']) + let bufnr = await nvim.call('winbufnr', [winid]) + let buf = nvim.createBuffer(bufnr) + let lines = await buf.lines + expect(lines[0].includes('title')).toBe(true) + }) + + it('should ignore events of other buffers', async () => { + let bufnr = workspace.bufnr + let notification = new Notification(nvim, {}) + await events.fire('BufWinLeave', [bufnr + 1]) + await events.fire('FloatBtnClick', [bufnr + 1, 1]) + notification.dispose() + }) + + it('should throw on showNotification when no dialog support', async () => { + Object.assign(workspace.env, { dialog: false }) + disposables.push(Disposable.create(() => { + Object.assign(workspace.env, { dialog: true }) + })) + let fn = async () => { + await window.showNotification({ + content: 'my notification', + title: 'title', + }) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should show notification without border', async () => { + helper.updateConfiguration('notification.border', false) + await window.showNotification({ + content: 'my notification', + title: 'title', + }) + let win = await helper.getFloat() + let height = await nvim.call('coc#float#get_height', [win.id]) + expect(height).toBe(2) + }) + + it('should show progress notification', async () => { + let called = 0 + let res = await window.withProgress({ title: 'Downloading', cancellable: true }, (progress, token) => { + let n = 0 + return new Promise(resolve => { + let interval = setInterval(() => { + progress.report({ message: 'progress', increment: 1 }) + n = n + 10 + called = called + 1 + if (n == 100) { + clearInterval(interval) + resolve('done') + } + }, 10) + token.onCancellationRequested(() => { + clearInterval(interval) + resolve(undefined) + }) + }) + }) + expect(called).toBeGreaterThan(8) + expect(res).toBe('done') + }) + + it('should cancel progress notification on window close', async () => { + let called = 0 + let p = window.withProgress({ title: 'Downloading', cancellable: true }, (progress, token) => { + let n = 0 + return new Promise(resolve => { + let interval = setInterval(() => { + progress.report({ message: 'progress', increment: 1 }) + n = n + 10 + called = called + 1 + if (n == 100) { + clearInterval(interval) + resolve('done') + } + }, 10) + token.onCancellationRequested(() => { + clearInterval(interval) + resolve(undefined) + }) + }) + }) + await helper.wait(30) + await nvim.call('coc#float#close_all', []) + let res = await p + expect(called).toBeLessThan(10) + expect(res).toBe(undefined) + }) + + it('should cancel progress when resolved', async () => { + let called = 0 + let p = window.withProgress({ title: 'Process' }, () => { + called = called + 1 + return Promise.resolve() + }) + await p + let win = await helper.getFloat() + if (win) { + let res = await nvim.call('coc#window#get_var', [win.id, 'closing']) + expect(res).toBe(1) + } + expect(called).toBe(1) + }) + + it('should be disabled by configuration', async () => { + helper.updateConfiguration('notification.disabledProgressSources', ['test']) + let p = window.withProgress({ title: 'Downloading', source: 'test' }, (progress, token) => { + let n = 0 + return new Promise(resolve => { + let interval = setInterval(() => { + progress.report({ message: 'progress', increment: 1 }) + n = n + 1 + if (n == 10) { + clearInterval(interval) + resolve('done') + } + }, 10) + }) + }) + await helper.wait(30) + let win = await helper.getFloat() + expect(win).toBeUndefined() + let res = await p + expect(res).toBe('done') + }) + + it('should show error message when rejected', async () => { + let p = window.withProgress({ title: 'Process' }, () => { + return Promise.reject(new Error('Unable to fetch')) + }) + let res = await p + expect(res).toBe(undefined) + let cmdline = await helper.getCmdline() + expect(cmdline).toMatch(/Unable to fetch/) + }) + }) + + describe('diffHighlights', () => { + let ns = 'window-test' + let priority = 99 + let ns_id: number + beforeAll(async () => { + ns_id = await nvim.call('coc#highlight#create_namespace', [ns]) + }) + + async function createFile(): Promise { + let content = 'foo\nbar' + let file = await createTmpFile(content) + return await helper.edit(file) + } + + async function setHighlights(hls: HighlightItem[]): Promise { + let bufnr = await nvim.call('bufnr', ['%']) as number + let arr = hls.map(o => [o.hlGroup, o.lnum, o.colStart, o.colEnd, o.combine === false ? 0 : 1, o.end_incl ? 1 : 0, o.start_incl ? 1 : 0]) + await nvim.call('coc#highlight#set', [bufnr, ns, arr, priority]) + } + + it('should add new highlights', async () => { + let buf = await createFile() + let items: HighlightItem[] = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 0, + colEnd: 3 + }] + let res = await window.diffHighlights(buf.id, ns, items) + expect(res).toBeDefined() + expect(res.add.length).toBe(1) + await window.applyDiffHighlights(buf.id, ns, priority, res) + let markers = await buf.getExtMarks(ns_id, 0, -1, { details: true }) + expect(markers.length).toBe(1) + expect(markers[0][3].end_col).toBe(3) + }) + + it('should return empty diff', async () => { + let buf = await createFile() + let items: HighlightItem[] = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 0, + colEnd: 3 + }] + await setHighlights(items) + let res = await window.diffHighlights(buf.id, ns, items) + expect(res).toBeDefined() + expect(res.remove).toEqual([]) + expect(res.add).toEqual([]) + expect(res.removeMarkers).toEqual([]) + }) + + it('should remove and add highlights', async () => { + let buf = await createFile() + let items: HighlightItem[] = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 0, + colEnd: 3 + }] + await setHighlights(items) + items = [{ + hlGroup: 'Search', + lnum: 1, + colStart: 0, + colEnd: 3 + }] + let res = await window.diffHighlights(buf.id, ns, items) + expect(res).toBeDefined() + expect(res.add.length).toBe(1) + expect(res.removeMarkers.length).toBe(1) + await window.applyDiffHighlights(buf.id, ns, priority, res) + let markers = await buf.getExtMarks(ns_id, 0, -1, { details: true }) + expect(markers.length).toBe(1) + expect(markers[0][1]).toBe(1) + expect(markers[0][3].end_col).toBe(3) + }) + + it('should update highlights of single line', async () => { + let buf = await createFile() + let items: HighlightItem[] = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 0, + colEnd: 1 + }, { + hlGroup: 'Search', + lnum: 1, + colStart: 2, + colEnd: 3 + }] + await setHighlights(items) + items = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 2, + colEnd: 3 + }] + let res = await window.diffHighlights(buf.id, ns, items) + expect(res).toBeDefined() + expect(res.add.length).toBe(1) + expect(res.removeMarkers.length).toBe(2) + await window.applyDiffHighlights(buf.id, ns, priority, res) + let markers = await buf.getExtMarks(ns_id, 0, -1, { details: true }) + expect(markers.length).toBe(1) + expect(markers[0][1]).toBe(0) + expect(markers[0][3].end_col).toBe(3) + }) + + it('should not use extmarks on neovim < 0.5.1', async () => { + let fn = workspace.has + workspace.has = feature => { + if (feature == 'nvim-0.5.1') return false + return fn.apply(workspace, [feature]) + } + disposables.push({ + dispose: () => { + workspace.has = fn + } + }) + let buf = await createFile() + let items: HighlightItem[] = [{ + hlGroup: 'Search', + lnum: 0, + colStart: 0, + colEnd: 1 + }, { + hlGroup: 'Search', + lnum: 0, + colStart: 2, + colEnd: 3 + }] + await setHighlights(items) + let res = await window.diffHighlights(buf.id, ns, []) + expect(res).toEqual({ + remove: [0], add: [], removeMarkers: [] + }) + await window.applyDiffHighlights(buf.id, ns, priority, res, true) + }) + }) + + describe('checkBuffer', () => { + async function checkFloat(content: string) { + let win = await helper.getFloat() + expect(win).toBeDefined() + let buf = await win.buffer + let lines = await buf.lines + expect(lines.join('\n')).toMatch(content) + } + + it('should should error message for document not attached', async () => { + await nvim.command('edit t|let b:coc_enabled = 0') + await window.bufferCheck() + await checkFloat('not attached') + await nvim.call('coc#float#close_all', []) + await nvim.command('edit +setl\\ buftype=nofile b') + await window.bufferCheck() + await checkFloat('not attached') + await nvim.call('coc#float#close_all', []) + await nvim.setVar('coc_max_filesize', 10240) + let filepath = path.join(process.cwd(), 'data/schema.json') + await helper.edit(filepath) + await window.bufferCheck() + await checkFloat('not attached') + await nvim.call('coc#float#close_all', []) + }) + + it('should show state of current buffer', async () => { + disposables.push(languages.registerDocumentFormatProvider(['*'], { + provideDocumentFormattingEdits: () => { + return [] + } + })) + await commands.executeCommand('document.checkBuffer') + await checkFloat('Provider state') + await nvim.call('coc#float#close_all', []) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/modules/workspace.test.ts b/sources_non_forked/coc.nvim/src/__tests__/modules/workspace.test.ts new file mode 100644 index 00000000..c14b8505 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/modules/workspace.test.ts @@ -0,0 +1,714 @@ +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { Disposable, Emitter } from 'vscode-languageserver-protocol' +import { Location, Position, Range, TextEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import events from '../../events' +import { TextDocumentContentProvider } from '../../provider' +import { ConfigurationTarget } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper, { createTmpFile } from '../helper' + +let nvim: Neovim +let disposables: Disposable[] = [] +let tmpFolder = path.join(os.tmpdir(), `coc-${process.pid}`) + +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + if (!fs.existsSync(tmpFolder)) fs.mkdirSync(tmpFolder) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() + disposeAll(disposables) + disposables = [] +}) + +describe('workspace properties', () => { + + it('should have initialized', () => { + let { nvim, rootPath, uri, insertMode, workspaceFolder, cwd, documents, textDocuments } = workspace + expect(insertMode).toBe(false) + expect(nvim).toBeTruthy() + expect(documents.length).toBe(1) + expect(textDocuments.length).toBe(1) + expect(rootPath).toBe(process.cwd()) + expect(cwd).toBe(process.cwd()) + let floatSupported = workspace.floatSupported + expect(floatSupported).toBe(true) + let { pluginRoot } = workspace + expect(typeof pluginRoot).toBe('string') + let { isVim, isNvim } = workspace + expect(isVim).toBe(false) + expect(isNvim).toBe(true) + expect(uri).toBeDefined() + expect(workspaceFolder).toBeUndefined() + let watchmanPath = workspace.getWatchmanPath() + expect(watchmanPath == null || typeof watchmanPath === 'string').toBe(true) + let folder = workspace.getWorkspaceFolder(uri) + expect(folder).toBeUndefined() + }) + + it('should get filetyps', async () => { + await helper.edit('f.js') + let filetypes = workspace.filetypes + expect(filetypes.has('javascript')).toBe(true) + let languageIds = workspace.languageIds + expect(languageIds.has('javascript')).toBe(true) + }) + + it('should get channelNames', async () => { + let names = workspace.channelNames + expect(Array.isArray(names)).toBe(true) + }) + + it('should work with deprecated method', async () => { + await nvim.setLine('foo') + await workspace['moveTo'](Position.create(0, 1)) + let col = await nvim.call('col', ['.']) + expect(col).toBe(2) + }) +}) + +describe('workspace methods', () => { + it('should call vim method', async () => { + let res = await workspace.callAsync('bufnr', ['%']) + expect(typeof res).toBe('number') + let obj: any = workspace.env + obj.isVim = true + disposables.push({ + dispose: () => { + obj.isVim = false + } + }) + res = await workspace.callAsync('bufnr', ['%']) + expect(typeof res).toBe('number') + }) + + it('should get the document', async () => { + let doc = await workspace.document + let buf = await nvim.buffer + expect(doc.buffer.equals(buf)).toBeTruthy() + doc = workspace.getDocument(doc.uri) + expect(doc.buffer.equals(buf)).toBeTruthy() + }) + + it('should get attached document', async () => { + let fn = () => { + workspace.getAttachedDocument('file://not_exists') + } + expect(fn).toThrow(Error) + await nvim.command(`edit +setl\\ buftype=nofile [tree]`) + let doc = await workspace.document + expect(doc.attached).toBe(false) + fn = () => { + workspace.getAttachedDocument(doc.bufnr) + } + expect(fn).toThrow(Error) + }) + + it('should get format options of without bufnr', async () => { + let opts = await workspace.getFormatOptions() + expect(opts.insertSpaces).toBe(true) + expect(opts.tabSize).toBe(2) + }) + + it('should get format options of current buffer', async () => { + let buf = await nvim.buffer + await buf.setVar('coc_trim_trailing_whitespace', 1) + await buf.setVar('coc_trim_final_newlines', 1) + await buf.setOption('shiftwidth', 8) + await buf.setOption('expandtab', false) + let doc = workspace.getDocument(buf.id) + let opts = await workspace.getFormatOptions(doc.uri) + expect(opts).toEqual({ + tabSize: 8, + insertSpaces: false, + insertFinalNewline: true, + trimTrailingWhitespace: true, + trimFinalNewlines: true + }) + }) + + it('should get format options when uri does not exist', async () => { + let uri = URI.file('/tmp/foo').toString() + let opts = await workspace.getFormatOptions(uri) + expect(opts.insertSpaces).toBe(true) + expect(opts.tabSize).toBe(2) + }) + + it('should get config files', async () => { + let file = workspace.getConfigFile(ConfigurationTarget.Global) + expect(file).toBeFalsy() + file = workspace.getConfigFile(ConfigurationTarget.User) + expect(file).toBeTruthy() + file = workspace.getConfigFile(ConfigurationTarget.Workspace) + expect(file).toBeTruthy() + }) + + it('should create file watcher', async () => { + let watcher = workspace.createFileSystemWatcher('**/*.ts') + expect(watcher).toBeDefined() + }) + + it('should get quickfix item from Location', async () => { + let filepath = await createTmpFile('quickfix') + let uri = URI.file(filepath).toString() + let p = Position.create(0, 0) + let loc = Location.create(uri, Range.create(p, p)) + let item = await workspace.getQuickfixItem(loc) + expect(item.filename).toBe(filepath) + expect(item.text).toBe('quickfix') + }) + + it('should get quickfix list from Locations', async () => { + let filepathA = await createTmpFile('fileA:1\nfileA:2\nfileA:3') + let uriA = URI.file(filepathA).toString() + let filepathB = await createTmpFile('fileB:1\nfileB:2\nfileB:3') + let uriB = URI.file(filepathB).toString() + let p1 = Position.create(0, 0) + let p2 = Position.create(1, 0) + let locations: Location[] = [] + locations.push(Location.create(uriA, Range.create(p1, p1))) + locations.push(Location.create(uriA, Range.create(p2, p2))) + locations.push(Location.create(uriB, Range.create(p1, p1))) + locations.push(Location.create(uriB, Range.create(p2, p2))) + let items = await workspace.getQuickfixList(locations) + expect(items[0].filename).toBe(filepathA) + expect(items[0].text).toBe('fileA:1') + expect(items[1].filename).toBe(filepathA) + expect(items[1].text).toBe('fileA:2') + expect(items[2].filename).toBe(filepathB) + expect(items[2].text).toBe('fileB:1') + expect(items[3].filename).toBe(filepathB) + expect(items[3].text).toBe('fileB:2') + }) + + it('should get line of document', async () => { + let doc = await workspace.document + await nvim.setLine('abc') + let line = await workspace.getLine(doc.uri, 0) + expect(line).toBe('abc') + }) + + it('should get line of file', async () => { + let filepath = await createTmpFile('quickfix') + let uri = URI.file(filepath).toString() + let line = await workspace.getLine(uri, 0) + expect(line).toBe('quickfix') + }) + + it('should read content from buffer', async () => { + let doc = await workspace.document + await doc.applyEdits([{ range: Range.create(0, 0, 0, 0), newText: 'foo' }]) + let line = await workspace.readFile(doc.uri) + expect(line).toBe('foo\n') + }) + + it('should read content from file', async () => { + let filepath = await createTmpFile('content') + let content = await workspace.readFile(URI.file(filepath).toString()) + expect(content).toBe(content) + }) + + it('should expand filepath', async () => { + let home = os.homedir() + let res = workspace.expand('~/$NODE_ENV/') + expect(res.startsWith(home)).toBeTruthy() + expect(res).toContain(process.env.NODE_ENV) + + res = workspace.expand('$HOME/$NODE_ENV/') + expect(res.startsWith(home)).toBeTruthy() + expect(res).toContain(process.env.NODE_ENV) + }) + + it('should expand variables', async () => { + expect(workspace.expand('${workspace}/foo')).toBe(`${workspace.root}/foo`) + expect(workspace.expand('${env:NODE_ENV}')).toBe(process.env.NODE_ENV) + expect(workspace.expand('${cwd}')).toBe(workspace.cwd) + let folder = path.dirname(workspace.root) + expect(workspace.expand('${workspaceFolderBasename}')).toBe(folder) + await helper.edit('bar.ts') + expect(workspace.expand('${file}')).toContain('bar') + expect(workspace.expand('${fileDirname}')).toBe(path.dirname(__dirname)) + expect(workspace.expand('${fileExtname}')).toBe('.ts') + expect(workspace.expand('${fileBasename}')).toBe('bar.ts') + expect(workspace.expand('${fileBasenameNoExtension}')).toBe('bar') + }) + + it('should run command', async () => { + let res = await workspace.runCommand('ls', __dirname, 1) + expect(res).toMatch('workspace') + }) + + it('should resolve module path if exists', async () => { + let res = await workspace.resolveModule('typescript') + res = await workspace.resolveModule('typescript') + expect(res).toBeTruthy() + }) + + it('should not resolve module if it does not exist', async () => { + let res = await workspace.resolveModule('foo') + res = await workspace.resolveModule('foo') + expect(res).toBeFalsy() + }) + + it('should return match score for document', async () => { + let doc = await helper.createDocument('tmp.xml') + expect(workspace.match(['xml'], doc.textDocument)).toBe(10) + expect(workspace.match(['wxml'], doc.textDocument)).toBe(0) + expect(workspace.match([{ language: 'xml' }], doc.textDocument)).toBe(10) + expect(workspace.match([{ language: 'wxml' }], doc.textDocument)).toBe(0) + expect(workspace.match([{ pattern: '**/*.xml' }], doc.textDocument)).toBe(5) + expect(workspace.match([{ pattern: '**/*.html' }], doc.textDocument)).toBe(0) + expect(workspace.match([{ scheme: 'file' }], doc.textDocument)).toBe(5) + expect(workspace.match([{ scheme: 'term' }], doc.textDocument)).toBe(0) + expect(workspace.match([{ language: 'xml' }, { scheme: 'file' }], doc.textDocument)).toBe(10) + }) + + it('should rename buffer', async () => { + let doc = await helper.createDocument('a') + let fsPath = URI.parse(doc.uri).fsPath.replace(/a$/, 'b') + disposables.push(Disposable.create(() => { + if (fs.existsSync(fsPath)) fs.unlinkSync(fsPath) + })) + let p = workspace.renameCurrent() + await helper.wait(50) + await nvim.input('b') + await p + let name = await nvim.eval('bufname("%")') as string + expect(name.endsWith('b')).toBe(true) + }) + + it('should rename file', async () => { + let fsPath = path.join(tmpFolder, 'x') + let newPath = path.join(tmpFolder, 'b') + disposables.push(Disposable.create(() => { + if (fs.existsSync(fsPath)) fs.unlinkSync(fsPath) + if (fs.existsSync(newPath)) fs.unlinkSync(newPath) + })) + fs.writeFileSync(fsPath, 'foo', 'utf8') + await helper.createDocument(fsPath) + let p = workspace.renameCurrent() + await helper.waitFor('mode', [], 'c') + await nvim.input('b') + await p + let name = await nvim.eval('bufname("%")') as string + expect(name.endsWith('b')).toBe(true) + expect(fs.existsSync(newPath)).toBe(true) + let content = fs.readFileSync(newPath, 'utf8') + expect(content).toMatch(/foo/) + }) + + it('should handle will save event', async () => { + async function doRename() { + let fsPath = await createTmpFile('foo', disposables) + let newPath = path.join(path.dirname(fsPath), 'new_file') + disposables.push(Disposable.create(() => { + if (fs.existsSync(newPath)) fs.unlinkSync(newPath) + })) + await workspace.renameFile(fsPath, newPath, { overwrite: true }) + if (fs.existsSync(newPath)) fs.unlinkSync(newPath) + } + let called = false + let disposable = workspace.onWillRenameFiles(e => { + let p = new Promise(resolve => { + setTimeout(() => { + called = true + resolve() + }, 10) + }) + e.waitUntil(p) + }) + await doRename() + disposable.dispose() + expect(called).toBe(true) + called = false + disposable = workspace.onWillRenameFiles(e => { + called = true + e.waitUntil(Promise.resolve({ changes: {} })) + }) + await doRename() + expect(called).toBe(true) + disposable.dispose() + }) +}) + +describe('workspace utility', () => { + + it('should create database', async () => { + let db = workspace.createDatabase('test') + let res = db.exists('xyz') + expect(res).toBe(false) + db.destroy() + }) + + it('should get current state', async () => { + let buf = await helper.edit() + await buf.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false }) + await nvim.call('cursor', [2, 2]) + let doc = workspace.getDocument(buf.id) + let state = await workspace.getCurrentState() + expect(doc.uri).toBe(state.document.uri) + expect(state.position).toEqual({ line: 1, character: 1 }) + }) + + it('should findUp to tsconfig.json from current file', async () => { + await helper.edit(path.join(__dirname, 'edit')) + let filepath = await workspace.findUp('tsconfig.json') + expect(filepath).toMatch('tsconfig.json') + }) + + it('should findUp from current file ', async () => { + await helper.edit('foo') + let filepath = await workspace.findUp('tsconfig.json') + expect(filepath).toMatch('tsconfig.json') + }) + + it('should not findUp from file in other directory', async () => { + await nvim.command(`edit ${path.join(os.tmpdir(), 'foo')}`) + let filepath = await workspace.findUp('tsconfig.json') + expect(filepath).toBeNull() + }) + + it('should register autocmd', async () => { + let event: any + let eventCount = 0 + let disposables = [] + disposables.push(workspace.registerAutocmd({ + event: 'TextYankPost', + arglist: ['v:event'], + callback: ev => { + eventCount += 1 + event = ev + } + })) + disposables.push(workspace.registerAutocmd({ + event: ['InsertEnter', 'CursorMoved'], + callback: () => { + eventCount += 1 + } + })) + await nvim.setLine('foo') + await helper.wait(30) + await nvim.command('normal! yy') + await helper.wait(30) + await nvim.command('normal! Abar') + await helper.wait(30) + expect(event.regtype).toBe('V') + expect(event.operator).toBe('y') + expect(event.regcontents).toEqual(['foo']) + expect(eventCount).toBeGreaterThan(2) + disposables.forEach(d => d.dispose()) + }) + + it('should regist keymap', async () => { + let fn = jest.fn() + await nvim.command('nmap go (coc-echo)') + let disposable = workspace.registerKeymap(['n', 'v'], 'echo', fn, { sync: true }) + await helper.wait(30) + let { mode } = await nvim.mode + expect(mode).toBe('n') + await nvim.call('feedkeys', ['go', 'i']) + await helper.wait(50) + expect(fn).toBeCalledTimes(1) + disposable.dispose() + await nvim.call('feedkeys', ['go', 'i']) + await helper.wait(50) + expect(fn).toBeCalledTimes(1) + }) + + it('should regist expr keymap', async () => { + let called = false + let fn = () => { + called = true + return '""' + } + await nvim.input('i') + let { mode } = await nvim.mode + expect(mode).toBe('i') + let disposable = workspace.registerExprKeymap('i', '"', fn) + await helper.wait(30) + await nvim.call('feedkeys', ['"', 't']) + await helper.wait(30) + expect(called).toBe(true) + let line = await nvim.line + expect(line).toBe('""') + disposable.dispose() + }) + + it('should regist buffer expr keymap', async () => { + let fn = () => '""' + await nvim.input('i') + let disposable = workspace.registerExprKeymap('i', '"', fn, true) + await helper.wait(30) + await nvim.call('feedkeys', ['"', 't']) + await helper.wait(30) + let line = await nvim.line + expect(line).toBe('""') + disposable.dispose() + }) + + it('should watch options', async () => { + let fn = jest.fn() + workspace.watchOption('showmode', fn, disposables) + workspace.watchOption('showmode', fn) + await helper.wait(30) + await nvim.command('set showmode') + await helper.wait(30) + expect(fn).toBeCalled() + await nvim.command('noa set noshowmode') + }) + + it('should watch global', async () => { + let fn = jest.fn() + workspace.watchGlobal('x', fn, disposables) + workspace.watchGlobal('x', fn) + workspace.watchGlobal('x') + await nvim.command('let g:x = 1') + await helper.wait(30) + expect(fn).toBeCalled() + }) + + it('should check nvim version', async () => { + expect(workspace.has('patch-7.4.248')).toBe(false) + expect(workspace.has('nvim-0.5.0')).toBe(true) + expect(workspace.has('nvim-0.9.0')).toBe(false) + }) +}) + +describe('workspace events', () => { + + it('should listen to fileType change', async () => { + let buf = await helper.edit() + await nvim.command('setf xml') + await helper.wait(50) + let doc = workspace.getDocument(buf.id) + expect(doc.filetype).toBe('xml') + }) + + it('should fire onDidOpenTextDocument', async () => { + let fn = jest.fn() + workspace.onDidOpenTextDocument(fn, null, disposables) + await helper.edit() + await helper.wait(30) + expect(fn).toHaveBeenCalledTimes(1) + }) + + it('should fire onDidChangeTextDocument', async () => { + let fn = jest.fn() + await helper.edit() + workspace.onDidChangeTextDocument(fn, null, disposables) + await nvim.setLine('foo') + let doc = await workspace.document + doc.forceSync() + await helper.wait(20) + expect(fn).toHaveBeenCalledTimes(1) + }) + + it('should fire onDidChangeConfiguration', async () => { + let fn = jest.fn() + let disposable = workspace.onDidChangeConfiguration(e => { + disposable.dispose() + expect(e.affectsConfiguration('tsserver')).toBe(true) + expect(e.affectsConfiguration('tslint')).toBe(false) + fn() + }) + let config = workspace.getConfiguration('tsserver') + config.update('enable', false) + expect(fn).toHaveBeenCalledTimes(1) + config.update('enable', undefined) + }) + + it('should get empty configuration for none exists section', () => { + let config = workspace.getConfiguration('notexists') + let keys = Object.keys(config) + expect(keys.length).toBe(0) + }) + + it('should fire onWillSaveUntil', async () => { + let doc = await workspace.document + let filepath = URI.parse(doc.uri).fsPath + let fn = jest.fn() + let disposable = workspace.onWillSaveTextDocument(event => { + let promise = new Promise(resolve => { + fn() + let edit: TextEdit = { + newText: 'foo', + range: Range.create(0, 0, 0, 0) + } + resolve([edit]) + }) + event.waitUntil(promise) + }) + await nvim.setLine('bar') + await helper.wait(30) + await events.fire('BufWritePre', [doc.bufnr, doc.bufname]) + await helper.wait(30) + let content = doc.getDocumentContent() + expect(content.startsWith('foobar')).toBe(true) + disposable.dispose() + expect(fn).toBeCalledTimes(1) + if (fs.existsSync(filepath)) { + fs.unlinkSync(filepath) + } + }) + + it('should not work for async waitUntil', async () => { + let doc = await helper.createDocument() + let filepath = URI.parse(doc.uri).fsPath + let disposable = workspace.onWillSaveTextDocument(event => { + setTimeout(() => { + let edit: TextEdit = { + newText: 'foo', + range: Range.create(0, 0, 0, 0) + } + event.waitUntil(Promise.resolve([edit])) + }, 30) + }) + await nvim.setLine('bar') + await helper.wait(30) + await nvim.command('wa') + let content = doc.getDocumentContent() + expect(content).toMatch('bar') + disposable.dispose() + if (fs.existsSync(filepath)) { + fs.unlinkSync(filepath) + } + }) + + it('should only use first returned textEdits', async () => { + let doc = await helper.createDocument() + let filepath = URI.parse(doc.uri).fsPath + disposables.push(Disposable.create(() => { + if (fs.existsSync(filepath)) { + fs.unlinkSync(filepath) + } + })) + workspace.onWillSaveTextDocument(event => { + event.waitUntil(Promise.resolve(undefined)) + }, null, disposables) + workspace.onWillSaveTextDocument(event => { + let promise = new Promise(resolve => { + setTimeout(() => { + let edit: TextEdit = { + newText: 'foo', + range: Range.create(0, 0, 0, 0) + } + resolve([edit]) + }, 10) + }) + event.waitUntil(promise) + }, null, disposables) + workspace.onWillSaveTextDocument(event => { + let promise = new Promise(resolve => { + setTimeout(() => { + let edit: TextEdit = { + newText: 'bar', + range: Range.create(0, 0, 0, 0) + } + resolve([edit]) + }, 30) + }) + event.waitUntil(promise) + }, null, disposables) + await nvim.setLine('bar') + await helper.wait(30) + await nvim.command('wa') + let content = doc.getDocumentContent() + expect(content).toMatch('foo') + }) + + it('should attach & detach', async () => { + let buf = await helper.edit() + await nvim.command('CocDisable') + let doc = workspace.getDocument(buf.id) + expect(doc).toBeUndefined() + await nvim.command('CocEnable') + doc = workspace.getDocument(buf.id) + expect(doc.bufnr).toBe(buf.id) + }) +}) + +describe('workspace textDocument content provider', () => { + + it('should regist document content provider', async () => { + let provider: TextDocumentContentProvider = { + provideTextDocumentContent: (_uri, _token): string => 'sample text' + } + workspace.registerTextDocumentContentProvider('test', provider) + await nvim.command('edit test://1') + let buf = await nvim.buffer + let lines = await buf.lines + expect(lines).toEqual(['sample text']) + }) + + it('should react on change event of document content provider', async () => { + let text = 'foo' + let emitter = new Emitter() + let event = emitter.event + let provider: TextDocumentContentProvider = { + onDidChange: event, + provideTextDocumentContent: (_uri, _token): string => text + } + workspace.registerTextDocumentContentProvider('jdk', provider) + workspace.autocmds.setupDynamicAutocmd(true) + await nvim.command('edit jdk://1') + await workspace.document + text = 'bar' + emitter.fire(URI.parse('jdk://1')) + await helper.waitFor('getline', ['.'], 'bar') + }) +}) + +describe('workspace registerBufferSync', () => { + it('should regist', async () => { + await helper.createDocument() + let created = 0 + let deleted = 0 + let changed = 0 + let disposable = workspace.registerBufferSync(() => { + created = created + 1 + return { + dispose: () => { + deleted += 1 + }, + onChange: () => { + changed += 1 + } + } + }) + disposables.push(disposable) + let doc = await helper.createDocument() + expect(created).toBe(2) + await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo')]) + expect(changed).toBe(1) + await nvim.command('bd!') + expect(deleted).toBe(1) + }) + + it('should invoke onTextChange', async () => { + let called = 0 + disposables.push(workspace.registerBufferSync(() => { + return { + dispose: () => { + }, + onTextChange: () => { + called = called + 1 + } + } + })) + let doc = await helper.createDocument() + await nvim.setLine('foo') + await doc.synchronize() + expect(called).toBe(1) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/rg b/sources_non_forked/coc.nvim/src/__tests__/rg new file mode 100755 index 00000000..056d698a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/rg @@ -0,0 +1,38 @@ +#!/usr/bin/env node +// black:30 red:31 green:32 + +let content = `\x1b[30mmodules/cursors.test.ts\x1b[m +\x1b[32m218\x1b[m- let doc = await setup() +\x1b[32m219\x1b[m- await nvim.call('cursor', [1, 4]) +\x1b[32m220\x1b[m: await nvim.input('\x1b[31mabc\x1b[m') +\x1b[32m221\x1b[m- await helper.wait(30) +\x1b[32m222\x1b[m- doc.forceSync() +\x1b[32m223\x1b[m- await helper.wait(100) +\x1b[32m224\x1b[m- let lines = await nvim.call('getline', [1, '$']) +\x1b[32m225\x1b[m: expect(lines).toEqual(['\x1b[31mabc\x1b[m fooabc fooabc', 'barabc barabc']) +\x1b[32m226\x1b[m- }) +\x1b[32m227\x1b[m- +-- +\x1b[32m32\x1b[m- expect(rangeCount()).toBe(5) +\x1b[32m33\x1b[m- let lines = await nvim.call('getline', [1, '$']) +\x1b[32m34\x1b[m: expect(lines).toEqual(['\x1b[31mabc\x1b[m fooabc fooabc', 'barabc barabc']) +\x1b[32m35\x1b[m- }) +\x1b[32m36\x1b[m- + +\x1b[30mmodules/position.test.ts\x1b[m +\x1b[32m42\x1b[m- test('getChangedPosition #1', () => { +\x1b[32m43\x1b[m- let pos = Position.create(0, 0) +\x1b[32m44\x1b[m: let edit = TextEdit.insert(pos, '\x1b[31mabc\x1b[m') +\x1b[32m45\x1b[m- let res = getChangedPosition(pos, edit) +\x1b[32m46\x1b[m- expect(res).toEqual({ line: 0, character: 3 }) +` + +let idx = process.argv.findIndex(s => s == '--sleep') +if (idx !== -1) { + let ms = process.argv[idx + 1] + setTimeout(() => { + process.stdout.write(content) + }, ms) +} else { + process.stdout.write(content) +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/sample/.vim/coc-settings.json b/sources_non_forked/coc.nvim/src/__tests__/sample/.vim/coc-settings.json new file mode 100644 index 00000000..745333b2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/sample/.vim/coc-settings.json @@ -0,0 +1,3 @@ +{ + "coc.preferences.rootPath": "./src" +} diff --git a/sources_non_forked/coc.nvim/src/__tests__/snippets/manager.test.ts b/sources_non_forked/coc.nvim/src/__tests__/snippets/manager.test.ts new file mode 100644 index 00000000..b22768a9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/snippets/manager.test.ts @@ -0,0 +1,302 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { InsertTextMode, Range, TextEdit } from 'vscode-languageserver-protocol' +import commandManager from '../../commands' +import Document from '../../model/document' +import snippetManager from '../../snippets/manager' +import { SnippetString } from '../../snippets/string' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +let doc: Document +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + let pyfile = path.join(__dirname, '../ultisnips.py') + await nvim.command(`execute 'pyxfile '.fnameescape('${pyfile}')`) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +beforeEach(async () => { + doc = await helper.createDocument() +}) + +describe('snippet provider', () => { + describe('insertSnippet command', () => { + it('should insert ultisnips snippet', async () => { + await nvim.setLine('foo') + let edit = TextEdit.replace(Range.create(0, 0, 0, 3), '${1:`echo "bar"`}') + await commandManager.executeCommand('editor.action.insertSnippet', edit, {}) + let line = await nvim.line + expect(line).toBe('bar') + edit = TextEdit.replace(Range.create(0, 0, 0, 3), '${1:`echo "foo"`}') + await commandManager.executeCommand('editor.action.insertSnippet', edit, { regex: '' }) + line = await nvim.line + expect(line).toBe('foo') + }) + }) + + describe('insertSnippet()', () => { + it('should throw when buffer not attached', async () => { + await nvim.command(`vnew +setl\\ buftype=nofile`) + let err + try { + await snippetManager.insertSnippet('foo') + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should throw with invalid range', async () => { + await nvim.command(`vnew +setl\\ buftype=nofile`) + let err + try { + await snippetManager.insertSnippet('foo', false, Range.create(3, 0, 3, 0)) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should not active when insert plain snippet', async () => { + await snippetManager.insertSnippet('foo') + let line = await nvim.line + expect(line).toBe('foo') + expect(snippetManager.session).toBe(undefined) + expect(snippetManager.getSession(doc.bufnr)).toBeUndefined() + }) + + it('should start new session if session exists', async () => { + await nvim.setLine('bar') + await snippetManager.insertSnippet('${1:foo} ') + await nvim.input('') + await nvim.command('stopinsert') + await nvim.input('A') + let active = await snippetManager.insertSnippet('${2:bar}') + expect(active).toBe(true) + let line = await nvim.getLine() + expect(line).toBe('foo barbar') + }) + + it('should start nest session', async () => { + await snippetManager.insertSnippet('${1:foo} ${2:bar}') + await nvim.input('') + let active = await snippetManager.insertSnippet('${1:x} $1') + expect(active).toBe(true) + }) + + it('should insert snippetString', async () => { + let snippetString = new SnippetString() + .appendTabstop(1) + .appendText(' ') + .appendPlaceholder('bar', 2) + await snippetManager.insertSnippet(snippetString) + await nvim.input('$foo;') + snippetString = new SnippetString() + .appendVariable('foo', 'x') + await snippetManager.insertSnippet(snippetString, false, Range.create(0, 5, 0, 6)) + let line = await nvim.line + expect(line).toBe('$foo;xbar') + }) + }) + + describe('nextPlaceholder()', () => { + it('should goto next placeholder', async () => { + await snippetManager.insertSnippet('${1:a} ${2:b}') + await snippetManager.nextPlaceholder() + let col = await nvim.call('col', '.') + expect(col).toBe(3) + }) + + it('should remove keymap on nextPlaceholder when session not exits', async () => { + await nvim.call('coc#snippet#enable') + await snippetManager.nextPlaceholder() + let val = await doc.buffer.getVar('coc_snippet_active') + expect(val).toBe(0) + }) + + it('should respect preferCompleteThanJumpPlaceholder', async () => { + let config = workspace.getConfiguration('suggest') + config.update('preferCompleteThanJumpPlaceholder', true) + await nvim.setLine('foo') + await nvim.input('o') + await snippetManager.insertSnippet('${1:foo} ${2:bar}') + await nvim.input('f') + await helper.waitPopup() + await nvim.input('') + await helper.waitFor('getline', ['.'], 'foo bar') + config.update('preferCompleteThanJumpPlaceholder', false) + }) + }) + + describe('previousPlaceholder()', () => { + it('should goto previous placeholder', async () => { + await snippetManager.insertSnippet('${1:a} ${2:b}') + await snippetManager.nextPlaceholder() + await snippetManager.previousPlaceholder() + let col = await nvim.call('col', '.') + expect(col).toBe(1) + }) + + it('should remove keymap on previousPlaceholder when session not exits', async () => { + await nvim.call('coc#snippet#enable') + await snippetManager.previousPlaceholder() + let val = await doc.buffer.getVar('coc_snippet_active') + expect(val).toBe(0) + }) + }) + + describe('Events', () => { + it('should check position on InsertEnter', async () => { + await nvim.input('ibar') + await snippetManager.insertSnippet('${1:foo} $1 ') + await nvim.input('A') + await helper.wait(50) + expect(snippetManager.session).toBeUndefined() + }) + + it('should change status item on editor change', async () => { + await nvim.command('tabe') + await workspace.document + await nvim.input('i') + await snippetManager.insertSnippet('${1:foo} $1 ') + let val = await nvim.getVar('coc_status') + expect(val).toBeDefined() + await nvim.setTabpage(nvim.createTabpage(1)) + val = await nvim.getVar('coc_status') as string + expect(val.includes('SNIP')).toBeFalsy() + }) + }) + + describe('cancel()', () => { + it('should cancel snippet session', async () => { + let buffer = doc.buffer + await nvim.call('coc#snippet#enable') + snippetManager.cancel() + let val = await buffer.getVar('coc_snippet_active') + expect(val).toBe(0) + let active = await snippetManager.insertSnippet('${1:foo}') + expect(active).toBe(true) + snippetManager.cancel() + expect(snippetManager.session).toBeUndefined() + }) + }) + + describe('jumpable()', () => { + it('should check jumpable', async () => { + await nvim.input('i') + await snippetManager.insertSnippet('${1:foo} ${2:bar}') + let jumpable = snippetManager.jumpable() + expect(jumpable).toBe(true) + await snippetManager.nextPlaceholder() + jumpable = snippetManager.jumpable() + expect(jumpable).toBe(true) + await snippetManager.nextPlaceholder() + jumpable = snippetManager.jumpable() + expect(jumpable).toBe(false) + }) + }) + + describe('synchronize text', () => { + it('should update placeholder on placeholder update', async () => { + await nvim.input('i') + await snippetManager.insertSnippet('$1\n${1/,/|/g}', true, undefined, InsertTextMode.adjustIndentation, {}) + await nvim.input('a,b') + await helper.wait(50) + let s = snippetManager.getSession(doc.bufnr) + await s.forceSynchronize() + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(['a,b', 'a|b']) + }) + + it('should adjust cursor position on update', async () => { + await nvim.call('cursor', [1, 1]) + await nvim.input('i') + await snippetManager.insertSnippet('${1/..*/ -> /}$1') + let line = await nvim.line + expect(line).toBe('') + await nvim.input('x') + let s = snippetManager.getSession(doc.bufnr) + expect(s).toBeDefined() + await s.forceSynchronize() + line = await nvim.line + expect(line).toBe(' -> x') + let col = await nvim.call('col', '.') + expect(col).toBe(6) + }) + + it('should synchronize text on change final placeholder', async () => { + let doc = await workspace.document + await nvim.input('i') + let res = await snippetManager.insertSnippet('$0empty$0') + expect(res).toBe(true) + await nvim.call('nvim_buf_set_text', [doc.bufnr, 0, 0, 0, 0, ['abc']]) + await doc.synchronize() + let s = snippetManager.getSession(doc.bufnr) + await s.forceSynchronize() + let line = await nvim.line + expect(line).toBe('abcemptyabc') + }) + + it('should not synchronize when position changed and pum visible', async () => { + let buf = await nvim.buffer + await nvim.setLine('foo') + await nvim.input('o') + let res = await snippetManager.insertSnippet("`!p snip.rv = ' '*(4- len(t[1]))`${1}", true, undefined, InsertTextMode.asIs, {}) + expect(res).toBe(true) + let line = await nvim.line + expect(line).toBe(' ') + await nvim.input('f') + await helper.wait(60) + await nvim.input('o') + await helper.wait(60) + await nvim.input('o') + await helper.wait(60) + let visible = await nvim.call('pumvisible') + expect(visible).toBe(1) + await nvim.input('') + let s = snippetManager.getSession(buf.id) + expect(s).toBeDefined() + await s.forceSynchronize() + line = await nvim.line + expect(line).toBe(' foo') + }) + }) + + describe('resolveSnippet()', () => { + it('should resolve snippet text', async () => { + let snippet = await snippetManager.resolveSnippet('${1:foo}') + expect(snippet.toString()).toBe('foo') + snippet = await snippetManager.resolveSnippet('${1:foo} ${2:`!p snip.rv = "foo"`}', {}) + expect(snippet.toString()).toBe('foo foo') + }) + + it('should avoid python resolve when necessary', async () => { + await nvim.command('startinsert') + let res = await snippetManager.insertSnippet('${1:foo} `!p snip.rv = t[1]`', true, Range.create(0, 0, 0, 0), InsertTextMode.asIs, {}) + expect(res).toBe(true) + let snippet = await snippetManager.resolveSnippet('${1:x} `!p snip.rv= t[1]`', {}) + expect(snippet.toString()).toBe('x ') + res = await nvim.call('pyxeval', 't[1]') + expect(res).toBe('foo') + }) + }) + + describe('dispose()', () => { + it('should dispose', async () => { + let active = await snippetManager.insertSnippet('${1:foo}') + expect(active).toBe(true) + snippetManager.dispose() + expect(snippetManager.session).toBeUndefined() + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/snippets/parser.test.ts b/sources_non_forked/coc.nvim/src/__tests__/snippets/parser.test.ts new file mode 100644 index 00000000..6f5f5976 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/snippets/parser.test.ts @@ -0,0 +1,1013 @@ +/* eslint-disable */ +import * as assert from 'assert' +import { EvalKind } from '../../snippets/eval' +import { Choice, CodeBlock, FormatString, Marker, Placeholder, Scanner, SnippetParser, Text, TextmateSnippet, TokenType, Transform, transformEscapes, Variable } from '../../snippets/parser' + +describe('SnippetParser', () => { + + test('transformEscapes', () => { + assert.equal(transformEscapes('b\\uabc\\LDef'), 'bAbcdef') + assert.equal(transformEscapes('b\\Uabc\\Edef'), 'bABCdef') + assert.equal(transformEscapes('b\\LABC\\Edef'), 'babcdef') + assert.equal(transformEscapes(' \\n \\t'), ' \n \t') + }) + + test('Scanner', () => { + + const scanner = new Scanner() + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('abc') + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('{{abc}}') + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.CurlyClose) + assert.equal(scanner.next().type, TokenType.CurlyClose) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('abc() ') + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.OpenParen) + assert.equal(scanner.next().type, TokenType.CloseParen) + assert.equal(scanner.next().type, TokenType.Format) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('abc 123') + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.Format) + assert.equal(scanner.next().type, TokenType.Int) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('$foo') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('$foo_bar') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('$foo-bar') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.Dash) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('${foo}') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.CurlyClose) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('${1223:foo}') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.Int) + assert.equal(scanner.next().type, TokenType.Colon) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.CurlyClose) + assert.equal(scanner.next().type, TokenType.EOF) + + scanner.text('\\${}') + assert.equal(scanner.next().type, TokenType.Backslash) + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.CurlyClose) + + scanner.text('${foo/regex/format/option}') + assert.equal(scanner.next().type, TokenType.Dollar) + assert.equal(scanner.next().type, TokenType.CurlyOpen) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.Forwardslash) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.Forwardslash) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.Forwardslash) + assert.equal(scanner.next().type, TokenType.VariableName) + assert.equal(scanner.next().type, TokenType.CurlyClose) + assert.equal(scanner.next().type, TokenType.EOF) + }) + + function assertText(value: string, expected: string, ultisnip = false) { + const p = new SnippetParser(ultisnip) + const actual = p.text(value) + assert.equal(actual, expected) + } + + function assertMarker(input: TextmateSnippet | Marker[] | string, ...ctors: Function[]) { + let marker: Marker[] + if (input instanceof TextmateSnippet) { + marker = input.children + } else if (typeof input === 'string') { + const p = new SnippetParser() + marker = p.parse(input).children + } else { + marker = input + } + while (marker.length > 0) { + let m = marker.pop() + let ctor = ctors.pop() + assert.ok(m instanceof ctor) + } + assert.equal(marker.length, ctors.length) + assert.equal(marker.length, 0) + } + + function assertTextAndMarker(value: string, escaped: string, ...ctors: Function[]) { + assertText(value, escaped) + assertMarker(value, ...ctors) + } + + function assertEscaped(value: string, expected: string) { + const actual = SnippetParser.escape(value) + assert.equal(actual, expected) + } + + test('Parser, escaped', function() { + assertEscaped('foo$0', 'foo\\$0') + assertEscaped('foo\\$0', 'foo\\\\\\$0') + assertEscaped('f$1oo$0', 'f\\$1oo\\$0') + assertEscaped('${1:foo}$0', '\\${1:foo\\}\\$0') + assertEscaped('$', '\\$') + }) + + test('Parser, escaped ultisnips', () => { + const actual = new SnippetParser(true).text('t\\`a\\`\n\\$ \\{\\}') + expect(actual).toBe('t`a`\n$ {}') + }) + + test('Parser, transform with empty placeholder', () => { + const actual = new SnippetParser(true).text('${1} ${1/^(.*)/$1aa/}') + expect(actual).toBe(' aa') + }) + + test('Parser, isPlainText()', function() { + const s = (input: string, res: boolean) => { + assert.equal(SnippetParser.isPlainText(input), res) + } + s('abc', true) + s('abc$0', true) + s('ab$0chh', false) + s('ab$1chh', false) + }) + + test('Parser, first placeholder / variable', function() { + const first = (input: string): Marker => { + const p = new SnippetParser(true) + let s = p.parse(input, true) + return s.first + } + const assertPlaceholder = (m: any, index: number) => { + assert.equal(m instanceof Placeholder, true) + assert.equal(m.index, index) + } + assertPlaceholder(first('foo'), 0) + assertPlaceholder(first('${1:foo}'), 1) + assertPlaceholder(first('${2:foo}'), 2) + let f = first('$foo $bar') as Variable + assert.equal(f instanceof Variable, true) + assert.equal(f.name, 'foo') + }) + + test('Parser, text', () => { + assertText('$', '$') + assertText('\\\\$', '\\$') + assertText('{', '{') + assertText('\\}', '}') + assertText('\\abc', '\\abc') + assertText('foo${f:\\}}bar', 'foo}bar') + assertText('\\{', '\\{') + assertText('I need \\\\\\$', 'I need \\$') + assertText('\\', '\\') + assertText('\\{{', '\\{{') + assertText('{{', '{{') + assertText('{{dd', '{{dd') + assertText('}}', '}}') + assertText('ff}}', 'ff}}') + + assertText('farboo', 'farboo') + assertText('far{{}}boo', 'far{{}}boo') + assertText('far{{123}}boo', 'far{{123}}boo') + assertText('far\\{{123}}boo', 'far\\{{123}}boo') + assertText('far{{id:bern}}boo', 'far{{id:bern}}boo') + assertText('far{{id:bern {{basel}}}}boo', 'far{{id:bern {{basel}}}}boo') + assertText('far{{id:bern {{id:basel}}}}boo', 'far{{id:bern {{id:basel}}}}boo') + assertText('far{{id:bern {{id2:basel}}}}boo', 'far{{id:bern {{id2:basel}}}}boo') + }) + + + test('Parser, TM text', () => { + assertTextAndMarker('foo${1:bar}}', 'foobar}', Text, Placeholder, Text) + assertTextAndMarker('foo${1:bar}${2:foo}}', 'foobarfoo}', Text, Placeholder, Placeholder, Text) + + assertTextAndMarker('foo${1:bar\\}${2:foo}}', 'foobar}foo', Text, Placeholder) + + let [, placeholder] = new SnippetParser().parse('foo${1:bar\\}${2:foo}}').children + let { children } = (placeholder) + + assert.equal((placeholder).index, '1') + assert.ok(children[0] instanceof Text) + assert.equal(children[0].toString(), 'bar}') + assert.ok(children[1] instanceof Placeholder) + assert.equal(children[1].toString(), 'foo') + }) + + test('Parser, placeholder', () => { + assertTextAndMarker('farboo', 'farboo', Text) + assertTextAndMarker('far{{}}boo', 'far{{}}boo', Text) + assertTextAndMarker('far{{123}}boo', 'far{{123}}boo', Text) + assertTextAndMarker('far\\{{123}}boo', 'far\\{{123}}boo', Text) + }) + + test('Parser, literal code', () => { + assertTextAndMarker('far`123`boo', 'far`123`boo', Text) + assertTextAndMarker('far\\`123\\`boo', 'far\\`123\\`boo', Text) + }) + + test('Parser, variables/tabstop', () => { + assertTextAndMarker('$far-boo', '-boo', Variable, Text) + assertTextAndMarker('\\$far-boo', '$far-boo', Text) + assertTextAndMarker('far$farboo', 'far', Text, Variable) + assertTextAndMarker('far${farboo}', 'far', Text, Variable) + assertTextAndMarker('$123', '', Placeholder) + assertTextAndMarker('$farboo', '', Variable) + assertTextAndMarker('$far12boo', '', Variable) + assertTextAndMarker('000_${far}_000', '000__000', Text, Variable, Text) + assertTextAndMarker('FFF_${TM_SELECTED_TEXT}_FFF$0', 'FFF__FFF', Text, Variable, Text, Placeholder) + }) + + test('Parser, variables/placeholder with defaults', () => { + assertTextAndMarker('${name:value}', 'value', Variable) + assertTextAndMarker('${1:value}', 'value', Placeholder) + assertTextAndMarker('${1:bar${2:foo}bar}', 'barfoobar', Placeholder) + + assertTextAndMarker('${name:value', '${name:value', Text) + assertTextAndMarker('${1:bar${2:foobar}', '${1:barfoobar', Text, Placeholder) + }) + + test('Parser, variable transforms', function() { + assertTextAndMarker('${foo///}', '', Variable) + assertTextAndMarker('${foo/regex/format/gmi}', '', Variable) + assertTextAndMarker('${foo/([A-Z][a-z])/format/}', '', Variable) + + // invalid regex + assertTextAndMarker('${foo/([A-Z][a-z])/format/GMI}', '${foo/([A-Z][a-z])/format/GMI}', Text) + assertTextAndMarker('${foo/([A-Z][a-z])/format/funky}', '${foo/([A-Z][a-z])/format/funky}', Text) + assertTextAndMarker('${foo/([A-Z][a-z]/format/}', '${foo/([A-Z][a-z]/format/}', Text) + + // tricky regex + assertTextAndMarker('${foo/m\\/atch/$1/i}', '', Variable) + assertMarker('${foo/regex\/format/options}', Text) + + // incomplete + assertTextAndMarker('${foo///', '${foo///', Text) + assertTextAndMarker('${foo/regex/format/options', '${foo/regex/format/options', Text) + + // format string + assertMarker('${foo/.*/${0:fooo}/i}', Variable) + assertMarker('${foo/.*/${1}/i}', Variable) + assertMarker('${foo/.*/$1/i}', Variable) + assertMarker('${foo/.*/This-$1-encloses/i}', Variable) + assertMarker('${foo/.*/complex${1:else}/i}', Variable) + assertMarker('${foo/.*/complex${1:-else}/i}', Variable) + assertMarker('${foo/.*/complex${1:+if}/i}', Variable) + assertMarker('${foo/.*/complex${1:?if:else}/i}', Variable) + assertMarker('${foo/.*/complex${1:/upcase}/i}', Variable) + + }) + + test('Parse, parse code block', () => { + assertText('aa \\`echo\\`', 'aa `echo`', true) + assertText('aa `xyz`', 'aa ', true) + assertText('aa `!v xyz`', 'aa ', true) + assertText('aa `!p xyz`', 'aa ', true) + assertText('aa `!p foo\nbar`', 'aa ', true) + const c = text => { + return (new SnippetParser(true)).parse(text) + } + assertMarker(c('`foo`'), CodeBlock) + assertMarker(c('`!v bar`'), CodeBlock) + assertMarker(c('`!p python`'), CodeBlock) + const assertPlaceholder = (text: string, kind: EvalKind, code: string) => { + let p = c(text).children[0] + assert.ok(p instanceof Placeholder) + let m = p.children[0] as CodeBlock + assert.ok(m instanceof CodeBlock) + assert.equal(m.kind, kind) + assert.equal(m.code, code) + } + assertPlaceholder('${1:` foo `}', 'shell', 'foo') + assertPlaceholder('${1:`!v bar`}', 'vim', 'bar') + assertPlaceholder('${1:`!p python`}', 'python', 'python') + assertPlaceholder('${1:`!p x\\`y`}', 'python', 'x\\`y') + assertPlaceholder('${1:`!p x\ny`}', 'python', 'x\ny') + assertPlaceholder('${1:`!p \nx\ny`}', 'python', 'x\ny') + }) + + test('Parser, CodeBlock toTextmateString', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + expect(c('`foo`').toTextmateString()).toBe('`foo`') + expect(c('`!p snip.rv`').toTextmateString()).toBe('`!p snip.rv`') + expect(c('`!v "var"`').toTextmateString()).toBe('`!v "var"`') + }) + + test('Parser, placeholder with CodeBlock primary', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${1/^_(.*)/$1/} $1 aa ${1:`!p snip.rv = "_foo"`}') + let arr = s.placeholders + arr = arr.filter(o => o.index == 1) + assert.equal(arr.length, 3) + let filtered = arr.filter(o => o.primary === true) + assert.equal(filtered.length, 1) + assert.equal(filtered[0], arr[2]) + let childs = arr.map(o => o.children[0]) + assert.ok(childs[0] instanceof Text) + assert.ok(childs[1] instanceof Text) + assert.ok(childs[2] instanceof CodeBlock) + }) + + test('Parser, placeholder with CodeBlock not primary', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${1/^_(.*)/$1/} ${1:_foo} ${2:bar} $1 $3 ${1:`!p snip.rv = "three"`}') + let arr = s.placeholders + arr = arr.filter(o => o.index == 1) + assert.equal(arr.length, 4) + assert.ok(arr[0].transform) + assert.equal(arr[1].primary, true) + assert.equal(arr[2].toString(), '_foo') + assert.equal(arr[3].toString(), '_foo') + assert.deepEqual(s.values, { '0': '', '1': '_foo', '2': 'bar', '3': '' }) + }) + + test('Parser, python CodeBlock with related', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${1:_foo} ${2:bar} $1 $3 ${3:`!p snip.rv = str(t[1]) + str(t[2])`}') + let b = s.pyBlocks[0] + expect(b).toBeDefined() + expect(b.related).toEqual([1, 2]) + }) + + test('Parser, python CodeBlock by sequence', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${2:\{${3:`!p foo`}\}} ${1:`!p bar`}') + let arr = s.pyBlocks + expect(arr[0].code).toBe('foo') + expect(arr[1].code).toBe('bar') + }) + + test('Parser, hasPython()', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + assert.equal(c('${1:`!p foo`}').hasPython, true) + assert.equal(c('`!p foo`').hasPython, true) + assert.equal(c('$1').hasPython, false) + }) + + test('Parser, hasCodeBlock()', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + assert.equal(c('${1:`!p foo`}').hasCodeBlock, true) + assert.equal(c('`!p foo`').hasCodeBlock, true) + assert.equal(c('$1').hasCodeBlock, false) + }) + + test('Parser, resolved variable', () => { + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${1:${VISUAL}} $1') + assert.ok(s.children[0] instanceof Placeholder) + assert.ok(s.children[0].children[0] instanceof Variable) + let v = s.children[0].children[0] as Variable + assert.equal(v.name, 'VISUAL') + }) + + test('Parser variable with code', () => { + // not allowed on ultisnips. + const c = text => { + return (new SnippetParser(true)).parse(text) + } + let s = c('${foo:`!p snip.rv = "bar"`}') + assert.ok(s.children[0] instanceof Variable) + assert.ok(s.children[0].children[0] instanceof CodeBlock) + }) + + test('Parser, transform condition if text', () => { + const p = new SnippetParser(true) + let snip = p.parse('begin|${1:t}${1/(t)$|(a)$|(.*)/(?1:abular)(?2:rray)/}') + expect(snip.toString()).toBe('begin|tabular') + let m = snip.placeholders.find(o => o.index == 1 && o.primary) + snip.resetMarker(m, 'a') + expect(snip.toString()).toBe('begin|array') + }) + + test('Parser, transform condition not match', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:xyz} ${1/^(f)(b?)/(?2:_:two)/}') + expect(snip.toString()).toBe('xyz xyz') + }) + + test('Parser, transform backslash in condition', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:foo} ${1/^(f)/(?1:x\\)\\:a:two)/}') + expect(snip.toString()).toBe('foo x):aoo') + }) + + test('Parser, transform backslash in format string', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:\\n} ${1/^(\\\\n)/$1aa/}') + expect(snip.toString()).toBe('\\n \\naa') + }) + + test('Parser, ultisnips transform replacement', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:foo} ${1/^\\w/$0_/}') + expect(snip.toString()).toBe('foo f_oo') + snip = p.parse('${1:foo} ${1/^\\w//}') + expect(snip.toString()).toBe('foo oo') + }) + + test('Parser, convert ultisnips regex', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:foo} ${1/^\\A/_/}') + expect(snip.toString()).toBe('foo _foo') + }) + + test('Parser, transform condition else text', () => { + const p = new SnippetParser(true) + let snip = p.parse('${1:foo} ${1/^(f)(b?)/(?2:_:two)/}') + expect(snip.toString()).toBe('foo twooo') + let m = snip.placeholders.find(o => o.index == 1 && o.primary) + snip.resetMarker(m, 'fb') + expect(snip.toString()).toBe('fb _') + }) + + test('Parser, transform escape sequence', () => { + const p = new SnippetParser(true) + const snip = p.parse('${1:a text}\n${1/\\w+\\s*/\\u$0/}') + expect(snip.toString()).toBe('a text\nA text') + }) + + test('Parser, transform backslash', () => { + const p = new SnippetParser(true) + const snip = p.parse('${1:a}\n${1/\\w+/\\(\\)\\:\\x\\\\y/}') + expect(snip.toString()).toBe('a\n():\\x\\\\y') + }) + + test('Parser, transform with ascii option', () => { + let p = new SnippetParser() + let snip = p.parse('${1:pêche}\n${1/.*/$0/a}') + expect(snip.toString()).toBe('pêche\npeche') + p = new SnippetParser() + snip = p.parse('${1/.*/$0/a}\n${1:pêche}') + expect(snip.toString()).toBe('peche\npêche') + }) + + test('Parser, placeholder with transform', () => { + const p = new SnippetParser() + const snippet = p.parse('${1:type}${1/(.+)/ /}') + let s = snippet.toString() + assert.equal(s.length, 5) + }) + + test('Parser, placeholder transforms', function() { + assertTextAndMarker('${1///}', '', Placeholder) + assertTextAndMarker('${1/regex/format/gmi}', '', Placeholder) + assertTextAndMarker('${1/([A-Z][a-z])/format/}', '', Placeholder) + assertTextAndMarker('${1///}', '', Placeholder) + + // tricky regex + assertTextAndMarker('${1/m\\/atch/$1/i}', '', Placeholder) + assertMarker('${1/regex\/format/options}', Text) + + // incomplete + assertTextAndMarker('${1///', '${1///', Text) + assertTextAndMarker('${1/regex/format/options', '${1/regex/format/options', Text) + }) + + test('No way to escape forward slash in snippet regex #36715', function() { + assertMarker('${TM_DIRECTORY/src\\//$1/}', Variable) + }) + + test('No way to escape forward slash in snippet format section #37562', function() { + assertMarker('${TM_SELECTED_TEXT/a/\\/$1/g}', Variable) + assertMarker('${TM_SELECTED_TEXT/a/in\\/$1ner/g}', Variable) + assertMarker('${TM_SELECTED_TEXT/a/end\\//g}', Variable) + }) + + test('Parser, placeholder with choice', () => { + + assertTextAndMarker('${1|one,two,three|}', 'one', Placeholder) + assertTextAndMarker('${1|one|}', 'one', Placeholder) + assertTextAndMarker('${1|one1,two2|}', 'one1', Placeholder) + assertTextAndMarker('${1|one1\\,two2|}', 'one1,two2', Placeholder) + assertTextAndMarker('${1|one1\\|two2|}', 'one1|two2', Placeholder) + assertTextAndMarker('${1|one1\\atwo2|}', 'one1\\atwo2', Placeholder) + assertTextAndMarker('${1|one,two,three,|}', '${1|one,two,three,|}', Text) + assertTextAndMarker('${1|one,', '${1|one,', Text) + + const p = new SnippetParser() + const snippet = p.parse('${1|one,two,three|}') + assertMarker(snippet, Placeholder) + const expected = [Placeholder, Text, Text, Text] + snippet.walk(marker => { + assert.equal(marker, expected.shift()) + return true + }) + }) + + test('Snippet choices: unable to escape comma and pipe, #31521', function() { + assertTextAndMarker('console.log(${1|not\\, not, five, 5, 1 23|});', 'console.log(not, not);', Text, Placeholder, Text) + }) + + test('Marker, toTextmateString()', function() { + + function assertTextsnippetString(input: string, expected: string): void { + const snippet = new SnippetParser().parse(input) + const actual = snippet.toTextmateString() + assert.equal(actual, expected) + } + + assertTextsnippetString('$1', '$1') + assertTextsnippetString('\\$1', '\\$1') + assertTextsnippetString('console.log(${1|not\\, not, five, 5, 1 23|});', 'console.log(${1|not\\, not, five, 5, 1 23|});') + assertTextsnippetString('console.log(${1|not\\, not, \\| five, 5, 1 23|});', 'console.log(${1|not\\, not, \\| five, 5, 1 23|});') + assertTextsnippetString('this is text', 'this is text') + assertTextsnippetString('this ${1:is ${2:nested with $var}}', 'this ${1:is ${2:nested with ${var}}}') + assertTextsnippetString('this ${1:is ${2:nested with $var}}}', 'this ${1:is ${2:nested with ${var}}}\\}') + }) + + test('Marker, toTextmateString() <-> identity', function() { + + function assertIdent(input: string): void { + // full loop: (1) parse input, (2) generate textmate string, (3) parse, (4) ensure both trees are equal + const snippet = new SnippetParser().parse(input) + const input2 = snippet.toTextmateString() + const snippet2 = new SnippetParser().parse(input2) + + function checkCheckChildren(marker1: Marker, marker2: Marker) { + assert.ok(marker1 instanceof Object.getPrototypeOf(marker2).constructor) + assert.ok(marker2 instanceof Object.getPrototypeOf(marker1).constructor) + + assert.equal(marker1.children.length, marker2.children.length) + assert.equal(marker1.toString(), marker2.toString()) + + for (let i = 0; i < marker1.children.length; i++) { + checkCheckChildren(marker1.children[i], marker2.children[i]) + } + } + + checkCheckChildren(snippet, snippet2) + } + + assertIdent('$1') + assertIdent('\\$1') + assertIdent('console.log(${1|not\\, not, five, 5, 1 23|});') + assertIdent('console.log(${1|not\\, not, \\| five, 5, 1 23|});') + assertIdent('this is text') + assertIdent('this ${1:is ${2:nested with $var}}') + assertIdent('this ${1:is ${2:nested with $var}}}') + assertIdent('this ${1:is ${2:nested with $var}} and repeating $1') + }) + + test('Parser, choice marker', () => { + const { placeholders } = new SnippetParser().parse('${1|one,two,three|}') + + assert.equal(placeholders.length, 1) + assert.ok(placeholders[0].choice instanceof Choice) + assert.ok(placeholders[0].children[0] instanceof Choice) + assert.equal((placeholders[0].children[0]).options.length, 3) + + assertText('${1|one,two,three|}', 'one') + assertText('\\${1|one,two,three|}', '${1|one,two,three|}') + assertText('${1\\|one,two,three|}', '${1\\|one,two,three|}') + assertText('${1||}', '${1||}') + }) + + test('Backslash character escape in choice tabstop doesn\'t work #58494', function() { + + const { placeholders } = new SnippetParser().parse('${1|\\,,},$,\\|,\\\\|}') + assert.equal(placeholders.length, 1) + assert.ok(placeholders[0].choice instanceof Choice) + }) + + test('Parser, only textmate', () => { + const p = new SnippetParser() + assertMarker(p.parse('far{{}}boo'), Text) + assertMarker(p.parse('far{{123}}boo'), Text) + assertMarker(p.parse('far\\{{123}}boo'), Text) + + assertMarker(p.parse('far$0boo'), Text, Placeholder, Text) + assertMarker(p.parse('far${123}boo'), Text, Placeholder, Text) + assertMarker(p.parse('far\\${123}boo'), Text) + }) + + test('Parser, real world', () => { + let marker = new SnippetParser().parse('console.warn(${1: $TM_SELECTED_TEXT })').children + + assert.equal(marker[0].toString(), 'console.warn(') + assert.ok(marker[1] instanceof Placeholder) + assert.equal(marker[2].toString(), ')') + + const placeholder = marker[1] + assert.equal(placeholder, false) + assert.equal(placeholder.index, '1') + assert.equal(placeholder.children.length, 3) + assert.ok(placeholder.children[0] instanceof Text) + assert.ok(placeholder.children[1] instanceof Variable) + assert.ok(placeholder.children[2] instanceof Text) + assert.equal(placeholder.children[0].toString(), ' ') + assert.equal(placeholder.children[1].toString(), '') + assert.equal(placeholder.children[2].toString(), ' ') + + const nestedVariable = placeholder.children[1] + assert.equal(nestedVariable.name, 'TM_SELECTED_TEXT') + assert.equal(nestedVariable.children.length, 0) + + marker = new SnippetParser().parse('$TM_SELECTED_TEXT').children + assert.equal(marker.length, 1) + assert.ok(marker[0] instanceof Variable) + }) + + test('Parser, transform example', () => { + let { children } = new SnippetParser().parse('${1:name} : ${2:type}${3/\\s:=(.*)/${1:+ :=}${1}/};\n$0') + + //${1:name} + assert.ok(children[0] instanceof Placeholder) + assert.equal(children[0].children.length, 1) + assert.equal(children[0].children[0].toString(), 'name') + assert.equal((children[0]).transform, undefined) + + // : + assert.ok(children[1] instanceof Text) + assert.equal(children[1].toString(), ' : ') + + //${2:type} + assert.ok(children[2] instanceof Placeholder) + assert.equal(children[2].children.length, 1) + assert.equal(children[2].children[0].toString(), 'type') + + //${3/\\s:=(.*)/${1:+ :=}${1}/} + assert.ok(children[3] instanceof Placeholder) + assert.equal(children[3].children.length, 1) + assert.notEqual((children[3]).transform, undefined) + let transform = (children[3]).transform + assert.equal(transform.regexp, '/\\s:=(.*)/') + assert.equal(transform.children.length, 2) + assert.ok(transform.children[0] instanceof FormatString) + assert.equal((transform.children[0]).index, 1) + assert.equal((transform.children[0]).ifValue, ' :=') + assert.ok(transform.children[1] instanceof FormatString) + assert.equal((transform.children[1]).index, 1) + assert.ok(children[4] instanceof Text) + assert.equal(children[4].toString(), ';\n') + + }) + + test('Parser, default placeholder values', () => { + + assertMarker('errorContext: `${1:err}`, error: $1', Text, Placeholder, Text, Placeholder) + + const [, p1, , p2] = new SnippetParser().parse('errorContext: `${1:err}`, error:$1').children + + assert.equal((p1).index, '1') + assert.equal((p1).children.length, '1') + assert.equal(((p1).children[0]), 'err') + + assert.equal((p2).index, '1') + assert.equal((p2).children.length, '1') + assert.equal(((p2).children[0]), 'err') + }) + + test('Parser, default placeholder values and one transform', () => { + + assertMarker('errorContext: `${1:err}`, error: ${1/err/ok/}', Text, Placeholder, Text, Placeholder) + + const [, p3, , p4] = new SnippetParser().parse('errorContext: `${1:err}`, error:${1/err/ok/}').children + + assert.equal((p3).index, '1') + assert.equal((p3).children.length, '1') + assert.equal(((p3).children[0]), 'err') + assert.equal((p3).transform, undefined) + + assert.equal((p4).index, '1') + assert.equal((p4).children.length, '1') + assert.equal(((p4).children[0]), 'ok') + assert.notEqual((p4).transform, undefined) + }) + + test('Repeated snippet placeholder should always inherit, #31040', function() { + assertText('${1:foo}-abc-$1', 'foo-abc-foo') + assertText('${1:foo}-abc-${1}', 'foo-abc-foo') + assertText('${1:foo}-abc-${1:bar}', 'foo-abc-foo') + assertText('${1}-abc-${1:foo}', 'foo-abc-foo') + }) + + test('backspace esapce in TM only, #16212', () => { + const actual = new SnippetParser().text('Foo \\\\${abc}bar') + assert.equal(actual, 'Foo \\bar') + }) + + test('colon as variable/placeholder value, #16717', () => { + let actual = new SnippetParser().text('${TM_SELECTED_TEXT:foo:bar}') + assert.equal(actual, 'foo:bar') + + actual = new SnippetParser().text('${1:foo:bar}') + assert.equal(actual, 'foo:bar') + }) + + test('incomplete placeholder', () => { + assertTextAndMarker('${1:}', '', Placeholder) + }) + + test('marker#len', () => { + + function assertLen(template: string, ...lengths: number[]): void { + const snippet = new SnippetParser().parse(template, true) + snippet.walk(m => { + const expected = lengths.shift() + assert.equal(m.len(), expected) + return true + }) + assert.equal(lengths.length, 0) + } + + assertLen('text$0', 4, 0) + assertLen('$1text$0', 0, 4, 0) + assertLen('te$1xt$0', 2, 0, 2, 0) + assertLen('errorContext: `${1:err}`, error: $0', 15, 0, 3, 10, 0) + assertLen('errorContext: `${1:err}`, error: $1$0', 15, 0, 3, 10, 0, 3, 0) + assertLen('$TM_SELECTED_TEXT$0', 0, 0) + assertLen('${TM_SELECTED_TEXT:def}$0', 0, 3, 0) + }) + + test('parser, parent node', function() { + let snippet = new SnippetParser().parse('This ${1:is ${2:nested}}$0', true) + + assert.equal(snippet.placeholders.length, 3) + let [first, second] = snippet.placeholders + assert.equal(first.index, '1') + assert.equal(second.index, '2') + assert.ok(second.parent === first) + assert.ok(first.parent === snippet) + + snippet = new SnippetParser().parse('${VAR:default${1:value}}$0', true) + assert.equal(snippet.placeholders.length, 2) + ;[first] = snippet.placeholders + assert.equal(first.index, '1') + + assert.ok(snippet.children[0] instanceof Variable) + assert.ok(first.parent === snippet.children[0]) + }) + + test('TextmateSnippet#enclosingPlaceholders', () => { + let snippet = new SnippetParser().parse('This ${1:is ${2:nested}}$0', true) + let [first, second] = snippet.placeholders + + assert.deepEqual(snippet.enclosingPlaceholders(first), []) + assert.deepEqual(snippet.enclosingPlaceholders(second), [first]) + }) + + test('TextmateSnippet#getTextBefore', () => { + let snippet = new SnippetParser().parse('This ${1:is ${2:nested}}$0', true) + expect(snippet.getTextBefore(snippet, undefined)).toBe('') + let [first, second] = snippet.placeholders + expect(snippet.getTextBefore(second, first)).toBe('is ') + snippet = new SnippetParser().parse('This ${1:foo ${2:is ${3:nested}}} $0', true) + let arr = snippet.placeholders + expect(snippet.getTextBefore(arr[2], arr[0])).toBe('foo is ') + }) + + test('TextmateSnippet#offset', () => { + let snippet = new SnippetParser().parse('te$1xt', true) + assert.equal(snippet.offset(snippet.children[0]), 0) + assert.equal(snippet.offset(snippet.children[1]), 2) + assert.equal(snippet.offset(snippet.children[2]), 2) + + snippet = new SnippetParser().parse('${TM_SELECTED_TEXT:def}', true) + assert.equal(snippet.offset(snippet.children[0]), 0) + assert.equal(snippet.offset((snippet.children[0]).children[0]), 0) + + // forgein marker + assert.equal(snippet.offset(new Text('foo')), -1) + }) + + test('TextmateSnippet#deleteText', () => { + let snippet = new SnippetParser().parse('foo ${1:bar}', true) + let res = snippet.deleteText(2, 2) + expect(res).toBe(true) + expect(snippet.toString()).toBe('fobar') + res = snippet.deleteText(2, 5) + expect(res).toBe(false) + }) + + test('TextmateSnippet#placeholder', () => { + let snippet = new SnippetParser().parse('te$1xt$0', true) + let placeholders = snippet.placeholders + assert.equal(placeholders.length, 2) + + snippet = new SnippetParser().parse('te$1xt$1$0', true) + placeholders = snippet.placeholders + assert.equal(placeholders.length, 3) + + + snippet = new SnippetParser().parse('te$1xt$2$0', true) + placeholders = snippet.placeholders + assert.equal(placeholders.length, 3) + + snippet = new SnippetParser().parse('${1:bar${2:foo}bar}$0', true) + placeholders = snippet.placeholders + assert.equal(placeholders.length, 3) + }) + + test('TextmateSnippet#replace 1/2', function() { + let snippet = new SnippetParser().parse('aaa${1:bbb${2:ccc}}$0', true) + + assert.equal(snippet.placeholders.length, 3) + const [, second] = snippet.placeholders + assert.equal(second.index, '2') + + const enclosing = snippet.enclosingPlaceholders(second) + assert.equal(enclosing.length, 1) + assert.equal(enclosing[0].index, '1') + let marker = snippet.placeholders.find(o => o.index == 2) + let nested = new SnippetParser().parse('ddd$1eee$0', true) + snippet.replace(marker, nested.children) + + assert.equal(snippet.toString(), 'aaabbbdddeee') + assert.equal(snippet.placeholders.length, 5) + }) + + test('TextmateSnippet#replace 2/2', function() { + let snippet = new SnippetParser().parse('aaa${1:bbb${2:ccc}}$0', true) + + assert.equal(snippet.placeholders.length, 3) + const [, second] = snippet.placeholders + assert.equal(second.index, '2') + + let nested = new SnippetParser().parse('dddeee$0', true) + snippet.replace(second, nested.children) + + assert.equal(snippet.toString(), 'aaabbbdddeee') + assert.equal(snippet.placeholders.length, 4) + }) + + test('TextmateSnippet#insertSnippet', function() { + let snippet = new SnippetParser().parse('${1:aaa} bbb ${2:ccc}}$0', true) + let marker = snippet.placeholders.find(o => o.index == 1) + snippet.insertSnippet('${1:dd} ${2:ff}', marker, ['', 'aaa']) + let arr = snippet.placeholders.map(p => p.index) + expect(arr).toEqual([1, 2, 3, 4, 5, 0]) + }) + + test('Maximum call stack size exceeded, #28983', function() { + new SnippetParser().parse('${1:${foo:${1}}}') + }) + + test('Snippet can freeze the editor, #30407', function() { + + const seen = new Set() + + seen.clear() + new SnippetParser().parse('class ${1:${TM_FILENAME/(?:\\A|_)([A-Za-z0-9]+)(?:\\.rb)?/(?2::\\u$1)/g}} < ${2:Application}Controller\n $3\nend').walk(marker => { + assert.ok(!seen.has(marker)) + seen.add(marker) + return true + }) + + seen.clear() + new SnippetParser().parse('${1:${FOO:abc$1def}}').walk(marker => { + assert.ok(!seen.has(marker)) + seen.add(marker) + return true + }) + }) + + test('Snippets: make parser ignore `${0|choice|}`, #31599', function() { + assertTextAndMarker('${0|foo,bar|}', '${0|foo,bar|}', Text) + assertTextAndMarker('${1|foo,bar|}', 'foo', Placeholder) + }) + + + test('Transform -> FormatString#resolve', function() { + + // shorthand functions + assert.equal(new FormatString(1, 'upcase').resolve('foo'), 'FOO') + assert.equal(new FormatString(1, 'downcase').resolve('FOO'), 'foo') + assert.equal(new FormatString(1, 'capitalize').resolve('bar'), 'Bar') + assert.equal(new FormatString(1, 'capitalize').resolve('bar no repeat'), 'Bar no repeat') + assert.equal(new FormatString(1, 'pascalcase').resolve('bar-foo'), 'BarFoo') + assert.equal(new FormatString(1, 'notKnown').resolve('input'), 'input') + + // if + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve(undefined), '') + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve(''), '') + assert.equal(new FormatString(1, undefined, 'foo', undefined).resolve('bar'), 'foo') + + // else + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve(undefined), 'foo') + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve(''), 'foo') + assert.equal(new FormatString(1, undefined, undefined, 'foo').resolve('bar'), 'bar') + + // if-else + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve(undefined), 'foo') + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve(''), 'foo') + assert.equal(new FormatString(1, undefined, 'bar', 'foo').resolve('baz'), 'bar') + }) + + test('Snippet variable transformation doesn\'t work if regex is complicated and snippet body contains \'$$\' #55627', function() { + const snippet = new SnippetParser().parse('const fileName = "${TM_FILENAME/(.*)\\..+$/$1/}"') + assert.equal(snippet.toTextmateString(), 'const fileName = "${TM_FILENAME/(.*)\\..+$/${1}/}"') + }) + + test('[BUG] HTML attribute suggestions: Snippet session does not have end-position set, #33147', function() { + + const { placeholders } = new SnippetParser().parse('src="$1"', true) + const [first, second] = placeholders + + assert.equal(placeholders.length, 2) + assert.equal(first.index, 1) + assert.equal(second.index, 0) + + }) + + test('Snippet optional transforms are not applied correctly when reusing the same variable, #37702', function() { + + const transform = new Transform() + transform.appendChild(new FormatString(1, 'upcase')) + transform.appendChild(new FormatString(2, 'upcase')) + transform.regexp = /^(.)|-(.)/g + + assert.equal(transform.resolve('my-file-name'), 'MyFileName') + + const clone = transform.clone() + assert.equal(clone.resolve('my-file-name'), 'MyFileName') + }) + + test('problem with snippets regex #40570', function() { + + const snippet = new SnippetParser().parse('${TM_DIRECTORY/.*src[\\/](.*)/$1/}') + assertMarker(snippet, Variable) + }) + + test('Variable transformation doesn\'t work if undefined variables are used in the same snippet #51769', function() { + let transform = new Transform() + transform.appendChild(new Text('bar')) + transform.regexp = new RegExp('foo', 'gi') + assert.equal(transform.toTextmateString(), '/foo/bar/ig') + }) + + test('Snippet parser freeze #53144', function() { + let snippet = new SnippetParser().parse('${1/(void$)|(.+)/${1:?-\treturn nil;}/}') + assertMarker(snippet, Placeholder) + }) + + test('snippets variable not resolved in JSON proposal #52931', function() { + assertTextAndMarker('FOO${1:/bin/bash}', 'FOO/bin/bash', Text, Placeholder) + }) + + test('Mirroring sequence of nested placeholders not selected properly on backjumping #58736', function() { + let snippet = new SnippetParser().parse('${3:nest1 ${1:nest2 ${2:nest3}}} $3') + assert.equal(snippet.children.length, 3) + assert.ok(snippet.children[0] instanceof Placeholder) + assert.ok(snippet.children[1] instanceof Text) + assert.ok(snippet.children[2] instanceof Placeholder) + + function assertParent(marker: Marker) { + marker.children.forEach(assertParent) + if (!(marker instanceof Placeholder)) { + return + } + let found = false + let m: Marker = marker + while (m && !found) { + if (m.parent === snippet) { + found = true + } + m = m.parent + } + assert.ok(found) + } + let [, , clone] = snippet.children + assertParent(clone) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/snippets/session.test.ts b/sources_non_forked/coc.nvim/src/__tests__/snippets/session.test.ts new file mode 100644 index 00000000..3fb7d96e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/snippets/session.test.ts @@ -0,0 +1,544 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { Position, Range } from 'vscode-languageserver-protocol' +import { UltiSnippetContext } from '../../snippets/eval' +import { shouldCancel, SnippetSession } from '../../snippets/session' +import window from '../../window' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +afterEach(async () => { + await helper.reset() +}) + +async function createSession(enableHighlight = false, preferComplete = false): Promise { + let doc = await workspace.document + return new SnippetSession(nvim, doc, enableHighlight, preferComplete) +} + +describe('SnippetSession', () => { + const defaultRange = Range.create(0, 0, 0, 0) + const defaultContext = { + line: '', + range: defaultRange + } + + async function start(inserted: string, range = defaultRange, select = true, context?: UltiSnippetContext): Promise { + await nvim.input('i') + let doc = await workspace.document + let session = new SnippetSession(nvim, doc) + return await session.start(inserted, range, select, context) + } + + async function getCursorRange(): Promise { + let pos = await window.getCursorPosition() + return Range.create(pos, pos) + } + + describe('start()', () => { + + it('should insert escaped text', async () => { + let res = await start('\\`a\\` \\$ \\{\\}', Range.create(0, 0, 0, 0), false, defaultContext) + expect(res).toBe(true) + let line = await nvim.line + expect(line).toBe('`a` $ {}') + }) + + it('should not start with plain snippet when jump to final placeholder', async () => { + let res = await start('bar$0', defaultRange) + expect(res).toBe(false) + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 3 }) + }) + + it('should start with range replaced', async () => { + await nvim.setLine('foo') + let res = await start('bar$0', Range.create(0, 0, 0, 3), true) + expect(res).toBe(false) + let line = await nvim.line + expect(line).toBe('bar') + }) + + it('should fix indent of next line when necessary', async () => { + let buf = await nvim.buffer + await nvim.setLine(' ab') + await nvim.input('i') + let session = await createSession() + let res = await session.start('${1:x}\n', Range.create(0, 3, 0, 3)) + expect(res).toBe(true) + let lines = await buf.lines + expect(lines).toEqual([' ax', ' b']) + }) + + it('should insert indent for snippet endsWith line break', async () => { + let buf = await nvim.buffer + await nvim.setLine(' bar') + await nvim.command('startinsert') + await nvim.call('cursor', [1, 3]) + let session = await createSession() + let res = await session.start('${1:foo}\n', Range.create(0, 2, 0, 2)) + expect(res).toBe(true) + let lines = await buf.lines + expect(lines).toEqual([' foo', ' bar']) + }) + + it('should start without select placeholder', async () => { + let session = await createSession() + let res = await session.start(' ${1:aa} ', defaultRange, false) + expect(res).toBe(true) + let { mode } = await nvim.mode + expect(mode).toBe('n') + await session.selectCurrentPlaceholder() + await helper.waitFor('mode', [], 's') + }) + + it('should start with variable selected', async () => { + let session = await createSession() + let res = await session.start('${foo:bar}', defaultRange, false) + expect(res).toBe(true) + let line = await nvim.getLine() + expect(line).toBe('bar') + await session.selectCurrentPlaceholder() + await helper.waitFor('mode', [], 's') + }) + + it('should select none transform placeholder', async () => { + await start('${1/..*/ -> /}xy$1', defaultRange) + let col = await nvim.call('col', '.') + expect(col).toBe(3) + }) + + it('should indent multiple lines variable text', async () => { + let buf = await nvim.buffer + let text = 'abc\n def' + await nvim.setVar('coc_selected_text', text) + await start('fun\n ${0:${TM_SELECTED_TEXT:return}}\nend') + let lines = await buf.lines + expect(lines.length).toBe(4) + expect(lines).toEqual([ + 'fun', ' abc', ' def', 'end' + ]) + }) + + it('should resolve VISUAL', async () => { + let text = 'abc' + await nvim.setVar('coc_selected_text', text) + await start('$VISUAL') + let line = await nvim.line + expect(line).toBe('abc') + }) + + it('should resolve default value of VISUAL', async () => { + await nvim.setVar('coc_selected_text', '') + await start('${VISUAL:foo}') + let line = await nvim.line + expect(line).toBe('foo') + }) + }) + + describe('nested snippet', () => { + it('should start with nest snippet', async () => { + let session = await createSession() + let res = await session.start('${1:a} ${2:b}', defaultRange, false) + let line = await nvim.getLine() + expect(line).toBe('a b') + expect(res).toBe(true) + let { placeholder } = session + expect(placeholder.index).toBe(1) + let r = await getCursorRange() + res = await session.start('${1:foo} ${2:bar}', r) + expect(res).toBe(true) + placeholder = session.placeholder + expect(placeholder.index).toBe(2) + line = await nvim.getLine() + expect(line).toBe('foo bara b') + expect(session.snippet.text).toBe('foo bara b') + await session.nextPlaceholder() + placeholder = session.placeholder + expect(placeholder.index).toBe(3) + expect(session.placeholder.value).toBe('bar') + let col = await nvim.call('col', ['.']) + expect(col).toBe(7) + await session.nextPlaceholder() + await session.nextPlaceholder() + expect(session.placeholder.index).toBe(5) + expect(session.placeholder.value).toBe('b') + }) + + it('should start nest snippet without select', async () => { + await nvim.command('startinsert') + let session = await createSession() + let res = await session.start('${1:a} ${2:b}', defaultRange) + let line = await nvim.call('getline', ['.']) + let r = await getCursorRange() + res = await session.start('${1:foo} ${2:bar}', r, false) + expect(res).toBe(true) + line = await nvim.line + expect(line).toBe('afoo bar b') + }) + }) + + describe('synchronize()', () => { + it('should synchronize content change', async () => { + let pyfile = path.join(__dirname, '../ultisnips.py') + await nvim.command(`execute 'pyxfile '.fnameescape('${pyfile}')`) + let session = await createSession(true) + await session.start('${1:foo}${2:`!p snip.rv = ""`} `!p snip.rv = t[1] + t[2]`', defaultRange, true, { + line: '', + range: defaultRange + }) + await nvim.input('b') + await helper.wait(20) + await nvim.input('a') + await helper.wait(30) + await nvim.input('r') + await helper.wait(40) + await session.forceSynchronize() + await helper.waitFor('getline', ['.'], 'bar bar') + }) + + it('should cancel when change after snippet', async () => { + let session = await createSession() + await nvim.setLine(' x') + await nvim.input('i') + await session.start('${1:foo }bar', defaultRange) + await nvim.setLine('foo bar y') + await session.forceSynchronize() + expect(session.isActive).toBe(false) + }) + + it('should cancel when change before and in snippet', async () => { + let session = await createSession() + await nvim.setLine(' x') + await nvim.input('i') + await session.start('${1:foo }bar', defaultRange) + await nvim.setLine('afoobar') + await session.forceSynchronize() + expect(session.isActive).toBe(false) + }) + + it('should reset position when change before snippet', async () => { + let session = await createSession() + await nvim.setLine('x') + await nvim.input('a') + let r = await getCursorRange() + await session.start('${1:foo} bar', r) + await nvim.setLine('yfoo bar') + await session.forceSynchronize() + expect(session.isActive).toBe(true) + let start = session.snippet.start + expect(start).toEqual(Position.create(0, 1)) + }) + + it('should cancel when before and body changed', async () => { + let session = await createSession() + await nvim.setLine('x') + await nvim.input('a') + await session.start('${1:foo }bar', defaultRange) + await nvim.setLine('yfoo bar') + await session.forceSynchronize() + expect(session.isActive).toBe(false) + }) + + it('should cancel when unable to find placeholder', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('${1:foo} bar', defaultRange) + await nvim.setLine('foodbar') + await session.forceSynchronize() + expect(session.isActive).toBe(false) + }) + + it('should cancel when unable to find removed Text', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('${1:foo} bar', defaultRange) + await nvim.setLine('fobar') + await session.forceSynchronize() + expect(session.isActive).toBe(false) + }) + + it('should adjust with removed text', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('${1:foo} bar$0', defaultRange) + await nvim.input('') + await nvim.call('cursor', [1, 5]) + await nvim.input('i') + await nvim.input('') + await session.forceSynchronize() + expect(session.isActive).toBe(true) + await session.nextPlaceholder() + let col = await nvim.call('col', ['.']) + expect(col).toBe(7) + }) + + it('should prefer range contains current cursor', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('$1 $2', defaultRange) + await nvim.input('A') + await nvim.input(' ') + await session.forceSynchronize() + expect(session.isActive).toBe(true) + let p = session.placeholder + expect(p.index).toBe(2) + }) + + it('should update cursor column after synchronize', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('${1} ${1:foo}', defaultRange) + await nvim.input('b') + await session.forceSynchronize() + let pos = await window.getCursorPosition() + expect(pos).toEqual(Position.create(0, 3)) + await nvim.input('a') + await session.forceSynchronize() + pos = await window.getCursorPosition() + expect(pos).toEqual(Position.create(0, 5)) + await nvim.input('') + await session.forceSynchronize() + pos = await window.getCursorPosition() + expect(pos).toEqual(Position.create(0, 3)) + }) + + it('should update cursor line after synchronize', async () => { + let buf = await nvim.buffer + let session = await createSession() + await nvim.input('i') + await session.start('${1} ${1:foo}', defaultRange) + await nvim.input('b') + await session.forceSynchronize() + let pos = await window.getCursorPosition() + expect(pos).toEqual(Position.create(0, 3)) + await nvim.input('') + await session.forceSynchronize() + expect(session.isActive).toBe(true) + pos = await window.getCursorPosition() + let lines = await buf.lines + expect(lines).toEqual(['b', ' b', '']) + expect(pos).toEqual(Position.create(2, 0)) + }) + }) + + describe('deactivate()', () => { + + it('should deactivate on cursor outside', async () => { + let buf = await nvim.buffer + let session = await createSession() + let res = await session.start('a${1:a}b', defaultRange) + expect(res).toBe(true) + await buf.append(['foo', 'bar']) + await nvim.call('cursor', [2, 1]) + await session.checkPosition() + expect(session.isActive).toBe(false) + }) + + it('should not throw when jump on deactivate session', async () => { + let session = await createSession() + session.deactivate() + await session.start('${1:foo} $0', defaultRange) + await session.selectPlaceholder(undefined, true) + await session.forceSynchronize() + await session.previousPlaceholder() + await session.nextPlaceholder() + }) + + it('should cancel keymap on jump final placeholder', async () => { + let session = await createSession() + await nvim.input('i') + await session.start('$0x${1:a}b$0', defaultRange) + let line = await nvim.line + expect(line).toBe('xab') + let map = await nvim.call('maparg', ['', 'i']) as string + expect(map).toMatch('coc#snippet#jump') + await session.nextPlaceholder() + map = await nvim.call('maparg', ['', 'i']) as string + expect(map).toBe('') + }) + }) + + describe('nextPlaceholder()', () => { + it('should not throw when session not activated', async () => { + let session = await createSession() + await session.start('${foo} ${bar}', defaultRange, false) + session.deactivate() + await session.nextPlaceholder() + await session.previousPlaceholder() + }) + + it('should jump to variable placeholder', async () => { + let session = await createSession() + await session.start('${foo} ${bar}', defaultRange, false) + await session.selectCurrentPlaceholder() + await session.nextPlaceholder() + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 6 }) + }) + + it('should jump to variable placeholder after number placeholder', async () => { + let session = await createSession() + await session.start('${foo} ${1:bar}', defaultRange, false) + await session.selectCurrentPlaceholder() + await session.nextPlaceholder() + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 2 }) + }) + + it('should jump to first placeholder', async () => { + let session = await createSession() + await session.start('${foo} ${foo} ${2:bar}', defaultRange, false) + await session.selectCurrentPlaceholder() + let pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 10 }) + await session.nextPlaceholder() + pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 2 }) + await session.nextPlaceholder() + pos = await window.getCursorPosition() + expect(pos).toEqual({ line: 0, character: 11 }) + }) + + it('should goto next placeholder', async () => { + let session = await createSession() + let res = await session.start('${1:a} ${2:b} c', defaultRange) + expect(res).toBe(true) + await session.nextPlaceholder() + let { placeholder } = session + expect(placeholder.index).toBe(2) + }) + + it('should jump to none transform placeholder', async () => { + let session = await createSession() + let res = await session.start('${1} ${2/^_(.*)/$2/}bar$2', defaultRange) + expect(res).toBe(true) + let line = await nvim.line + expect(line).toBe(' bar') + await session.nextPlaceholder() + let col = await nvim.call('col', '.') + expect(col).toBe(5) + }) + }) + + describe('previousPlaceholder()', () => { + + it('should goto previous placeholder', async () => { + let session = await createSession() + let res = await session.start('${1:foo} ${2:bar}', defaultRange) + expect(res).toBe(true) + await session.nextPlaceholder() + expect(session.placeholder.index).toBe(2) + await session.previousPlaceholder() + expect(session.placeholder.index).toBe(1) + }) + }) + + describe('highlights()', () => { + it('should add highlights', async () => { + let ns = await nvim.call('coc#highlight#create_namespace', ['snippets']) + let session = await createSession(true) + await session.start('${2:bar ${1:foo}} $2', defaultRange) + let buf = nvim.createBuffer(workspace.bufnr) + let markers = await buf.getExtMarks(ns, 0, -1, { details: true }) + expect(markers.length).toBe(2) + expect(markers[0][3].hl_group).toBe('CocSnippetVisual') + expect(markers[1][3].hl_group).toBe('CocSnippetVisual') + session.deactivate() + }) + }) + + describe('checkPosition()', () => { + + it('should cancel snippet if position out of range', async () => { + let session = await createSession() + await nvim.setLine('bar') + await session.start('${1:foo}', defaultRange) + await nvim.call('cursor', [1, 5]) + await session.checkPosition() + expect(session.isActive).toBe(false) + }) + + it('should not cancel snippet if position in range', async () => { + let session = await createSession() + await session.start('${1:foo}', defaultRange) + await nvim.call('cursor', [1, 3]) + await session.checkPosition() + expect(session.isActive).toBe(true) + }) + }) + + describe('findPlaceholder()', () => { + + it('should find current placeholder if possible', async () => { + let session = await createSession() + await session.start('${1:abc}${2:def}', defaultRange) + let placeholder = session.findPlaceholder(Range.create(0, 3, 0, 3)) + expect(placeholder.index).toBe(1) + }) + + it('should return null if placeholder not found', async () => { + let session = await createSession() + await session.start('${1:abc}xyz${2:def}', defaultRange) + let placeholder = session.findPlaceholder(Range.create(0, 4, 0, 4)) + expect(placeholder).toBeNull() + }) + }) + + describe('selectPlaceholder()', () => { + + it('should select range placeholder', async () => { + let session = await createSession() + await session.start('${1:abc}', defaultRange) + let mode = await nvim.mode + expect(mode.mode).toBe('s') + await nvim.input('') + let line = await nvim.line + expect(line).toBe('') + }) + + it('should select empty placeholder', async () => { + let session = await createSession() + await session.start('a ${1} ${2}', defaultRange) + let mode = await nvim.mode + expect(mode.mode).toBe('i') + let col = await nvim.call('col', '.') + expect(col).toBe(3) + }) + + it('should select choice placeholder', async () => { + await nvim.input('i') + let session = await createSession() + await session.start('${1|one,two,three|}', defaultRange) + let line = await nvim.line + expect(line).toBe('one') + await helper.waitPopup() + let val = await nvim.eval('g:coc#_context') as any + expect(val.start).toBe(0) + expect(val.candidates).toEqual(['one', 'two', 'three']) + }) + }) + + describe('shouldCancel()', () => { + it('should check cancel', async () => { + let doc = await helper.createDocument() + expect(shouldCancel(doc, Position.create(0, 0))).toBe(false) + await nvim.setLine('foo fo f') + await doc.synchronize() + await nvim.input('A') + await nvim.input('') + await helper.waitPopup() + expect(shouldCancel(doc, Position.create(0, 3))).toBe(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/snippets/snippet.test.ts b/sources_non_forked/coc.nvim/src/__tests__/snippets/snippet.test.ts new file mode 100644 index 00000000..c11cc93f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/snippets/snippet.test.ts @@ -0,0 +1,600 @@ +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { CancellationTokenSource } from 'vscode-languageserver-protocol' +import { Position, Range, TextEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import { LinesTextDocument } from '../../model/textdocument' +import { addPythonTryCatch, convertRegex, executePythonCode, UltiSnippetContext } from '../../snippets/eval' +import { Placeholder, TextmateSnippet } from '../../snippets/parser' +import { checkContentBefore, CocSnippet, getContentBefore, getEndPosition, getParts, normalizeSnippetString, reduceTextEdit, shouldFormat } from '../../snippets/snippet' +import { parseComments, parseCommentstring, SnippetVariableResolver } from '../../snippets/variableResolve' +import { UltiSnippetOption } from '../../types' +import workspace from '../../workspace' +import helper from '../helper' + +let nvim: Neovim +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim + let pyfile = path.join(__dirname, '../ultisnips.py') + await nvim.command(`execute 'pyxfile '.fnameescape('${pyfile}')`) +}) + +afterAll(async () => { + await helper.shutdown() +}) + +async function createSnippet(snippet: string, opts?: UltiSnippetOption, range = Range.create(0, 0, 0, 0), line = '') { + let resolver = new SnippetVariableResolver(nvim, workspace.workspaceFolderControl) + let snip = new CocSnippet(snippet, Position.create(0, 0), nvim, resolver) + let context: UltiSnippetContext + if (opts) context = { range, line, ...opts, } + await snip.init(context) + return snip +} + +function createTextDocument(text: string): LinesTextDocument { + return new LinesTextDocument('file://a', 'txt', 1, text.split('\n'), 1, true) +} + +describe('CocSnippet', () => { + async function assertResult(snip: string, resolved: string) { + let c = await createSnippet(snip, {}) + expect(c.text).toBe(resolved) + } + + async function assertPyxValue(code: string, res: any) { + let val = await nvim.call(`pyxeval`, code) as string + if (typeof res === 'number' || typeof res === 'string' || typeof res === 'boolean') { + expect(val).toBe(res) + } else if (res instanceof RegExp) { + expect(val).toMatch(res) + } else { + expect(val).toEqual(res) + } + } + + describe('resolveVariables()', () => { + it('should resolve uppercase variables', async () => { + let doc = await helper.createDocument() + let fsPath = URI.parse(doc.uri).fsPath + await assertResult('$TM_FILENAME', path.basename(fsPath)) + await assertResult('$TM_FILENAME_BASE', path.basename(fsPath, path.extname(fsPath))) + await assertResult('$TM_DIRECTORY', path.dirname(fsPath)) + await assertResult('$TM_FILEPATH', fsPath) + await nvim.call('setreg', ['""', 'foo']) + await assertResult('$YANK', 'foo') + await assertResult('$TM_LINE_INDEX', '0') + await assertResult('$TM_LINE_NUMBER', '1') + await nvim.setLine('foo') + await assertResult('$TM_CURRENT_LINE', 'foo') + await nvim.call('setreg', ['*', 'foo']) + await assertResult('$CLIPBOARD', 'foo') + let d = new Date() + await assertResult('$CURRENT_YEAR', d.getFullYear().toString()) + await assertResult('$NOT_EXISTS', 'NOT_EXISTS') + }) + + it('should resolve new VSCode variables', async () => { + let doc = await helper.createDocument() + await doc.buffer.setOption('comments', 's1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-') + await doc.buffer.setOption('commentstring', '') + let fsPath = URI.parse(doc.uri).fsPath + let c = await createSnippet('$RANDOM') + expect(c.text.length).toBe(6) + c = await createSnippet('$RANDOM_HEX') + expect(c.text.length).toBe(6) + c = await createSnippet('$UUID') + expect(c.text).toMatch('-') + c = await createSnippet('$RELATIVE_FILEPATH') + expect(c.text).toMatch(path.basename(fsPath)) + c = await createSnippet('$WORKSPACE_NAME') + expect(c.text.length).toBeGreaterThan(0) + c = await createSnippet('$WORKSPACE_FOLDER') + expect(c.text.length).toBeGreaterThan(0) + await assertResult('$LINE_COMMENT', '//') + await assertResult('$BLOCK_COMMENT_START', '/*') + await assertResult('$BLOCK_COMMENT_END', '*/') + await doc.buffer.setOption('comments', '') + await doc.buffer.setOption('commentstring', '// %s') + await assertResult('$LINE_COMMENT', '//') + await assertResult('$BLOCK_COMMENT_START', '') + await assertResult('$BLOCK_COMMENT_END', '') + }) + + it('should resolve variables in placeholders', async () => { + await nvim.setLine('foo') + await assertResult('$1 ${1:$TM_CURRENT_LINE}', 'foo foo') + await assertResult('$1 ${1:$TM_CURRENT_LINE bar}', 'foo bar foo bar') + await assertResult('$2 ${2:|${1:$TM_CURRENT_LINE}|}', '|foo| |foo|') + await assertResult('$1 $2 ${2:${1:|$TM_CURRENT_LINE|}}', '|foo| |foo| |foo|') + }) + + it('should resolve variables with default value', async () => { + await assertResult('$1 ${1:${VISUAL:foo}}', 'foo foo') + }) + + it('should resolve for lower case variables', async () => { + await assertResult('${foo:abcdef} ${bar}', 'abcdef bar') + await assertResult('${1:${foo:abcdef}} ${1/^\\w\\w(.*)/$1/}', 'abcdef cdef') + }) + }) + + describe('code block initialize', () => { + it('should init shell code block', async () => { + await assertResult('`echo "hello"` world', 'hello world') + }) + + it('should init vim block', async () => { + await assertResult('`!v eval("1 + 1")` = 2', '2 = 2') + await nvim.setLine(' ') + await assertResult('${1:`!v indent(".")`} "$1"', '2 "2"') + }) + + it('should init code block in placeholders', async () => { + await assertResult('f ${1:`echo "b"`}', 'f b') + await assertResult('f ${1:`!v "b"`}', 'f b') + await assertResult('f ${1:`!p snip.rv = "b"`}', 'f b') + }) + + it('should setup python globals', async () => { + await helper.edit('t.js') + await createSnippet('`!p snip.rv = fn`', {}) + await assertPyxValue('fn', 't.js') + await assertPyxValue('path', /t\.js$/) + await assertPyxValue('t', ['']) + await assertPyxValue('context', true) + await createSnippet('`!p snip.rv = fn`', { + regex: '[ab]', + context: 'False' + }, Range.create(0, 2, 0, 3), 'a b') + await assertPyxValue('context', false) + await assertPyxValue('match.group(0)', 'b') + }) + + it('should setup python match', async () => { + let c = await createSnippet('\\\\frac{`!p snip.rv = match.group(1)`}{$1}$0', { + regex: '((\\d+)|(\\d*)(\\\\)?([A-Za-z]+)((\\^|_)(\\{\\d+\\}|\\d))*)/', + context: 'True' + }, Range.create(0, 0, 0, 3), '20/') + await assertPyxValue('context', true) + await assertPyxValue('match.group(1)', '20') + expect(c.text).toBe('\\frac{20}{}') + }) + + it('should work with methods of snip', async () => { + await nvim.command('setl shiftwidth=4 ft=txt tabstop=4 expandtab') + await createSnippet('`!p snip.rv = "a"`', {}, Range.create(0, 4, 0, 8), ' abcd') + await executePythonCode(nvim, [ + 'snip.shift(1)', + // ultisnip indent only when there's '\n' in snip.rv + 'snip += ""', + 'newLine = snip.mkline("foo")' + ]) + await assertPyxValue('newLine', ' foo') + await executePythonCode(nvim, [ + 'snip.unshift(1)', + 'newLine = snip.mkline("b")' + ]) + await assertPyxValue('newLine', ' b') + await executePythonCode(nvim, [ + 'snip.shift(1)', + 'snip.reset_indent()', + 'newLine = snip.mkline("f")' + ]) + await assertPyxValue('newLine', ' f') + await executePythonCode(nvim, [ + 'fff = snip.opt("&fff", "foo")', + 'ft = snip.opt("&ft", "ft")', + ]) + await assertPyxValue('fff', 'foo') + await assertPyxValue('ft', 'txt') + }) + + it('should init python code block', async () => { + await assertResult('`!p snip.rv = "a"` = a', 'a = a') + await assertResult('`!p snip.rv = t[1]` = ${1:a}', 'a = a') + await assertResult('`!p snip.rv = t[1]` = ${1:`!v eval("\'a\'")`}', 'a = a') + await assertResult('`!p snip.rv = t[1] + t[2]` = ${1:a} ${2:b}', 'ab = a b') + }) + + it('should init python placeholder', async () => { + await assertResult('foo ${1/^\\|(.*)\\|$/$1/} ${1:|`!p snip.rv = "a"`|}', 'foo a |a|') + await assertResult('foo $1 ${1:`!p snip.rv = "a"`}', 'foo a a') + await assertResult('${1/^_(.*)/$1/} $1 aa ${1:`!p snip.rv = "_foo"`}', 'foo _foo aa _foo') + }) + + it('should init nested python placeholder', async () => { + await assertResult('${1:foo`!p snip.rv = t[2]`} ${2:bar} $1', 'foobar bar foobar') + await assertResult('${3:f${2:oo${1:b`!p snip.rv = "ar"`}}} `!p snip.rv = t[3]`', 'foobar foobar') + }) + + it('should recursive init python placeholder', async () => { + await assertResult('${1:`!p snip.rv = t[2]`} ${2:`!p snip.rv = t[3]`} ${3:`!p snip.rv = t[4][0]`} ${4:bar}', 'b b b bar') + await assertResult('${1:foo} ${2:`!p snip.rv = t[1][0]`} ${3:`!p snip.rv = ""`} ${4:`!p snip.rv = t[2]`}', 'foo f f') + }) + + it('should update python block from placeholder', async () => { + await assertResult('`!p snip.rv = t[1][0] if len(t[1]) > 0 else ""` ${1:`!p snip.rv = t[2]`} ${2:foo}', 'f foo foo') + }) + + it('should update nested placeholder values', async () => { + let c = await createSnippet('${2:foo ${1:`!p snip.rv = "bar"`}} ${2/^\\w//} `!p snip.rv = t[2]`', {}) + expect(c.text).toBe('foo bar oo bar foo bar') + }) + + }) + + describe('getContentBefore()', () => { + it('should get text before marker', async () => { + let c = await createSnippet('${1:foo} ${2:bar}', {}) + let markers = c.placeholders + let p = markers[0].parent + expect(p instanceof TextmateSnippet).toBe(true) + expect(getContentBefore(p)).toBe('') + expect(getContentBefore(markers[0])).toBe('') + expect(getContentBefore(markers[1])).toBe('foo ') + }) + + it('should get text before nested marker', async () => { + let c = await createSnippet('${1:foo} ${2:is nested with $4} $3 bar', {}) + let markers = c.placeholders as Placeholder[] + let p = markers.find(o => o.index == 4) + expect(getContentBefore(p)).toBe('foo is nested with ') + p = markers.find(o => o.index == 0) + expect(getContentBefore(p)).toBe('foo is nested with bar') + }) + + it('should consider normal line break', async () => { + let c = await createSnippet('${1:foo}\n${2:is nested with $4}', {}) + let markers = c.placeholders as Placeholder[] + let p = markers.find(o => o.index == 4) + expect(getContentBefore(p)).toBe('is nested with ') + }) + + it('should consider line break after update', async () => { + let c = await createSnippet('${1:foo} ${2}', {}) + let p = c.getPlaceholder(1) + await c.tmSnippet.update(nvim, p.marker, 'abc\ndef') + let markers = c.placeholders as Placeholder[] + let placeholder = markers.find(o => o.index == 2) + expect(getContentBefore(placeholder)).toBe('def ') + }) + }) + + describe('getSortedPlaceholders()', () => { + it('should get sorted placeholders', async () => { + const assert = (snip: CocSnippet, index: number | undefined, indexes: number[]) => { + let curr = index == null ? undefined : snip.getPlaceholder(index) + let res = snip.getSortedPlaceholders(curr) + expect(res.map(o => o.index)).toEqual(indexes) + } + let c = await createSnippet('${1:foo} ${2/^\\w//} ${2:bar} ', {}) + assert(c, undefined, [1, 2, 0]) + assert(c, 1, [1, 2, 0]) + assert(c, 2, [2, 1, 0]) + }) + }) + + describe('getNewText()', () => { + it('should getNewText for placeholder', async () => { + let c = await createSnippet('before ${1:foo} after$2', {}) + let p = c.getPlaceholder(1) + expect(c.getNewText(p, `fff`)).toBe(undefined) + expect(c.getNewText(p, `before foo `)).toBe(undefined) + expect(c.getNewText(p, `before foo afteralll`)).toBe(undefined) + expect(c.getNewText(p, `before bar after`)).toBe('bar') + p = c.getPlaceholder(2) + expect(c.getNewText(p, `before foo afterbar`)).toBe('bar') + }) + }) + + describe('updatePlaceholder()', () => { + async function assertUpdate(text: string, value: string, result: string, index = 1): Promise { + let c = await createSnippet(text, {}) + let p = c.getPlaceholder(index) + expect(p != null).toBe(true) + await c.tmSnippet.update(nvim, p.marker, value) + expect(c.tmSnippet.toString()).toBe(result) + return c + } + + it('should work with snip.c', async () => { + let code = [ + '#ifndef ${1:`!p', + 'if not snip.c:', + ' import random, string', + " name = re.sub(r'[^A-Za-z0-9]+','_', snip.fn).upper()", + " rand = ''.join(random.sample(string.ascii_letters+string.digits, 8))", + " snip.rv = ('%s_%s' % (name,rand)).upper()", + "else:", + " snip.rv = snip.c + t[2]`}", + '#define $1', + '$2' + ].join('\n') + let c = await createSnippet(code, {}) + let first = c.text.split('\n')[0] + let p = c.getPlaceholder(2) + expect(p).toBeDefined() + await c.tmSnippet.update(nvim, p.marker, 'foo') + let t = c.tmSnippet.toString() + expect(t.startsWith(first)).toBe(true) + expect(t.split('\n').map(s => s.endsWith('foo'))).toEqual([true, true, true]) + }) + + it('should calculate delta', async () => { + // TODO + }) + + it('should update variable placeholders', async () => { + await assertUpdate('${foo} ${foo}', 'bar', 'bar bar') + await assertUpdate('${foo} ${foo:x}', 'bar', 'bar bar') + await assertUpdate('${1:${foo:x}} $1', 'bar', 'bar bar') + }) + + it('should update placeholder with code blocks', async () => { + await assertUpdate('${1:`echo "foo"`} $1', 'bar', 'bar bar') + await assertUpdate('${2:${1:`echo "foo"`}} $2', 'bar', 'bar bar') + await assertUpdate('${1:`!v "foo"`} $1', 'bar', 'bar bar') + await assertUpdate('${1:`!p snip.rv = "foo"`} $1', 'bar', 'bar bar') + }) + + it('should update related python blocks', async () => { + // multiple + await assertUpdate('`!p snip.rv = t[1]` ${1:`!p snip.rv = "foo"`} `!p snip.rv = t[1]`', 'bar', 'bar bar bar') + // parent + await assertUpdate('`!p snip.rv = t[2]` ${2:foo ${1:`!p snip.rv = "foo"`}}', 'bar', 'foo bar foo bar') + // related placeholders + await assertUpdate('${2:foo `!p snip.rv = t[1]`} ${1:`!p snip.rv = "foo"`}', 'bar', 'foo bar bar') + }) + + it('should update python code blocks with normal placeholder values', async () => { + await assertUpdate('`!p snip.rv = t[1]` $1 `!p snip.rv = t[1]`', 'bar', 'bar bar bar') + await assertUpdate('`!p snip.rv = t[2]` ${2:foo $1}', 'bar', 'foo bar foo bar') + await assertUpdate('${2:foo `!p snip.rv = t[1]`} $1', 'bar', 'foo bar bar') + }) + + it('should reset values for removed placeholders', async () => { + // Keep remained placeholder this is same behavior of VSCode. + let s = await assertUpdate('${2:bar${1:foo}} $2 $1', 'bar', 'bar bar foo', 2) + let prev = s.getPrevPlaceholder(2) + expect(prev).toBeDefined() + expect(prev.value).toBe('foo') + // python placeholder, reset to empty value + await assertUpdate('${2:bar${1:foo}} $2 `!p snip.rv = t[1]`', 'bar', 'bar bar ', 2) + // not reset since $1 still exists + await assertUpdate('${2:bar${1:foo}} $2 $1 `!p snip.rv = t[1]`', 'bar', 'bar bar foo foo', 2) + }) + }) + + describe('getRanges()', () => { + it('should get ranges of placeholder', async () => { + let c = await createSnippet('${2:${1:x} $1}\n$2', {}) + let p = c.getPlaceholder(1) + let arr = c.getRanges(p) + expect(arr.length).toBe(4) + expect(arr[0]).toEqual(Range.create(0, 0, 0, 1)) + expect(arr[1]).toEqual(Range.create(0, 2, 0, 3)) + expect(arr[2]).toEqual(Range.create(1, 0, 1, 1)) + expect(arr[3]).toEqual(Range.create(1, 2, 1, 3)) + expect(c.text).toBe('x x\nx x') + }) + }) + + describe('insertSnippet()', () => { + it('should update indexes of python blocks', async () => { + let c = await createSnippet('${1:a} ${2:b} ${3:`!p snip.rv=t[2]`}', {}) + let p = c.getPlaceholder(1) + await c.insertSnippet(p, '${1:foo} ${2:bar}', ['', '']) + expect(c.text).toBe('foo bar b b') + p = c.getPlaceholder(5) + expect(p.after).toBe(' b') + let source = new CancellationTokenSource() + let res = await c.updatePlaceholder(p, Position.create(0, 9), 'xyz', source.token) + expect(res.text).toBe('foo bar xyz xyz') + }) + + it('should insert nested placeholder', async () => { + let c = await createSnippet('${1:foo}\n$1', {}) + let p = c.getPlaceholder(1) + let marker = await c.insertSnippet(p, '${1:x} $1', ['', '']) as Placeholder + p = c.getPlaceholder(marker.index) + let source = new CancellationTokenSource() + let res = await c.updatePlaceholder(p, Position.create(0, 3), 'bar', source.token) + expect(res.text).toBe('bar bar\nbar bar') + expect(res.delta).toEqual(Position.create(0, 0)) + }) + + it('should insert nested python snippet', async () => { + let c = await createSnippet('${1:foo}\n`!p snip.rv = t[1]`', {}) + let p = c.getPlaceholder(1) + let line = await nvim.line + let marker = await c.insertSnippet(p, '${1:x} `!p snip.rv = t[1]`', ['', ''], { line, range: Range.create(0, 0, 0, 3) }) as Placeholder + p = c.getPlaceholder(marker.index) + expect(c.text).toBe('x x\nx x') + let source = new CancellationTokenSource() + let res = await c.updatePlaceholder(p, Position.create(0, 1), 'bar', source.token) + expect(res.text).toBe('bar bar\nbar bar') + await executePythonCode(nvim, [`snip = ContextSnippet()`]) + let val = await nvim.call('pyxeval', 'snip.last_placeholder.current_text') + expect(val).toBe('foo') + }) + + it('should insert python snippet to normal snippet', async () => { + let c = await createSnippet('${1:foo}\n$1', {}) + let p = c.getPlaceholder(1) + expect(c.hasPython).toBe(false) + let marker = await c.insertSnippet(p, '${1:x} `!p snip.rv = t[1]`', ['', ''], { line: '', range: Range.create(0, 0, 0, 3) }) as Placeholder + p = c.getPlaceholder(marker.index) + expect(c.text).toBe('x x\nx x') + let source = new CancellationTokenSource() + let res = await c.updatePlaceholder(p, Position.create(0, 1), 'bar', source.token) + expect(res.text).toBe('bar bar\nbar bar') + expect(c.hasPython).toBe(true) + }) + + it('should not change match for original placeholders', async () => { + let c = await createSnippet('`!p snip.rv = match.group(1)` $1', { + regex: '^(\\w+)' + }, Range.create(0, 0, 0, 3), 'foo') + let p = c.getPlaceholder(1) + expect(c.hasPython).toBe(true) + expect(c.text).toBe('foo ') + await c.insertSnippet(p, '`!p snip.rv = match.group(1)`', ['', ''], { + regex: '^(\\w+)', + line: 'bar', + range: Range.create(0, 0, 0, 3) + }) + expect(c.text).toBe('foo bar') + }) + }) + + describe('utils', () => { + function assertThrow(fn: () => void) { + let err + try { + fn() + } catch (e) { + err = e + } + expect(err).toBeDefined() + } + + it('should check shouldFormat', () => { + expect(shouldFormat(' f')).toBe(true) + expect(shouldFormat('a\nb')).toBe(true) + expect(shouldFormat('foo')).toBe(false) + }) + + it('should normalizeSnippetString', () => { + expect(normalizeSnippetString('a\n\n\tb', ' ', { + insertSpaces: true, + tabSize: 2 + })).toBe('a\n\n b') + expect(normalizeSnippetString('a\n\n b', '\t', { + insertSpaces: false, + tabSize: 2 + })).toBe('a\n\n\t\tb') + }) + + it('should throw for invalid regex', async () => { + assertThrow(() => { + convertRegex('\\z') + }) + assertThrow(() => { + convertRegex('(?s)') + }) + assertThrow(() => { + convertRegex('(?x)') + }) + assertThrow(() => { + convertRegex('a\nb') + }) + assertThrow(() => { + convertRegex('(<)?(\\w+@\\w+(?:\\.\\w+)+)(?(1)>|$)') + }) + assertThrow(() => { + convertRegex('(<)?(\\w+@\\w+(?:\\.\\w+)+)(?(1)>|)') + }) + }) + + it('should convert regex', async () => { + // \\A + expect(convertRegex('\\A')).toBe('^') + expect(convertRegex('f(?#abc)b')).toBe('fb') + expect(convertRegex('f(?Pdef)b')).toBe('f(?def)b') + expect(convertRegex('f(?P=abc)b')).toBe('f\\kb') + }) + + it('should catch error with executePythonCode', async () => { + let fn = async () => { + await executePythonCode(nvim, ['INVALID_CODE']) + } + await expect(fn()).rejects.toThrow(Error) + }) + + it('should set error with addPythonTryCatch', async () => { + let code = addPythonTryCatch('INVALID_CODE', true) + await nvim.command(`pyx ${code}`) + let msg = await nvim.getVar('errmsg') + expect(msg).toBeDefined() + expect(msg).toMatch('INVALID_CODE') + }) + + it('should parse comments', async () => { + expect(parseCommentstring('a%sb')).toBeUndefined() + expect(parseCommentstring('// %s')).toBe('//') + expect(parseComments('')).toEqual({ + start: undefined, + end: undefined, + single: undefined + }) + expect(parseComments('s:/*')).toEqual({ + start: '/*', + end: undefined, + single: undefined + }) + expect(parseComments('e:*/')).toEqual({ + end: '*/', + start: undefined, + single: undefined + }) + expect(parseComments(':#,:b')).toEqual({ + end: undefined, + start: undefined, + single: '#' + }) + }) + + it('should reduce TextEdit', () => { + let e: TextEdit + e = TextEdit.replace(Range.create(0, 0, 0, 3), 'foo') + expect(reduceTextEdit(e, '')).toEqual(e) + e = TextEdit.replace(Range.create(0, 0, 0, 3), 'foo\nbar') + expect(reduceTextEdit(e, 'bar')).toEqual( + TextEdit.replace(Range.create(0, 0, 0, 0), 'foo\n') + ) + e = TextEdit.replace(Range.create(0, 0, 0, 3), 'foo\nbar') + expect(reduceTextEdit(e, 'foo')).toEqual( + TextEdit.replace(Range.create(0, 3, 0, 3), '\nbar') + ) + e = TextEdit.replace(Range.create(0, 0, 0, 3), 'def') + expect(reduceTextEdit(e, 'daf')).toEqual( + TextEdit.replace(Range.create(0, 1, 0, 2), 'e') + ) + e = TextEdit.replace(Range.create(2, 0, 3, 0), 'ascii ascii bar\n') + expect(reduceTextEdit(e, 'xyz ascii bar\n')).toEqual( + TextEdit.replace(Range.create(2, 0, 2, 3), 'ascii') + ) + }) + + it('should get new end position', () => { + let assert = (pos: Position, oldText: string, newText: string, res: Position) => { + expect(getEndPosition(pos, createTextDocument(oldText), createTextDocument(newText))).toEqual(res) + } + assert(Position.create(0, 0), 'foo', 'bar', undefined) + assert(Position.create(0, 0), 'foo\nbar', 'bar', undefined) + assert(Position.create(0, 0), 'foo\nbar', 'x\nfoo\nba', undefined) + assert(Position.create(0, 0), 'foo\nbar', 'x\nfoo\nbar', Position.create(1, 0)) + assert(Position.create(0, 0), 'foo', 'foo', Position.create(0, 0)) + }) + + it('should check content before position', () => { + let assert = (pos: Position, oldText: string, newText: string, res: boolean) => { + expect(checkContentBefore(pos, createTextDocument(oldText), createTextDocument(newText))).toBe(res) + } + assert(Position.create(1, 0), 'foo\nbar', 'foo', true) + assert(Position.create(1, 1), 'foo\nbar', 'foo', false) + assert(Position.create(2, 0), 'foo\nbar\n', 'foo', false) + assert(Position.create(1, 1), 'foo\nbar', 'foo\nbd', true) + assert(Position.create(1, 1), 'foo\nbar', 'foo\nab', false) + assert(Position.create(1, 1), 'foo\nbar', 'aoo\nbb', false) + }) + + it('should getParts by range', async () => { + expect(getParts('abcdef', Range.create(1, 5, 1, 11), Range.create(1, 6, 1, 10))).toEqual(['a', 'f']) + expect(getParts('abc\nfoo\ndef', Range.create(0, 5, 2, 3), Range.create(1, 1, 1, 2))).toEqual(['abc\nf', 'o\ndef']) + expect(getParts('abc\ndef', Range.create(0, 1, 2, 3), Range.create(0, 1, 2, 3))).toEqual(['', '']) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/snippets/string.test.ts b/sources_non_forked/coc.nvim/src/__tests__/snippets/string.test.ts new file mode 100644 index 00000000..cfbadda9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/snippets/string.test.ts @@ -0,0 +1,78 @@ +import { SnippetString } from '../../snippets/string' + +describe('SnippetString', () => { + describe('Append', () => { + it('should append plain snippets', () => { + let snippetString = new SnippetString('foo') + expect(snippetString.value).toBe('foo') + + snippetString = new SnippetString().appendText('foo') + expect(snippetString.value).toBe('foo') + }) + + it('should append tabstop', () => { + let snippetString = new SnippetString() + .appendTabstop() + .appendText(' ') + .appendTabstop() + .appendText(' ') + .appendTabstop(4) + .appendText(' ') + .appendTabstop(3) + + expect(snippetString.value).toBe('$1 $2 $4 $3') + }) + + it('should append placeholder', () => { + let snippetString = new SnippetString() + .appendPlaceholder('abcdef') + .appendText(' ') + .appendPlaceholder('foo') + .appendText(' ') + .appendPlaceholder('bar', 4) + .appendText(' ') + .appendPlaceholder('a', 3) + .appendText(' ') + .appendPlaceholder(s => { + s.appendText('plain') + }, 5) + + expect(snippetString.value).toBe('${1:abcdef} ${2:foo} ${4:bar} ${3:a} ${5:plain}') + }) + + it('should append choice', () => { + let snippetString = new SnippetString() + .appendChoice(['foo', 'bar']) + .appendText(' ') + .appendChoice(['foo3', 'bar3'], 3) + .appendText(' ') + .appendChoice(['foo2', 'bar2'], 2) + + expect(snippetString.value).toBe('${1|foo,bar|} ${3|foo3,bar3|} ${2|foo2,bar2|}') + }) + + it('should append variables', () => { + let snippetString = new SnippetString() + .appendVariable('foo', 'abcdef') + .appendText(' ') + .appendVariable('bar') + + expect(snippetString.value).toBe('${foo:abcdef} ${bar}') + + snippetString = new SnippetString() + .appendVariable('foo', s => s.appendText('abcdef')) + .appendText(' ') + .appendVariable('bar') + + expect(snippetString.value).toBe('${foo:abcdef} ${bar}') + }) + }) + + describe('isSnippetString()', () => { + let snippetString = new SnippetString() + expect(SnippetString.isSnippetString(snippetString)).toBe(true) + + let snippetStr = '' + expect(SnippetString.isSnippetString(snippetStr)).toBe(false) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/tree/basicProvider.test.ts b/sources_non_forked/coc.nvim/src/__tests__/tree/basicProvider.test.ts new file mode 100644 index 00000000..5d81429b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/tree/basicProvider.test.ts @@ -0,0 +1,541 @@ +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import { TreeItemCollapsibleState } from '../../tree' +import commandsManager from '../../commands' +import BasicDataProvider, { TreeNode } from '../../tree/BasicDataProvider' +import { disposeAll } from '../../util' + +let disposables: Disposable[] = [] + +type NodeDef = [string, NodeDef[]?] + +interface CustomNode extends TreeNode { + kind?: string + x?: number + y?: number +} + +afterEach(async () => { + disposeAll(disposables) + disposables = [] +}) + +function createNode(label: string, children?: TreeNode[], key?: string, tooltip?: string): CustomNode { + let res: TreeNode = { label } + if (children) res.children = children + if (tooltip) res.tooltip = tooltip + if (key) res.key = key + return res +} + +let defaultDef: NodeDef[] = [ + ['a', [['c'], ['d']]], + ['b', [['e'], ['f']]], + ['g'] +] + +function createLabels(data: ReadonlyArray): string[] { + let res: string[] = [] + const addLabels = (n: TreeNode, level: number) => { + res.push(' '.repeat(level) + n.label) + if (n.children) { + for (let node of n.children) { + addLabels(node, level + 1) + } + } + } + for (let item of data || []) { + addLabels(item, 0) + } + return res +} + +function findNode(label: string, nodes: ReadonlyArray): TreeNode | undefined { + for (let n of nodes) { + if (n.label == label) { + return n + } + let children = n.children + if (Array.isArray(children)) { + let find = findNode(label, children) + if (find) return find + } + } +} + +function createNodes(defs: NodeDef[]): TreeNode[] { + return defs.map(o => { + let children + if (Array.isArray(o[1])) { + children = createNodes(o[1]) + } + return createNode(o[0], children) + }) +} + +describe('BasicDataProvider', () => { + describe('getChildren()', () => { + it('should get children from root', async () => { + let nodes = createNodes(defaultDef) + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + let res = await provider.getChildren() + expect(res.length).toBe(3) + expect(res.map(o => o.label)).toEqual(['a', 'b', 'g']) + }) + + it('should get children from child node', async () => { + let provider = new BasicDataProvider({ + provideData: () => { + return createNodes(defaultDef) + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let nodes = await provider.getChildren(res[0]) + expect(nodes.length).toBe(2) + expect(nodes.map(o => o.label)).toEqual(['c', 'd']) + }) + + it('should throw when provideData throws', async () => { + let provider = new BasicDataProvider({ + provideData: () => { + throw new Error('my error') + } + }) + disposables.push(provider) + let err + try { + await provider.getChildren() + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + }) + + describe('getTreeItem()', () => { + it('should get tree item from node', async () => { + let provider = new BasicDataProvider({ + provideData: () => { + return createNodes(defaultDef) + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let item = provider.getTreeItem(res[0]) + expect(item).toBeDefined() + expect(item.collapsibleState).toBe(TreeItemCollapsibleState.Collapsed) + item = provider.getTreeItem(res[2]) + expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None) + }) + + it('should respect expandLevel option', async () => { + let provider = new BasicDataProvider({ + expandLevel: 1, + provideData: () => { + return createNodes(defaultDef) + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let item = provider.getTreeItem(res[0]) + expect(item).toBeDefined() + expect(item.collapsibleState).toBe(TreeItemCollapsibleState.Expanded) + }) + + it('should include highlights', async () => { + let provider = new BasicDataProvider({ + provideData: () => { + return [createNode('a', [], undefined, 'tip')] + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let item = provider.getTreeItem(res[0]) + expect(item).toBeDefined() + expect(item.tooltip).toBe('tip') + }) + + it('should use icon from node', async () => { + let node = createNode('a', [], undefined, 'tip') + node.icon = { + text: 'i', + hlGroup: 'Function' + } + let provider = new BasicDataProvider({ + provideData: () => { + return [node] + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let item = provider.getTreeItem(res[0]) + expect(item).toBeDefined() + expect(item.icon).toBeDefined() + expect(item.icon).toEqual({ + text: 'i', + hlGroup: 'Function' + }) + }) + + it('should resolve icon', async () => { + let provider = new BasicDataProvider({ + provideData: () => { + let node = createNode('a', [], undefined, 'tip') + node.kind = 'function' + return [node] + }, + resolveIcon: item => { + if (item.kind === 'function') { + return { + text: 'f', + hlGroup: 'Function' + } + } + } + }) + disposables.push(provider) + let res = await provider.getChildren() + let item = provider.getTreeItem(res[0]) + expect(item).toBeDefined() + expect(item.icon).toEqual({ + text: 'f', + hlGroup: 'Function' + }) + }) + }) + + describe('getParent()', () => { + it('should get undefined when data does not exist', async () => { + let node = createNode('a') + let provider = new BasicDataProvider({ + provideData: () => { + return [node] + } + }) + disposables.push(provider) + let res = provider.getParent(node) + expect(res).toBeUndefined() + }) + + it('should get parent node', async () => { + let node = createNode('g') + let provider = new BasicDataProvider({ + provideData: () => { + return [ + createNode('a', [createNode('c', [node]), createNode('d')]), + createNode('b', [createNode('e'), createNode('f')]), + createNode('g') + ] + } + }) + disposables.push(provider) + await provider.getChildren() + let res = provider.getParent(node) + expect(res).toBeDefined() + expect(res.label).toBe('c') + // console.log(provider.labels.join('\n')) + }) + }) + + describe('resolveTreeItem()', () => { + it('should resolve tooltip and command', async () => { + let node = createNode('a') + let provider = new BasicDataProvider({ + provideData: () => { + return [node] + }, + resolveItem: item => { + item.tooltip = 'tip' + item.command = { + command: 'test command', + title: 'test' + } + return item + } + }) + disposables.push(provider) + await provider.getChildren() + let source = new CancellationTokenSource() + let item = provider.getTreeItem(node) + let resolved = await provider.resolveTreeItem(item, node, source.token) + expect(resolved.tooltip).toBe('tip') + expect(resolved.command.command).toBe('test command') + }) + + it('should register command invoke click', async () => { + let node = createNode('a') + let called: TreeNode + let provider = new BasicDataProvider({ + provideData: () => { + return [node] + }, + handleClick: item => { + called = item + } + }) + disposables.push(provider) + await provider.getChildren() + let source = new CancellationTokenSource() + let item = provider.getTreeItem(node) + let resolved = await provider.resolveTreeItem(item, node, source.token) + expect(resolved.command).toBeDefined() + expect(resolved.command.command).toMatch('invoke') + await commandsManager.execute(resolved.command) + expect(called).toBeDefined() + expect(called).toBe(node) + }) + }) + + describe('update()', () => { + it('should add children with event', async () => { + let defs: NodeDef[] = [ + ['a', [['b']]], + ['b', [['f']]] + ] + let nodes = createNodes(defs) + let b = nodes[0].children[0] + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let called = false + provider.onDidChangeTreeData(node => { + expect(node).toBe(b) + called = true + }) + let newDefs: NodeDef[] = [ + ['a', [['b', [['c'], ['d']]]]], + ['b', [['f']]] + ] + let curr = provider.update(createNodes(newDefs)) + let labels = createLabels(curr) + expect(labels).toEqual([ + 'a', ' b', ' c', ' d', 'b', ' f' + ]) + expect(called).toBe(true) + expect(b.children).toBeDefined() + expect(b.children.length).toBe(2) + }) + + it('should remove children with event', async () => { + let defs: NodeDef[] = [ + ['a', [['b', [['c'], ['d']]]]], + ['e', [['f']]] + ] + let nodes = createNodes(defs) + let b = nodes[0].children[0] + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let called = false + provider.onDidChangeTreeData(node => { + expect(node).toBe(b) + called = true + }) + let newDefs: NodeDef[] = [ + ['a', [['b']]], + ['e', [['f']]] + ] + let curr = provider.update(createNodes(newDefs)) + let labels = createLabels(curr) + expect(labels).toEqual([ + 'a', ' b', 'e', ' f' + ]) + expect(called).toBe(true) + expect(b.children).toBeUndefined() + }) + + it('should not fire event for children when parent have changed', async () => { + let defs: NodeDef[] = [ + ['a', [['b', [['c'], ['d']]]]] + ] + let nodes = createNodes(defs) + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let called = 0 + provider.onDidChangeTreeData(node => { + expect(node).toBeUndefined() + called += 1 + }) + let newDefs: NodeDef[] = [ + ['a', [['b', [['c'], ['d'], ['g']]]]], + ['e', [['f']]] + ] + let curr = provider.update(createNodes(newDefs)) + expect(called).toBe(1) + let labels = createLabels(curr) + expect(labels).toEqual([ + 'a', ' b', ' c', ' d', ' g', 'e', ' f' + ]) + }) + + it('should fire events for independent node change', async () => { + let defs: NodeDef[] = [ + ['a', [['b', [['c']]]]], + ['e', [['f']]] + ] + let nodes = createNodes(defs) + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let called = [] + provider.onDidChangeTreeData(node => { + called.push(node) + }) + let newDefs: NodeDef[] = [ + ['a', [['b', [['c'], ['d']]]]], + ['e', [['f', [['g']]]]] + ] + let curr = provider.update(createNodes(newDefs)) + expect(called.length).toBe(2) + expect(called[0].label).toBe('b') + expect(called[1].label).toBe('f') + let labels = createLabels(curr) + expect(labels).toEqual([ + 'a', ' b', ' c', ' d', 'e', ' f', ' g' + ]) + }) + + it('should apply new properties', async () => { + let defs: NodeDef[] = [ + ['a', [['b']]], + ['e', [['f']]] + ] + let nodes = createNodes(defs) + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let newNodes = createNodes([ + ['a', [['b', [['c']]]]], + ['e', [['f', [['g']]]]] + ]) + let b = newNodes[0].children[0] + Object.assign(b, { x: 1, y: 2 }) + let curr = provider.update(newNodes) + let node = curr[0].children[0] + expect(node).toBeDefined() + expect(node.x).toBe(1) + expect(node.y).toBe(2) + }) + + it('should keep references and have new data sequence', async () => { + let defs: NodeDef[] = [ + ['a', [['b'], ['c']]], + ['e', [['f']]], + ['g'] + ] + let nodes = createNodes(defs) + let keeps = [ + findNode('a', nodes), + findNode('b', nodes), + findNode('c', nodes), + findNode('e', nodes), + findNode('f', nodes), + ] + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let newNodes = createNodes([ + ['a', [['c', [['d'], ['h']]], ['b']]], + ['e', [['f', [['j']]], ['i']]] + ]) + let curr = provider.update(newNodes) + expect(curr).toBe(nodes) + expect(keeps[0]).toBe(findNode('a', curr)) + expect(keeps[1]).toBe(findNode('b', curr)) + expect(keeps[2]).toBe(findNode('c', curr)) + expect(keeps[3]).toBe(findNode('e', curr)) + expect(keeps[4]).toBe(findNode('f', curr)) + let labels = createLabels(curr) + expect(labels).toEqual([ + 'a', ' c', ' d', ' h', ' b', 'e', ' f', ' j', ' i' + ]) + }) + + it('should use key for nodes', async () => { + let nodes = [ + createNode('a', [], 'x'), + createNode('a', [], 'y'), + createNode('a', [], 'z'), + ] + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let newNodes = [ + createNode('a', [], 'x'), + createNode('a', [], 'z'), + ] + let curr = provider.update(newNodes) + expect(curr.length).toBe(2) + expect(curr[0].key).toBe('x') + expect(curr[1].key).toBe('z') + }) + + it('should reset data', async () => { + let nodes = [ + createNode('a', [], 'x'), + ] + let provider = new BasicDataProvider({ + provideData: () => { + return nodes + } + }) + disposables.push(provider) + await provider.getChildren() + let newNodes = [ + createNode('a', [], 'x'), + ] + let curr = provider.update(newNodes, true) + expect(curr === nodes).toBe(false) + }) + }) + + describe('dispose', () => { + it('should invoke onDispose from opts', async () => { + let called = false + let provider = new BasicDataProvider({ + provideData: () => { + return [] + }, + onDispose: () => { + called = true + } + }) + provider.dispose() + expect(called).toBe(true) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/tree/treeView.test.ts b/sources_non_forked/coc.nvim/src/__tests__/tree/treeView.test.ts new file mode 100644 index 00000000..0c9249a9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/tree/treeView.test.ts @@ -0,0 +1,1176 @@ +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events from '../../events' +import { TreeViewOptions } from '../../tree' +import BasicDataProvider, { ProviderOptions, TreeNode } from '../../tree/BasicDataProvider' +import { TreeItem } from '../../tree/TreeItem' +import TreeView from '../../tree/TreeView' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import helper from '../helper' + +type NodeDef = [string, NodeDef[]?] + +let nvim: Neovim +let disposables: Disposable[] = [] +let treeView: TreeView +let provider: BasicDataProvider +let nodes: TreeNode[] +beforeAll(async () => { + await helper.setup() + nvim = helper.nvim +}) + +afterAll(async () => { + await helper.shutdown() +}) + +beforeEach(async () => { + await helper.createDocument() +}) + +afterEach(async () => { + if (provider) provider.dispose() + if (treeView) treeView.dispose() + disposeAll(disposables) + await helper.reset() +}) + +function createNode(label: string, children?: TreeNode[], key?: string, tooltip?: string): TreeNode { + let res: TreeNode = { label } + if (children) res.children = children + if (tooltip) res.tooltip = tooltip + if (key) res.key = key + return res +} + +function createNodes(defs: NodeDef[]): TreeNode[] { + return defs.map(o => { + let children + if (Array.isArray(o[1])) { + children = createNodes(o[1]) + } + return createNode(o[0], children) + }) +} + +function createTreeView(defs: NodeDef[], opts: Partial> = {}, providerOpts: Partial> = {}) { + nodes = createNodes(defs) + provider = new BasicDataProvider(Object.assign(providerOpts, { + provideData: () => { + return nodes + } + })) + treeView = new TreeView('test', Object.assign(opts, { + bufhidden: 'hide', + treeDataProvider: provider + })) +} + +function updateData(defs: NodeDef[], reset = false) { + nodes = createNodes(defs) + provider.update(nodes, reset) +} + +function makeUpdateUIThrowError() { + (treeView as any).updateUI = () => { + throw new Error('Test error') + } +} + +let defaultDef: NodeDef[] = [ + ['a', [['c'], ['d']]], + ['b', [['e'], ['f']]], + ['g'] +] + +async function checkLines(arr: string[]): Promise { + let lines = await nvim.call('getline', [1, '$']) + expect(lines).toEqual(arr) +} + +describe('TreeView', () => { + describe('TreeItem()', () => { + it('should create TreeItem from resourceUri', async () => { + let item = new TreeItem(URI.file('/foo/bar.ts')) + expect(item.resourceUri).toBeDefined() + expect(item.label).toBe('bar.ts') + expect(item.label).toBeDefined() + }) + }) + + describe('show()', () => { + it('should show with title', async () => { + createTreeView(defaultDef) + expect(treeView).toBeDefined() + await treeView.show() + let visible = treeView.visible + expect(visible).toBe(true) + await helper.wait(50) + await checkLines(['test', '+ a', '+ b', ' g']) + }) + + it('should not show when visible', async () => { + createTreeView(defaultDef) + await treeView.show() + let windowId = treeView.windowId + await treeView.show() + expect(treeView.windowId).toBe(windowId) + }) + + it('should reuse window', async () => { + createTreeView(defaultDef) + await treeView.show() + let windowId = treeView.windowId + await helper.wait(50) + provider.dispose() + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + expect(treeView.windowId).toBe(windowId) + }) + + it('should render item icon', async () => { + createTreeView(defaultDef) + nodes[0].icon = { text: 'i', hlGroup: 'Title' } + nodes[1].icon = { text: 'i', hlGroup: 'Title' } + nodes[2].icon = { text: 'i', hlGroup: 'Title' } + await treeView.show() + await helper.wait(50) + await checkLines(['test', '+ i a', '+ i b', ' i g']) + }) + }) + + describe('configuration', () => { + afterAll(() => { + let { configurations } = workspace + configurations.updateUserConfig({ + 'tree.openedIcon': '-', + 'tree.closedIcon': '+', + }) + }) + + it('should change open close icon', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + let { configurations } = workspace + configurations.updateUserConfig({ + 'tree.openedIcon': '', + 'tree.closedIcon': '', + }) + await helper.wait(50) + await checkLines(['test', ' a', ' b', ' g']) + }) + }) + + describe('attach events', () => { + function waitVisibilityEvent(visible: boolean): Promise { + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + disposable.dispose() + reject('event not fired after 2s') + }, 2000) + let disposable = treeView.onDidChangeVisibility(e => { + clearTimeout(timer) + expect(e.visible).toBe(visible) + disposable.dispose() + resolve(undefined) + }) + }) + } + + it('should emit visibility change event', async () => { + createTreeView(defaultDef) + let p = waitVisibilityEvent(true) + await treeView.show() + await p + nvim.command('close', true) + await waitVisibilityEvent(false) + p = waitVisibilityEvent(true) + await treeView.show() + await p + nvim.command('enew', true) + await waitVisibilityEvent(false) + p = waitVisibilityEvent(true) + await treeView.show() + await p + }) + + it('should dispose on tab close', async () => { + await nvim.command('tabe') + createTreeView(defaultDef) + await treeView.show() + await nvim.command('close') + await nvim.command('normal! 1gt') + await nvim.command('tabonly') + await helper.waitValue(() => { + return treeView.valid + }, false) + }) + }) + + describe('public properties', () => { + it('should change title', async () => { + createTreeView(defaultDef) + treeView.title = 'foo' + await treeView.show() + await events.race(['TextChanged']) + await checkLines(['foo', '+ a', '+ b', ' g']) + treeView.title = 'bar' + await events.race(['TextChanged']) + await checkLines(['bar', '+ a', '+ b', ' g']) + treeView.title = undefined + await events.race(['TextChanged']) + }) + + it('should change description', async () => { + createTreeView(defaultDef) + treeView.description = 'desc' + await treeView.show() + await events.race(['TextChanged']) + await checkLines(['test desc', '+ a', '+ b', ' g']) + treeView.description = 'foo bar' + await events.race(['TextChanged']) + await checkLines(['test foo bar', '+ a', '+ b', ' g']) + treeView.description = '' + await events.race(['TextChanged']) + await checkLines(['test', '+ a', '+ b', ' g']) + }) + + it('should change message', async () => { + createTreeView(defaultDef) + treeView.message = 'hello' + await treeView.show() + await events.race(['TextChanged']) + await checkLines(['hello', '', 'test', '+ a', '+ b', ' g']) + treeView.message = 'foo' + await events.race(['TextChanged']) + await checkLines(['foo', '', 'test', '+ a', '+ b', ' g']) + treeView.message = undefined + await events.race(['TextChanged']) + await checkLines(['test', '+ a', '+ b', ' g']) + }) + }) + + describe('options', () => { + it('should disable winfixwidth', async () => { + createTreeView(defaultDef, { winfixwidth: false }) + await treeView.show() + let res = await nvim.eval('&winfixwidth') + expect(res).toBe(0) + }) + + it('should disable leaf indent', async () => { + createTreeView(defaultDef, { disableLeafIndent: true }) + await treeView.show() + await events.race(['TextChanged']) + await checkLines(['test', '+ a', '+ b', 'g']) + }) + + it('should should adjust window width', async () => { + let def: NodeDef[] = [ + ['a', [['c'], ['d']]], + ['very long line'] + ] + createTreeView(def, { autoWidth: true }) + await treeView.show('belowright 10vs') + await events.race(['TextChanged']) + let width = await nvim.call('winwidth', [0]) + expect(width).toBeGreaterThan(10) + }) + + it('should support many selection', async () => { + createTreeView(defaultDef, { canSelectMany: true }) + await treeView.show() + await events.race(['TextChanged']) + let selection: TreeNode[] + treeView.onDidChangeSelection(e => { + selection = e.selection + }) + await nvim.command('exe 1') + await nvim.input('') + await helper.wait(10) + await nvim.command('exe 2') + await nvim.input('') + await helper.wait(50) + expect(selection.length).toBe(1) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + expect(selection.length).toBe(2) + await nvim.input('') + await helper.wait(50) + expect(selection.length).toBe(1) + let buf = await nvim.buffer + let res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + let signs = res[0].signs + expect(treeView.selection.length).toBe(1) + expect(signs.length).toBe(1) + expect(signs[0]).toEqual({ + lnum: 2, + id: 3001, + name: 'CocTreeSelected', + priority: 10, + group: 'CocTree' + }) + }) + }) + + describe('key-mappings', () => { + it('should jump back by ', async () => { + let winid = await nvim.call('win_getid') + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + let win = await nvim.window + expect(win.id).toBe(winid) + }) + + it('should toggle selection by ', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + let selection: TreeNode[] + treeView.onDidChangeSelection(e => { + selection = e.selection + }) + await nvim.command('exe 1') + await nvim.input('') + await helper.wait(10) + await nvim.command('exe 2') + await nvim.input('') + await helper.wait(50) + expect(selection.length).toBe(1) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + let buf = await nvim.buffer + let res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + let signs = res[0].signs + expect(treeView.selection.length).toBe(1) + expect(signs.length).toBe(1) + expect(signs[0]).toEqual({ + lnum: 3, + id: 3002, + name: 'CocTreeSelected', + priority: 10, + group: 'CocTree' + }) + await nvim.input('') + await helper.wait(50) + res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + signs = res[0].signs + expect(signs.length).toBe(0) + }) + + it('should reset signs after expand & collapse', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', + '- a', + ' c', + ' d', + '+ b', + ' g', + ]) + await nvim.command('exe 3') + await nvim.input('') + await helper.wait(50) + let buf = await nvim.buffer + let res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + expect(res[0].signs.length).toBe(1) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + expect(res[0].signs.length).toBe(0) + await nvim.input('t') + await helper.wait(100) + res = await nvim.call('sign_getplaced', [buf.id, { group: 'CocTree' }]) + expect(res[0].signs.length).toBe(1) + }) + + it('should close tree view by ', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + expect(treeView.visible).toBe(true) + await nvim.input('') + await helper.wait(50) + expect(treeView.visible).toBe(false) + }) + + it('should invoke command by ', async () => { + let node: TreeNode + createTreeView(defaultDef, {}, { + handleClick: n => { + node = n + } + }) + await treeView.show() + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + expect(node).toBeUndefined() + await nvim.command('exe 2') + await nvim.input('') + await helper.wait(50) + expect(node.label).toBe('a') + }) + + it('should not throw when resolve command cancelled', async () => { + let node: TreeNode + let cancelled = false + createTreeView(defaultDef, {}, { + handleClick: n => { + node = n + }, + resolveItem: (item, _node, token) => { + return new Promise(resolve => { + let timer = setTimeout(() => { + item.command = { + title: 'not exists', + command: 'test' + } + resolve(item) + }, 5000) + token.onCancellationRequested(() => { + cancelled = true + clearTimeout(timer) + resolve(item) + }) + }) + } + }) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('') + await helper.wait(50) + await nvim.command('exe 1') + await helper.wait(50) + expect(cancelled).toBe(true) + expect(node).toBeUndefined() + }) + + it('should toggle expand by t', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + c.children = [createNode('h')] + await treeView.show() + await helper.wait(50) + await nvim.command('exe 1') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 3') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', '- a', ' + c', ' d', '- b', ' e', ' f', ' g' + ]) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', '+ a', '- b', ' e', ' f', ' g' + ]) + }) + + it('should should collapse parent node by t', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', + '- a', + ' c', + ' d', + '+ b', + ' g', + ]) + await nvim.command('exe 3') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', + '+ a', + '+ b', + ' g', + ]) + }) + + it('should collapse all nodes by M', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + c.children = [createNode('h')] + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 3') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 6') + await nvim.input('t') + await helper.wait(50) + await checkLines([ + 'test', + '- a', + ' - c', + ' h', + ' d', + '- b', + ' e', + ' f', + ' g', + ]) + await nvim.input('M') + await helper.wait(50) + await checkLines([ + 'test', + '+ a', + '+ b', + ' g', + ]) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should toggle expand on open/close icon click ', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.call('cursor', [1, 1]) + await nvim.input('') + await helper.wait(50) + await nvim.call('cursor', [2, 1]) + await nvim.input('') + await helper.wait(50) + await checkLines([ + 'test', + '- a', + ' c', + ' d', + '+ b', + ' g', + ]) + await nvim.input('') + await helper.wait(50) + await checkLines([ + 'test', + '+ a', + '+ b', + ' g', + ]) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should invoke command on node click', async () => { + let node: TreeNode + createTreeView(defaultDef, {}, { + handleClick: n => { + node = n + } + }) + await treeView.show() + await helper.wait(50) + await nvim.call('cursor', [2, 3]) + await nvim.input('') + await helper.wait(50) + expect(node).toBeDefined() + expect(node.label).toBe('a') + }) + }) + + describe('invokeActions', () => { + it('should show warning when resolveActions does not exist', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.call('cursor', [2, 3]) + await nvim.input('') + await helper.wait(50) + let cmdline = await helper.getCmdline() + expect(cmdline).toMatch('No actions') + }) + + it('should show warning when resolveActions is empty', async () => { + createTreeView(defaultDef, {}, { + resolveActions: () => { + return [] + } + }) + await treeView.show() + await helper.wait(50) + await nvim.call('cursor', [2, 3]) + await nvim.input('') + await helper.wait(50) + let cmdline = await helper.getCmdline() + expect(cmdline).toMatch('No actions') + }) + + it('should invoke selected action', async () => { + let args: any[] + let called = false + createTreeView(defaultDef, {}, { + resolveActions: (item, element) => { + args = [item, element] + return [{ + title: 'one', + handler: () => { + called = true + } + }] + } + }) + await treeView.show() + await events.race(['TextChanged'], 200) + await nvim.call('cursor', [2, 3]) + await nvim.input('') + await helper.waitFloat() + await nvim.input('') + await helper.wait(50) + expect(called).toBe(true) + expect(args[0].label).toBe('a') + expect(args[1].label).toBe('a') + }) + }) + + describe('events', () => { + it('should emit visibility change on buffer unload', async () => { + createTreeView(defaultDef) + let visible + treeView.onDidChangeVisibility(e => { + visible = e.visible + }) + await treeView.show() + await helper.wait(50) + let buf = await nvim.buffer + nvim.command(`bd! ${buf.id}`, true) + await helper.wait(50) + expect(visible).toBe(false) + }) + + it('should show tooltip on CursorHold', async () => { + createTreeView(defaultDef, {}, { + resolveItem: (item, node) => { + if (node.label == 'a') { + item.tooltip = 'first' + } + if (node.label == 'b') { + item.tooltip = { kind: 'markdown', value: '#title' } + } + return item + } + }) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + let bufnr = await nvim.eval(`bufnr('%')`) as number + await events.fire('CursorHold', [bufnr]) + let win = await helper.getFloat() + expect(win).toBeDefined() + let buf = await win.buffer + let lines = await buf.lines + expect(lines).toEqual(['first']) + await helper.wait(50) + await nvim.command('exe 3') + await events.fire('CursorHold', [bufnr]) + lines = await buf.lines + expect(lines).toEqual(['#title']) + }) + }) + + describe('data change', () => { + it('should ignore hidden node change', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + let tick = await nvim.eval('b:changedtick') + updateData([ + ['a', [['c', [['h']]], ['d']]], + ['b', [['e'], ['f']]], + ['g'] + ]) + await helper.wait(50) + let curr = await nvim.eval('b:changedtick') + expect(curr).toBe(tick) + }) + + it('should render all nodes on root change', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + updateData([ + ['g'], + ['h'], + ['b', [['e'], ['f']]], + ['a', [['c'], ['d']]] + ]) + await helper.wait(50) + await checkLines([ + 'test', + ' g', + ' h', + '+ b', + '+ a', + ]) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should keep node open state', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + c.children = [createNode('h')] + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 3') + await nvim.input('t') + await helper.wait(50) + await nvim.command('exe 6') + await nvim.input('t') + await helper.wait(50) + updateData([ + ['h'], + ['g', [['i']]], + ['b', [['f']]], + ['a', [['c'], ['j']]] + ]) + await helper.wait(50) + await checkLines([ + 'test', + ' h', + '+ g', + '- b', + ' f', + '- a', + ' c', + ' j', + ]) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should render changed nodes', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + updateData([ + ['a', [['h', [['i']]], ['d']]], + ['b', [['e'], ['f']]], + ['g'], + ]) + await helper.wait(50) + await checkLines([ + 'test', + '- a', + ' + h', + ' d', + '+ b', + ' g', + ]) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should error message on error', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await nvim.command('exe 2') + await nvim.input('t') + await helper.wait(50) + let msg = 'Unable to fetch children' + provider.getChildren = () => { + throw new Error(msg) + } + updateData([['a']]) + await helper.wait(50) + let line = await nvim.call('getline', [1]) + expect(line).toMatch(msg) + let res = await treeView.checkLines() + expect(res).toBe(true) + }) + + it('should show error message on refresh error', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + makeUpdateUIThrowError() + updateData([ + ['a', [['h'], ['d']]], + ['b', [['e'], ['f']]], + ['g'], + ]) + await helper.wait(50) + let line = await helper.getCmdline() + expect(line).toMatch('Error on tree refresh') + }) + + it('should render deprecated node with deprecated highlight', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + let defs: NodeDef[] = [ + ['a'], + ['b'] + ] + let nodes = createNodes(defs) + nodes[0].deprecated = true + provider.update(nodes) + await helper.wait(50) + await checkLines([ + 'test', + ' a', + ' b', + ]) + let ns = await nvim.call('coc#highlight#create_namespace', ['tree']) + let bufnr = await nvim.call('bufnr', ['%']) + let markers = await nvim.call('nvim_buf_get_extmarks', [bufnr, ns, [1, 0], [1, -1], { details: true }]) as any[] + expect(markers.length > 0).toBe(true) + expect(markers[0][3]['hl_group']).toBe('CocDeprecatedHighlight') + }) + }) + + describe('focusItem()', () => { + it('should not throw when node not rendered', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + let c = nodes[0].children[0] + treeView.focusItem(c) + }) + + it('should focus rendered node', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + treeView.focusItem(nodes[1]) + await helper.wait(50) + let line = await nvim.call('getline', ['.']) + expect(line).toBe('+ b') + }) + }) + + describe('reveal()', () => { + it('should throw error when getParent does not exist', async () => { + createTreeView(defaultDef) + provider.getParent = undefined + await treeView.show() + await helper.wait(50) + let err + try { + await treeView.reveal(nodes[0].children[0]) + } catch (e) { + err = e + } + expect(err).toBeDefined() + }) + + it('should select item', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + let h = createNode('h') + c.children = [h] + await treeView.show() + await helper.wait(50) + await treeView.reveal(h) + await checkLines([ + 'test', + '- a', + ' - c', + ' h', + ' d', + '+ b', + ' g', + ]) + let selection = treeView.selection + expect(selection.length).toBe(1) + expect(selection[0].label).toBe('h') + let line = await nvim.call('getline', ['.']) + expect(line).toMatch('h') + }) + + it('should not select item', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await treeView.reveal(nodes[1], { select: false }) + let lnum = await nvim.call('line', ['.']) + expect(lnum).toBe(1) + }) + + it('should focus item', async () => { + createTreeView(defaultDef) + await treeView.show() + await helper.wait(50) + await treeView.reveal(nodes[1], { focus: true }) + let line = await nvim.call('getline', ['.']) + expect(line).toMatch('b') + }) + + it('should expand item whih single level', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + c.children = [createNode('h')] + await treeView.show() + await helper.wait(50) + await treeView.reveal(nodes[0], { expand: true }) + await checkLines([ + 'test', + '- a', + ' + c', + ' d', + '+ b', + ' g', + ]) + }) + + it('should expand item whih 2 level', async () => { + createTreeView(defaultDef) + let c = nodes[0].children[0] + c.children = [createNode('h')] + await treeView.show() + await helper.wait(50) + await treeView.reveal(nodes[0], { expand: 2 }) + await checkLines([ + 'test', + '- a', + ' - c', + ' h', + ' d', + '+ b', + ' g', + ]) + }) + }) + + describe('filter', () => { + async function createFilterTreeView(opts: Partial> = {}): Promise { + createTreeView(defaultDef, { enableFilter: true }, opts) + await treeView.show() + await helper.wait(50) + await nvim.input('f') + await helper.wait(50) + } + + it('should start filter by input', async () => { + await createFilterTreeView() + await checkLines([ + 'test', ' ', ' a', ' c', ' d', ' b', ' e', ' f', ' g' + ]) + await nvim.input('a') + await helper.wait(50) + await checkLines([ + 'test', + 'a ', + ' a', + ]) + }) + + it('should not throw error on filter', async () => { + await createFilterTreeView() + ; (treeView as any).getRenderedLine = () => { + throw new Error('Error on updateUI') + } + await nvim.input('a') + await helper.wait(50) + }) + + it('should add & remove Cursor highlight on window change', async () => { + let winid = await nvim.call('win_getid') + let ns = await nvim.call('coc#highlight#create_namespace', ['tree']) + await createFilterTreeView() + let bufnr = await nvim.call('bufnr', ['%']) + let markers = await nvim.call('nvim_buf_get_extmarks', [bufnr, ns, [1, 0], [1, -1], {}]) as [number, number, number][] + expect(markers[0]).toBeDefined() + await nvim.call('win_gotoid', [winid]) + await helper.wait(50) + markers = await nvim.call('nvim_buf_get_extmarks', [bufnr, ns, [1, 0], [1, -1], {}]) as [number, number, number][] + expect(markers.length).toBe(0) + await nvim.command('wincmd p') + await helper.wait(50) + markers = await nvim.call('nvim_buf_get_extmarks', [bufnr, ns, [1, 0], [1, -1], {}]) as [number, number, number][] + expect(markers.length).toBe(1) + }) + + it('should filter new nodes on data change', async () => { + await createFilterTreeView() + await nvim.input('a') + await helper.wait(50) + updateData([ + ['ab'], + ['e'], + ['fa'] + ]) + await helper.wait(50) + await checkLines([ + 'test', + 'a ', + ' ab', + ' fa', + ]) + }) + + it('should change selected item by and ', async () => { + await createFilterTreeView() + await nvim.input('a') + await helper.wait(50) + updateData([ + ['ab'], + ['fa'] + ]) + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + let curr = treeView.selection[0] + expect(curr.label).toBe('fa') + await nvim.input('') + await helper.wait(50) + curr = treeView.selection[0] + expect(curr.label).toBe('ab') + await nvim.input('') + await helper.wait(50) + curr = treeView.selection[0] + expect(curr.label).toBe('fa') + await nvim.input('') + await helper.wait(50) + curr = treeView.selection[0] + expect(curr.label).toBe('ab') + }) + + it('should not throw with empty nodes', async () => { + await createFilterTreeView() + await nvim.input('ab') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await checkLines(['test', 'ab ']) + let curr = treeView.selection[0] + expect(curr).toBeUndefined() + }) + + it('should invoke command by ', async () => { + let node + await createFilterTreeView({ + handleClick: n => { + node = n + } + }) + await nvim.input('') + await helper.wait(50) + expect(node).toBeDefined() + let curr = treeView.selection[0] + expect(curr).toBeDefined() + }) + + it('should keep state when press with empty selection ', async () => { + await createFilterTreeView() + await nvim.input('ab') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await checkLines(['test', 'ab ']) + }) + + it('should delete last filter character by ', async () => { + await createFilterTreeView() + await nvim.input('a') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await checkLines([ + 'test', ' ', ' a', ' c', ' d', ' b', ' e', ' f', ' g' + ]) + }) + + it('should clean filter character by ', async () => { + await createFilterTreeView() + await nvim.input('ab') + await helper.wait(50) + await nvim.input('') + await helper.wait(50) + await checkLines([ + 'test', ' ', ' a', ' c', ' d', ' b', ' e', ' f', ' g' + ]) + }) + + it('should cancel filter by and ', async () => { + await createFilterTreeView() + await nvim.input('') + await helper.wait(50) + await checkLines([ + 'test', + '+ a', + '+ b', + ' g', + ]) + await nvim.input('f') + await helper.wait(20) + await nvim.input('') + await helper.wait(20) + await checkLines([ + 'test', + '+ a', + '+ b', + ' g', + ]) + }) + + it('should navigate input history by and ', async () => { + await createFilterTreeView() + await nvim.input('a') + await helper.wait(20) + await nvim.input('') + await helper.wait(20) + await nvim.input('f') + await helper.wait(20) + await nvim.input('b') + await helper.wait(20) + await nvim.input('') + await helper.wait(20) + await nvim.input('f') + await helper.wait(20) + await nvim.input('') + await helper.wait(20) + await checkLines(['test', 'a ', ' a',]) + await nvim.input('') + await helper.wait(20) + await checkLines(['test', 'b ', ' b',]) + await nvim.input('') + await helper.wait(20) + await checkLines(['test', 'a ', ' a',]) + await nvim.input('') + await helper.wait(20) + await checkLines(['test', 'b ', ' b',]) + }) + }) +}) diff --git a/sources_non_forked/coc.nvim/src/__tests__/ultisnips.py b/sources_non_forked/coc.nvim/src/__tests__/ultisnips.py new file mode 100644 index 00000000..8ab3d0e2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/ultisnips.py @@ -0,0 +1,280 @@ +import re, os, vim, string, random +from collections import deque, namedtuple + +_Placeholder = namedtuple("_FrozenPlaceholder", ["current_text", "start", "end"]) +_VisualContent = namedtuple("_VisualContent", ["mode", "text"]) +_Position = namedtuple("_Position", ["line", "col"]) + + +class _SnippetUtilCursor(object): + def __init__(self, cursor): + self._cursor = [cursor[0] - 1, cursor[1]] + self._set = False + + def preserve(self): + self._set = True + self._cursor = [vim.buf.cursor[0], vim.buf.cursor[1]] + + def is_set(self): + return self._set + + def set(self, line, column): + self.__setitem__(0, line) + self.__setitem__(1, column) + + def to_vim_cursor(self): + return (self._cursor[0] + 1, self._cursor[1]) + + def __getitem__(self, index): + return self._cursor[index] + + def __setitem__(self, index, value): + self._set = True + self._cursor[index] = value + + def __len__(self): + return 2 + + def __str__(self): + return str((self._cursor[0], self._cursor[1])) + + +class IndentUtil(object): + + """Utility class for dealing properly with indentation.""" + + def __init__(self): + self.reset() + + def reset(self): + """Gets the spacing properties from Vim.""" + self.shiftwidth = int( + vim.eval("exists('*shiftwidth') ? shiftwidth() : &shiftwidth") + ) + self._expandtab = vim.eval("&expandtab") == "1" + self._tabstop = int(vim.eval("&tabstop")) + + def ntabs_to_proper_indent(self, ntabs): + """Convert 'ntabs' number of tabs to the proper indent prefix.""" + line_ind = ntabs * self.shiftwidth * " " + line_ind = self.indent_to_spaces(line_ind) + line_ind = self.spaces_to_indent(line_ind) + return line_ind + + def indent_to_spaces(self, indent): + """Converts indentation to spaces respecting Vim settings.""" + indent = indent.expandtabs(self._tabstop) + right = (len(indent) - len(indent.rstrip(" "))) * " " + indent = indent.replace(" ", "") + indent = indent.replace("\t", " " * self._tabstop) + return indent + right + + def spaces_to_indent(self, indent): + """Converts spaces to proper indentation respecting Vim settings.""" + if not self._expandtab: + indent = indent.replace(" " * self._tabstop, "\t") + return indent + + +class SnippetUtil(object): + + """Provides easy access to indentation, etc. + + This is the 'snip' object in python code. + + """ + + def __init__(self, _initial_indent, start, end, context): + self._ind = IndentUtil() + self._visual = _VisualContent( + vim.eval("visualmode()"), vim.eval('get(g:,"coc_selected_text","")') + ) + self._initial_indent = _initial_indent + self._reset("") + self._start = start + self._end = end + self._context = context + + def _reset(self, cur): + """Gets the snippet ready for another update. + + :cur: the new value for c. + + """ + self._ind.reset() + self._cur = cur + self._rv = "" + self._changed = False + self.reset_indent() + + def shift(self, amount=1): + """Shifts the indentation level. Note that this uses the shiftwidth + because thats what code formatters use. + + :amount: the amount by which to shift. + + """ + self.indent += " " * self._ind.shiftwidth * amount + + def unshift(self, amount=1): + """Unshift the indentation level. Note that this uses the shiftwidth + because thats what code formatters use. + + :amount: the amount by which to unshift. + + """ + by = -self._ind.shiftwidth * amount + try: + self.indent = self.indent[:by] + except IndexError: + self.indent = "" + + def mkline(self, line="", indent=None): + """Creates a properly set up line. + + :line: the text to add + :indent: the indentation to have at the beginning + if None, it uses the default amount + + """ + if indent is None: + indent = self.indent + # this deals with the fact that the first line is + # already properly indented + if "\n" not in self._rv: + try: + indent = indent[len(self._initial_indent) :] + except IndexError: + indent = "" + indent = self._ind.spaces_to_indent(indent) + + return indent + line + + def reset_indent(self): + """Clears the indentation.""" + self.indent = self._initial_indent + + # Utility methods + @property + def fn(self): # pylint:disable=no-self-use,invalid-name + """The filename.""" + return vim.eval('expand("%:t")') or "" + + @property + def basename(self): # pylint:disable=no-self-use + """The filename without extension.""" + return vim.eval('expand("%:t:r")') or "" + + @property + def ft(self): # pylint:disable=invalid-name + """The filetype.""" + return self.opt("&filetype", "") + + @property + def rv(self): # pylint:disable=invalid-name + """The return value. + + The text to insert at the location of the placeholder. + + """ + return self._rv + + @rv.setter + def rv(self, value): # pylint:disable=invalid-name + """See getter.""" + self._changed = True + self._rv = value + + @property + def _rv_changed(self): + """True if rv has changed.""" + return self._changed + + @property + def c(self): # pylint:disable=invalid-name + """The current text of the placeholder.""" + return self._cur + + @property + def v(self): # pylint:disable=invalid-name + """Content of visual expansions.""" + return self._visual + + @property + def p(self): + if "coc_last_placeholder" in vim.vars: + p = vim.vars["coc_last_placeholder"] + start = _Position(p["start"]["line"], p["start"]["col"]) + end = _Position(p["end"]["line"], p["end"]["col"]) + return _Placeholder(p["current_text"], start, end) + return None + + @property + def context(self): + return self._context + + def opt(self, option, default=None): # pylint:disable=no-self-use + """Gets a Vim variable.""" + if vim.eval("exists('%s')" % option) == "1": + try: + return vim.eval(option) + except vim.error: + pass + return default + + def __add__(self, value): + """Appends the given line to rv using mkline.""" + self.rv += "\n" # pylint:disable=invalid-name + self.rv += self.mkline(value) + return self + + def __lshift__(self, other): + """Same as unshift.""" + self.unshift(other) + + def __rshift__(self, other): + """Same as shift.""" + self.shift(other) + + @property + def snippet_start(self): + """ + Returns start of the snippet in format (line, column). + """ + return self._start + + @property + def snippet_end(self): + """ + Returns end of the snippet in format (line, column). + """ + return self._end + + @property + def buffer(self): + return vim.buf + + +class ContextSnippet(object): + def __init__(self): + self.buffer = vim.current.buffer + self.window = vim.current.window + self.cursor = _SnippetUtilCursor(vim.current.window.cursor) + self.line = vim.current.window.cursor[0] - 1 + self.column = vim.current.window.cursor[1] - 1 + self.before = vim.eval('strpart(getline("."), 0, col(".") - 1)') + line = vim.eval('line(".")') + self.after = line[self.column :] + if "coc_selected_text" in vim.vars: + self.visual_mode = vim.eval("visualmode()") + self.visual_text = vim.vars["coc_selected_text"] + else: + self.visual_mode = None + self.visual_text = "" + if "coc_last_placeholder" in vim.vars: + p = vim.vars["coc_last_placeholder"] + start = _Position(p["start"]["line"], p["start"]["col"]) + end = _Position(p["end"]["line"], p["end"]["col"]) + self.last_placeholder = _Placeholder(p["current_text"], start, end) + else: + self.last_placeholder = None diff --git a/sources_non_forked/coc.nvim/src/__tests__/vimrc b/sources_non_forked/coc.nvim/src/__tests__/vimrc new file mode 100644 index 00000000..76814e67 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/__tests__/vimrc @@ -0,0 +1,64 @@ +set nocompatible + +set hidden +set noswapfile +set nobackup +set completeopt=menuone,noinsert,noselect +set tabstop=2 +set cmdheight=2 +set shiftwidth=2 +set updatetime=300 +set expandtab +set noshowmode +set shortmess=aFtW +set noruler + +let s:dir = expand(':h') +let s:root = expand(':h:h:h') +let g:coc_node_env = 'test' + +let g:coc_vim_commands = [{ + \ "id": "config", + \ "cmd": "edit coc-settings.json" + \ }] + +autocmd BufNewFile,BufRead *.ts set filetype=typescript + +execute 'set runtimepath+='.s:root + +" Float window id on current tab. +function! GetFloatWin() abort + if has('nvim') + for i in range(1, winnr('$')) + let id = win_getid(i) + let config = nvim_win_get_config(id) + if (!empty(config) && config['focusable'] == v:true && !empty(config['relative'])) + if !getwinvar(id, 'button', 0) + return id + endif + endif + endfor + else + let ids = popup_list() + return get(filter(ids, 'get(popup_getpos(v:val),"visible",0)'), 0, 0) + endif + return 0 +endfunction + +" float/popup relative to current cursor position +function! GetFloatCursorRelative(winid) abort + if !coc#float#valid(a:winid) + return v:null + endif + let winid = win_getid() + if winid == a:winid + return v:null + endif + let [cursorLine, cursorCol] = coc#cursor#screen_pos() + if has('nvim') + let [row, col] = nvim_win_get_position(a:winid) + return {'row' : row - cursorLine, 'col' : col - cursorCol} + endif + let pos = popup_getpos(a:winid) + return {'row' : pos['line'] - cursorLine - 1, 'col' : pos['col'] - cursorCol - 1} +endfunction diff --git a/sources_non_forked/coc.nvim/src/attach.ts b/sources_non_forked/coc.nvim/src/attach.ts new file mode 100644 index 00000000..3e2ccac0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/attach.ts @@ -0,0 +1,137 @@ +'use strict' +import { attach, Attach, NeovimClient } from '@chemzqm/neovim' +import log4js from 'log4js' +import events from './events' +import Plugin from './plugin' +import semver from 'semver' +import { objectLiteral } from './util/is' +import { URI } from 'vscode-uri' +import { version as VERSION } from '../package.json' + +const logger = require('./util/logger')('attach') +const isTest = global.hasOwnProperty('__TEST__') +/** + * Request actions that not need plugin ready + */ +const ACTIONS_NO_WAIT = ['installExtensions', 'updateExtensions'] + +export default (opts: Attach, requestApi = true): Plugin => { + const nvim: NeovimClient = attach(opts, log4js.getLogger('node-client'), requestApi) + if (!global.hasOwnProperty('__TEST__')) { + nvim.call('coc#util#path_replace_patterns').then(prefixes => { + if (objectLiteral(prefixes)) { + const old_uri = URI.file + URI.file = (path): URI => { + path = path.replace(/\\/g, '/') + Object.keys(prefixes).forEach(k => path = path.replace(new RegExp('^' + k), prefixes[k])) + return old_uri(path) + } + } + }).logError() + } + nvim.setVar('coc_process_pid', process.pid, true) + const plugin = new Plugin(nvim) + let clientReady = false + let initialized = false + nvim.on('notification', async (method, args) => { + switch (method) { + case 'VimEnter': { + if (!initialized && clientReady) { + initialized = true + await plugin.init() + } + break + } + case 'Log': { + logger.debug(...args) + break + } + case 'TaskExit': + case 'TaskStderr': + case 'TaskStdout': + case 'GlobalChange': + case 'PromptInsert': + case 'InputChar': + case 'MenuInput': + case 'OptionSet': + case 'PromptKeyPress': + case 'FloatBtnClick': + logger.trace('Event: ', method, ...args) + await events.fire(method, args) + break + case 'CocAutocmd': + logger.trace('Notification autocmd:', ...args) + await events.fire(args[0], args.slice(1)) + break + case 'redraw': + break + default: { + let exists = plugin.hasAction(method) + if (!exists) { + console.error(`action "${method}" does not exist`) + return + } + try { + if (!plugin.isReady) { + logger.warn(`Plugin not ready when received "${method}"`, args) + } else { + logger.info('receive notification:', method, args) + } + await plugin.ready + await plugin.cocAction(method, ...args) + } catch (e) { + nvim.echoError(`Error on notification "${method}": ${(e instanceof Error ? e.message : e)}`) + logger.error(e) + } + } + } + }) + + nvim.on('request', async (method: string, args, resp) => { + if (method == 'redraw') { + // ignore redraw from neovim + resp.send() + return + } + let timer = setTimeout(() => { + logger.error('Request cost more than 3s', method, args) + }, 3000) + try { + if (method == 'CocAutocmd') { + logger.trace('Request autocmd:', ...args) + await events.fire(args[0], args.slice(1)) + resp.send(undefined) + } else { + if (!plugin.isReady && !ACTIONS_NO_WAIT.includes(method)) { + logger.warn(`Plugin not ready on request "${method}"`, args) + resp.send('Plugin not ready', true) + return + } + logger.info('Request action:', method, args) + let res = await plugin.cocAction(method, ...args) + resp.send(res) + } + clearTimeout(timer) + } catch (e) { + clearTimeout(timer) + resp.send(e instanceof Error ? e.message : e.toString(), true) + logger.error(`Request error:`, method, args, e) + } + }) + + nvim.channelId.then(async channelId => { + clientReady = true + // Used for test client on vim side + if (isTest) nvim.call('coc#rpc#set_channel', [channelId], true) + let { major, minor, patch } = semver.parse(VERSION) + nvim.setClientInfo('coc', { major, minor, patch }, 'remote', {}, {}) + let entered = await nvim.getVvar('vim_did_enter') + if (entered && !initialized) { + initialized = true + await plugin.init() + } + }).catch(e => { + console.error(`Channel create error: ${e.message}`) + }) + return plugin +} diff --git a/sources_non_forked/coc.nvim/src/commands.ts b/sources_non_forked/coc.nvim/src/commands.ts new file mode 100644 index 00000000..8ffbab34 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/commands.ts @@ -0,0 +1,426 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import * as language from 'vscode-languageserver-protocol' +import { CodeAction, Disposable, InsertTextMode, Location, Position, Range, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import diagnosticManager from './diagnostic/manager' +import Mru from './model/mru' +import Plugin from './plugin' +import snippetsManager from './snippets/manager' +import { UltiSnippetOption } from './types' +import { wait } from './util' +import window from './window' +import workspace from './workspace' +import events from './events' +const logger = require('./util/logger')('commands') + +// command center +export interface Command { + readonly id: string | string[] + execute(...args: any[]): void | Promise +} + +class CommandItem implements Disposable, Command { + constructor( + public id: string, + private impl: (...args: any[]) => void, + private thisArg: any, + public internal = false + ) { + } + + public execute(...args: any[]): void | Promise { + let { impl, thisArg } = this + return impl.apply(thisArg, args || []) + } + + public dispose(): void { + this.thisArg = null + this.impl = null + } +} + +export class CommandManager implements Disposable { + private readonly commands = new Map() + public titles = new Map() + public onCommandList: string[] = [] + private mru: Mru + + public init(nvim: Neovim, plugin: Plugin): void { + this.mru = workspace.createMru('commands') + this.register({ + id: 'vscode.open', + execute: async (url: string | URI) => { + nvim.call('coc#ui#open_url', url.toString(), true) + } + }, true) + this.register({ + id: 'workbench.action.reloadWindow', + execute: async () => { + nvim.command('CocRestart', true) + } + }, true) + this.register({ + id: 'editor.action.insertSnippet', + execute: async (edit: TextEdit, ultisnip?: UltiSnippetOption) => { + const opts = ultisnip === true ? {} : ultisnip + return await snippetsManager.insertSnippet(edit.newText, true, edit.range, InsertTextMode.adjustIndentation, opts ? opts : undefined) + } + }, true) + this.register({ + id: 'editor.action.doCodeAction', + execute: async (action: CodeAction) => { + await plugin.cocAction('doCodeAction', action) + } + }, true) + this.register({ + id: 'editor.action.triggerSuggest', + execute: async () => { + let doc = workspace.getDocument(workspace.bufnr) + if (doc) await doc.synchronize() + nvim.call('coc#start', [], true) + } + }, true) + this.register({ + id: 'editor.action.triggerParameterHints', + execute: async () => { + let doc = workspace.getDocument(workspace.bufnr) + if (doc) await doc.synchronize() + await plugin.cocAction('showSignatureHelp') + } + }, true) + this.register({ + id: 'editor.action.addRanges', + execute: async (ranges: Range[]) => { + await plugin.cocAction('addRanges', ranges) + } + }, true) + this.register({ + id: 'editor.action.restart', + execute: async () => { + await wait(30) + nvim.command('CocRestart', true) + } + }, true) + this.register({ + id: 'editor.action.showReferences', + execute: async (_filepath: string, _position: Position, references: Location[]) => { + await workspace.showLocations(references) + } + }, true) + this.register({ + id: 'editor.action.rename', + execute: async (uri: string, position: Position) => { + await workspace.jumpTo(uri, position) + await plugin.cocAction('rename') + } + }, true) + this.register({ + id: 'editor.action.format', + execute: async () => { + await plugin.cocAction('format') + } + }, true) + this.register({ + id: 'workspace.refactor', + execute: async (locations: Location[]) => { + let locs = locations.filter(o => Location.is(o)) + await plugin.getHandler().refactor.fromLocations(locs) + } + }, true) + this.register({ + id: 'workspace.clearWatchman', + execute: async () => { + let res = await window.runTerminalCommand('watchman watch-del-all') + if (res.success) window.showMessage('Cleared watchman watching directories.') + } + }, false, 'run watch-del-all for watchman to free up memory.') + this.register({ + id: 'workspace.workspaceFolders', + execute: async () => { + let folders = workspace.workspaceFolders + let lines = folders.map(folder => URI.parse(folder.uri).fsPath) + await window.echoLines(lines) + } + }, false, 'show opened workspaceFolders.') + this.register({ + id: 'workspace.renameCurrentFile', + execute: async () => { + await workspace.renameCurrent() + } + }, false, 'change current filename to a new name and reload it.') + this.register({ + id: 'extensions.toggleAutoUpdate', + execute: async () => { + let config = workspace.getConfiguration('coc.preferences') + let interval = config.get('extensionUpdateCheck', 'daily') + if (interval == 'never') { + config.update('extensionUpdateCheck', 'daily', true) + window.showMessage('Extension auto update enabled.', 'more') + } else { + config.update('extensionUpdateCheck', 'never', true) + window.showMessage('Extension auto update disabled.', 'more') + } + } + }, false, 'toggle auto update of extensions.') + this.register({ + id: 'workspace.diagnosticRelated', + execute: () => diagnosticManager.jumpRelated() + }, false, 'jump to related locations of current diagnostic.') + this.register({ + id: 'workspace.showOutput', + execute: async (name?: string) => { + if (name) { + window.showOutputChannel(name) + } else { + let names = workspace.channelNames + if (names.length == 0) return + if (names.length == 1) { + window.showOutputChannel(names[0]) + } else { + let idx = await window.showQuickpick(names) + if (idx == -1) return + let name = names[idx] + window.showOutputChannel(name) + } + } + } + }, false, 'open output buffer to show output from languageservers or extensions.') + this.register({ + id: 'document.showIncomingCalls', + execute: async () => { + await plugin.cocAction('showIncomingCalls') + } + }, false, 'show incoming calls in tree view.') + this.register({ + id: 'document.showOutgoingCalls', + execute: async () => { + await plugin.cocAction('showOutgoingCalls') + } + }, false, 'show outgoing calls in tree view.') + this.register({ + id: 'document.echoFiletype', + execute: async () => { + let bufnr = await nvim.call('bufnr', '%') + let doc = workspace.getDocument(bufnr) + if (!doc) return + await window.echoLines([doc.filetype]) + } + }, false, 'echo the mapped filetype of the current buffer') + this.register({ + id: 'document.renameCurrentWord', + execute: async () => { + let bufnr = await nvim.call('bufnr', '%') + let doc = workspace.getDocument(bufnr) + if (!doc) return + let edit = await plugin.cocAction('getWordEdit') as WorkspaceEdit + if (!edit) { + window.showMessage('Invalid position', 'warning') + return + } + let ranges: Range[] = [] + let { changes, documentChanges } = edit + if (changes) { + let edits = changes[doc.uri] + if (edits) ranges = edits.map(e => e.range) + } else if (documentChanges) { + for (let c of documentChanges) { + if (TextDocumentEdit.is(c) && c.textDocument.uri == doc.uri) { + ranges = c.edits.map(e => e.range) + } + } + } + if (ranges.length) { + await plugin.cocAction('addRanges', ranges) + } + } + }, false, 'rename word under cursor in current buffer by use multiple cursors.') + this.register({ + id: 'document.jumpToNextSymbol', + execute: async () => { + let doc = await workspace.document + if (!doc) return + let ranges = await plugin.cocAction('symbolRanges') as Range[] + if (!ranges) return + let { textDocument } = doc + let offset = await window.getOffset() + ranges.sort((a, b) => { + if (a.start.line != b.start.line) { + return a.start.line - b.start.line + } + return a.start.character - b.start.character + }) + for (let i = 0; i <= ranges.length - 1; i++) { + if (textDocument.offsetAt(ranges[i].start) > offset) { + await window.moveTo(ranges[i].start) + return + } + } + await window.moveTo(ranges[0].start) + } + }, false, 'Jump to next symbol highlight position.') + this.register({ + id: 'workspace.undo', + execute: async () => { + await workspace.files.undoWorkspaceEdit() + } + }, false, 'Undo previous workspace edit') + this.register({ + id: 'workspace.redo', + execute: async () => { + await workspace.files.redoWorkspaceEdit() + } + }, false, 'Redo previous workspace edit') + this.register({ + id: 'workspace.inspectEdit', + execute: async () => { + await workspace.files.inspectEdit() + } + }, false, 'Inspect previous workspace edit in new tab') + this.register({ + id: 'workspace.openLocation', + execute: async (winid: number, loc: Location, openCommand?: string) => { + if (winid) await nvim.call('win_gotoid', [winid]) + await workspace.jumpTo(loc.uri, loc.range.start, openCommand) + } + }, true) + this.register({ + id: 'document.jumpToPrevSymbol', + execute: async () => { + let doc = await workspace.document + if (!doc) return + let ranges = await plugin.cocAction('symbolRanges') as Range[] + if (!ranges) return + let { textDocument } = doc + let offset = await window.getOffset() + ranges.sort((a, b) => { + if (a.start.line != b.start.line) { + return a.start.line - b.start.line + } + return a.start.character - b.start.character + }) + for (let i = ranges.length - 1; i >= 0; i--) { + if (textDocument.offsetAt(ranges[i].end) < offset) { + await window.moveTo(ranges[i].start) + return + } + } + await window.moveTo(ranges[ranges.length - 1].start) + } + }, false, 'Jump to previous symbol highlight position.') + this.register({ + id: 'document.checkBuffer', + execute: async () => { + await plugin.cocAction('bufferCheck') + } + }, false, 'Check providers for current buffer.') + } + + public get commandList(): CommandItem[] { + let res: CommandItem[] = [] + for (let item of this.commands.values()) { + if (!item.internal) res.push(item) + } + return res + } + + public dispose(): void { + for (const registration of this.commands.values()) { + registration.dispose() + } + this.commands.clear() + } + + public execute(command: language.Command): Promise { + return this.executeCommand(command.command, ...(command.arguments ?? [])) + } + + public register(command: T, internal = false, description?: string): T { + for (const id of Array.isArray(command.id) ? command.id : [command.id]) { + this.registerCommand(id, command.execute, command, internal) + if (description) this.titles.set(id, description) + } + return command + } + + public has(id: string): boolean { + return this.commands.has(id) + } + + public unregister(id: string): void { + let item = this.commands.get(id) + if (!item) return + item.dispose() + this.commands.delete(id) + } + + /** + * Registers a command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Registering a command with an existing command identifier twice + * will cause an error. + * + * @param command A unique identifier for the command. + * @param impl A command handler function. + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + public registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any, internal = false): Disposable { + if (id.startsWith("_")) internal = true + this.commands.set(id, new CommandItem(id, impl, thisArg, internal)) + return Disposable.create(() => { + this.commands.delete(id) + }) + } + + /** + * Executes the command denoted by the given command identifier. + * + * * *Note 1:* When executing an editor command not all types are allowed to + * be passed as arguments. Allowed are the primitive types `string`, `boolean`, + * `number`, `undefined`, and `null`, as well as [`Position`](#Position), [`Range`](#Range), [`URI`](#URI) and [`Location`](#Location). + * * *Note 2:* There are no restrictions when executing commands that have been contributed + * by extensions. + * + * @param command Identifier of the command to execute. + * @param rest Parameters passed to the command function. + * @return A promise that resolves to the returned value of the given command. `undefined` when + * the command handler function doesn't return anything. + */ + public executeCommand(command: string, ...rest: any[]): Promise { + let cmd = this.commands.get(command) + if (!cmd) throw new Error(`Command: ${command} not found`) + return Promise.resolve(cmd.execute.apply(cmd, rest)) + } + + /** + * Used for user invoked command. + */ + public async fireCommand(id: string, ...args: any[]): Promise { + // needed to load onCommand extensions + await events.fire('Command', [id]) + let start = Date.now() + let res = await this.executeCommand(id, ...args) + if (args.length == 0) { + await this.addRecent(id, events.lastChangeTs > start) + } + return res + } + + public async addRecent(cmd: string, repeat: boolean): Promise { + await this.mru.add(cmd) + if (repeat) await workspace.nvim.command(`silent! call repeat#set("\\(coc-command-repeat)", -1)`) + } + + public async repeatCommand(): Promise { + let mruList = await this.mru.load() + let first = mruList[0] + if (first) { + await this.executeCommand(first) + await workspace.nvim.command(`silent! call repeat#set("\\(coc-command-repeat)", -1)`) + } + } +} + +export default new CommandManager() diff --git a/sources_non_forked/coc.nvim/src/completion/complete.ts b/sources_non_forked/coc.nvim/src/completion/complete.ts new file mode 100644 index 00000000..809df49f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/complete.ts @@ -0,0 +1,407 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, CancellationTokenSource, Emitter, Event, Position } from 'vscode-languageserver-protocol' +import Document from '../model/document' +import { CompleteOption, CompleteResult, ExtendedCompleteItem, FloatConfig, ISource, VimCompleteItem } from '../types' +import { wait } from '../util' +import { getCharCodes } from '../util/fuzzy' +import { byteSlice, characterIndex, isWord } from '../util/string' +import { matchScore } from './match' +import MruLoader from './mru' +const isVim = process.env.VIM_NODE_RPC == '1' +const logger = require('../util/logger')('completion-complete') + +export interface CompleteConfig { + selection: 'none' | 'recentlyUsed' | 'recentlyUsedByPrefix' + disableKind: boolean + disableMenu: boolean + disableMenuShortcut: boolean + enablePreview: boolean + enablePreselect: boolean + labelMaxLength: number + floatEnable: boolean + autoTrigger: string + previewIsKeyword: string + triggerCompletionWait: number + minTriggerInputLength: number + triggerAfterInsertEnter: boolean + acceptSuggestionOnCommitCharacter: boolean + noselect: boolean + keepCompleteopt: boolean + maxItemCount: number + timeout: number + snippetIndicator: string + fixInsertedWord: boolean + localityBonus: boolean + highPrioritySourceLimit: number + lowPrioritySourceLimit: number + removeDuplicateItems: boolean + defaultSortMethod: string + asciiCharactersOnly: boolean + ignoreRegexps: string[] + floatConfig: FloatConfig +} + +export type Callback = () => void + +export default class Complete { + // identify this complete + private results: Map = new Map() + private _input = '' + private _completing = false + private localBonus: Map = new Map() + // source names that already filtered. + private filtered: Set = new Set() + private tokenSource: CancellationTokenSource + private timer: NodeJS.Timer + private names: string[] = [] + private readonly _onDidRefresh = new Emitter() + public readonly onDidRefresh: Event = this._onDidRefresh.event + constructor(public option: CompleteOption, + private document: Document, + private config: CompleteConfig, + private sources: ISource[], + private mruLoader: MruLoader, + private nvim: Neovim) { + this.tokenSource = new CancellationTokenSource() + sources.sort((a, b) => b.priority - a.priority) + this.names = sources.map(o => o.name) + } + + private fireRefresh(waitTime: number): void { + if (this.timer) clearTimeout(this.timer) + this.timer = setTimeout(() => { + if (this.allFiltered) return + this._onDidRefresh.fire() + }, waitTime) + } + + private get allFiltered(): boolean { + let { filtered, results } = this + if (filtered.size === 0) return false + for (let key of results.keys()) { + if (!filtered.has(key)) return false + } + return true + } + + public get isCompleting(): boolean { + return this._completing + } + + public get input(): string { + return this._input + } + + public get isEmpty(): boolean { + let empty = true + for (let res of this.results.values()) { + if (res.items.length > 0) { + empty = false + break + } + } + return empty + } + + public getIncompleteSources(): string[] { + let names: string[] = [] + for (let [name, result] of this.results.entries()) { + if (result.isIncomplete) { + names.push(name) + } + } + return names + } + + public async doComplete(): Promise { + let token = this.tokenSource.token + let res = await Promise.all([ + this.nvim.call('coc#util#synname', []), + this.document.patchChange() + ]) + this.option.synname = res[0] + if (token.isCancellationRequested) return true + let { triggerCompletionWait, localityBonus } = this.config + await wait(Math.min(triggerCompletionWait ?? 0, 50)) + if (token.isCancellationRequested) return true + let { colnr, linenr, col } = this.option + if (localityBonus) { + let line = linenr - 1 + this.localBonus = this.document.getLocalifyBonus(Position.create(line, col - 1), Position.create(line, colnr)) + } + await this.completeSources(this.sources) + return token.isCancellationRequested + } + + private async completeSources(sources: ReadonlyArray): Promise { + let { fixInsertedWord, timeout } = this.config + let { results, tokenSource, } = this + let col = this.option.col + let isFilter = results.size > 0 + let followPart = !fixInsertedWord ? '' : this.getFollowPart() + let names = sources.map(s => s.name) + let total = names.length + this._completing = true + let token = tokenSource.token + let timer: NodeJS.Timer + let tp = new Promise(resolve => { + timer = setTimeout(() => { + if (!tokenSource.token.isCancellationRequested) { + names = names.filter(n => !finished.includes(n)) + tokenSource.cancel() + logger.warn(`Complete timeout after ${timeout}ms`, names) + this.nvim.setVar(`coc_timeout_sources`, names, true) + } + resolve() + }, typeof timeout === 'number' ? timeout : 500) + }) + const finished: string[] = [] + await Promise.race([ + tp, + Promise.all(sources.map(s => this.completeSource(s, token, followPart).then(() => { + finished.push(s.name) + if (token.isCancellationRequested || isFilter) return + let colChanged = this.option.col !== col + if (colChanged) this.cancel() + if (colChanged || finished.length === total) { + this.fireRefresh(0) + } else if (results.has(s.name)) { + this.fireRefresh(16) + } + })))]) + clearTimeout(timer) + this._completing = false + } + + private async completeSource(source: ISource, token: CancellationToken, followPart: string): Promise { + // new option for each source + let opt = Object.assign({}, this.option) + let { snippetIndicator } = this.config + let { name } = source + try { + if (typeof source.shouldComplete === 'function') { + let shouldRun = await Promise.resolve(source.shouldComplete(opt)) + if (!shouldRun || token.isCancellationRequested) return + } + const priority = source.priority ?? 0 + const start = Date.now() + await new Promise((resolve, reject) => { + Promise.resolve(source.doComplete(opt, token)).then(result => { + let len = result ? result.items.length : 0 + if (token.isCancellationRequested) { + resolve(undefined) + return + } + logger.debug(`Source "${name}" finished with ${len} items ${Date.now() - start}ms`) + if (len > 0) { + result.priority = priority + let hasFollow = followPart.length > 0 + result.items.forEach((item, idx) => { + let word = item.word ?? '' + let abbr = item.abbr ?? word + item.word = word + item.source = name + item.priority = priority + item.filterText = item.filterText ?? word + if (hasFollow && word != followPart && word.endsWith(followPart)) { + item.word = word.slice(0, - followPart.length) + } + if (item.isSnippet === true && !abbr.endsWith(snippetIndicator)) item.abbr = `${abbr}${snippetIndicator}` + item.localBonus = this.localBonus.get(item.filterText) || 0 + item.user_data = `${name}:${idx}` + }) + this.setResult(name, result) + } else { + this.results.delete(name) + } + resolve() + }, err => { + reject(err) + }) + }) + } catch (err) { + this.nvim.echoError(err) + logger.error('Complete error:', source.name, err) + } + } + + public async completeInComplete(resumeInput: string, names: string[]): Promise { + let { document } = this + this.cancel() + this.tokenSource = new CancellationTokenSource() + let token = this.tokenSource.token + await document.patchChange(true) + if (token.isCancellationRequested) return undefined + let { input, colnr, linenr } = this.option + let character = resumeInput[resumeInput.length - 1] + Object.assign(this.option, { + input: resumeInput, + line: document.getline(linenr - 1), + colnr: colnr + (resumeInput.length - input.length), + triggerCharacter: !character || isWord(character) ? undefined : character, + triggerForInComplete: true + }) + let sources = this.sources.filter(s => names.includes(s.name)) + await this.completeSources(sources) + if (token.isCancellationRequested) return undefined + return this.filterItems(resumeInput) + } + + public filterItems(input: string): ExtendedCompleteItem[] | undefined { + let { results, names } = this + this._input = input + if (results.size == 0) return [] + let len = input.length + let emptyInput = len == 0 + let { maxItemCount, selection, enablePreselect, defaultSortMethod, removeDuplicateItems } = this.config + let arr: ExtendedCompleteItem[] = [] + let codes = getCharCodes(input) + let words: Set = new Set() + let maxMru = -1 + let checkMru = selection !== 'none' + for (let name of names) { + let result = results.get(name) + if (!result) continue + let snippetSource = name === 'snippets' + let items = result.items + for (let idx = 0; idx < items.length; idx++) { + let item = items[idx] + let { word, filterText, dup } = item + if (dup !== 1 && words.has(word)) continue + if (filterText.length < len) continue + if (removeDuplicateItems && item.isSnippet !== true && words.has(word)) continue + if (!emptyInput) { + let score = item.kind && filterText == input ? 64 : matchScore(filterText, codes) + if (score === 0) continue + if (snippetSource && word === input) { + item.score = 99 + } else { + item.score = score * (item.sourceScore || 1) + } + } + if (checkMru) { + let n = this.mruLoader.getScore(input, item) + maxMru = Math.max(n, maxMru) + item.recentScore = n + } + words.add(word) + arr.push(item) + } + } + arr.sort((a, b) => { + let sa = a.sortText + let sb = b.sortText + if (a.score !== b.score) return b.score - a.score + if (a.priority !== b.priority) return b.priority - a.priority + if (a.localBonus !== b.localBonus) return b.localBonus - a.localBonus + if (a.source === b.source && sa !== sb) return sa < sb ? -1 : 1 + // not sort with empty input + if (input.length === 0) return 0 + switch (defaultSortMethod) { + case 'none': + return 0 + case 'alphabetical': + return a.filterText.localeCompare(b.filterText) + case 'length': + default: // Fallback on length + return a.filterText.length - b.filterText.length + } + }) + let sourceNames = results.keys() + process.nextTick(() => { + let { results } = this + for (let name of sourceNames) { + let result = results.get(name) + if (result) result.items = arr.filter(o => o.source === name) + } + }) + if (maxMru !== -1) { + let idx = arr.findIndex(o => o.recentScore === maxMru) + if (enablePreselect && !isVim) { + arr[idx].preselect = true + } else { + let removed = arr.splice(idx, 1) + arr.unshift(removed[0]) + } + } + return this.limitCompleteItems(arr.slice(0, maxItemCount)) + } + + public async filterResults(input: string): Promise { + this.filtered = new Set(this.results.keys()) + if (input !== this.option.input) { + let names = this.getIncompleteSources() + if (names.length) { + return await this.completeInComplete(input, names) + } + } + return this.filterItems(input) + } + + private limitCompleteItems(items: ExtendedCompleteItem[]): ExtendedCompleteItem[] { + let { highPrioritySourceLimit, lowPrioritySourceLimit } = this.config + if (!highPrioritySourceLimit && !lowPrioritySourceLimit) return items + let counts: Map = new Map() + return items.filter(item => { + let { priority, source } = item + let isLow = priority < 90 + let curr = counts.get(source) || 0 + if ((lowPrioritySourceLimit && isLow && curr == lowPrioritySourceLimit) + || (highPrioritySourceLimit && !isLow && curr == highPrioritySourceLimit)) { + return false + } + counts.set(source, curr + 1) + return true + }) + } + + // handle startcol change + private setResult(name: string, result: CompleteResult): void { + let { results } = this + let { line, colnr, col } = this.option + if (typeof result.startcol === 'number' && result.startcol != col) { + let { startcol } = result + this.option.col = startcol + this.option.input = byteSlice(line, startcol, colnr - 1) + results.clear() + results.set(name, result) + } else { + results.set(name, result) + } + } + + private cancel(): void { + let { tokenSource, timer } = this + if (timer) clearTimeout(timer) + tokenSource.cancel() + this._completing = false + } + + public resolveCompletionItem(item: VimCompleteItem | undefined): ExtendedCompleteItem | null { + if (typeof item.user_data !== 'string') return null + try { + let arr = item.user_data.split(':', 2) + let res = this.results.get(arr[0]) + return res ? res.items.find(o => o.user_data == item.user_data) : null + } catch (e) { + return null + } + } + + private getFollowPart(): string { + let { colnr, line } = this.option + let idx = characterIndex(line, colnr - 1) + if (idx == line.length) return '' + let part = line.slice(idx - line.length) + return part.match(/^\S?[\w-]*/)[0] + } + + public dispose(): void { + this.cancel() + this._onDidRefresh.dispose() + this.sources = [] + this.filtered.clear() + this.results.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/completion/floating.ts b/sources_non_forked/coc.nvim/src/completion/floating.ts new file mode 100644 index 00000000..5293a967 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/floating.ts @@ -0,0 +1,68 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import events from '../events' +import { parseDocuments } from '../markdown' +import { FloatConfig, Documentation } from '../types' +const logger = require('../util/logger')('floating') + +export interface PumBounding { + readonly height: number + readonly width: number + readonly row: number + readonly col: number + readonly scrollbar: boolean +} + +export interface FloatingConfig extends FloatConfig { + excludeImages: boolean +} + +export default class Floating { + private winid = 0 + private bufnr = 0 + + constructor( + private nvim: Neovim, + private isVim: boolean) { + } + + public async show(docs: Documentation[], bounding: PumBounding, config: FloatingConfig): Promise { + let { nvim } = this + docs = docs.filter(o => o.content.trim().length > 0) + let { lines, codes, highlights } = parseDocuments(docs, { excludeImages: config.excludeImages }) + if (lines.length == 0) { + this.close() + return + } + let opts: any = { + codes, + highlights, + maxWidth: config.maxWidth || 80, + pumbounding: bounding, + } + if (config.border) opts.border = [1, 1, 1, 1] + if (config.highlight) opts.highlight = config.highlight + if (config.borderhighlight) opts.borderhighlight = config.borderhighlight + if (!this.isVim) { + if (typeof config.winblend === 'number') opts.winblend = config.winblend + opts.focusable = config.focusable === true ? 1 : 0 + if (config.shadow) opts.shadow = 1 + } + let res = await nvim.call('coc#dialog#create_pum_float', [this.winid, this.bufnr, lines, opts]) + nvim.redrawVim() + if (!res || res.length == 0) return + this.winid = res[0] + this.bufnr = res[1] + if (!events.pumvisible) { + this.close() + } + } + + public close(): void { + let { winid, nvim } = this + this.winid = 0 + if (!winid) return + nvim.call('coc#float#close', [winid], true) + nvim.redrawVim() + } +} diff --git a/sources_non_forked/coc.nvim/src/completion/index.ts b/sources_non_forked/coc.nvim/src/completion/index.ts new file mode 100644 index 00000000..488c935c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/index.ts @@ -0,0 +1,600 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events, { InsertChange, PopupChangeEvent } from '../events' +import Document from '../model/document' +import sources from '../sources' +import { CompleteOption, ExtendedCompleteItem, FloatConfig, ISource, VimCompleteItem } from '../types' +import { disposeAll } from '../util' +import * as Is from '../util/is' +import { equals } from '../util/object' +import { byteLength, byteSlice, characterIndex, isWord } from '../util/string' +import workspace from '../workspace' +import Complete, { CompleteConfig } from './complete' +import Floating, { PumBounding } from './floating' +import MruLoader from './mru' +import { shouldIndent, shouldStop, waitInsertEvent, waitTextChangedI } from './util' +const logger = require('../util/logger')('completion') +const completeItemKeys = ['abbr', 'menu', 'info', 'kind', 'icase', 'dup', 'empty', 'user_data'] + +export interface LastInsert { + character: string + timestamp: number +} + +export class Completion implements Disposable { + public config: CompleteConfig + private nvim: Neovim + private pretext: string | undefined + private hasInsert = false + private activated = false + private changedtick: number + private triggerTimer: NodeJS.Timer + private popupEvent: PopupChangeEvent + private floating: Floating + private disposables: Disposable[] = [] + private complete: Complete | null = null + private resolveTokenSource: CancellationTokenSource + // saved for commit character. + private previousItem: VimCompleteItem | {} | undefined + private mru: MruLoader + + public init(): void { + this.nvim = workspace.nvim + this.config = this.getCompleteConfig() + this.mru = new MruLoader(this.config.selection) + void this.mru.load() + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('suggest')) { + this.config = this.getCompleteConfig() + } + }, null, this.disposables) + this.floating = new Floating(workspace.nvim, workspace.env.isVim) + events.on('InsertLeave', () => { + this.stop() + }, null, this.disposables) + events.on('CursorMovedI', (bufnr, cursor, hasInsert) => { + if (this.triggerTimer) clearTimeout(this.triggerTimer) + if (hasInsert || !this.option || bufnr !== this.option.bufnr) return + if (this.option.linenr === cursor[0]) { + let doc = workspace.getDocument(bufnr) + let line = doc.getline(cursor[0] - 1) + let idx = characterIndex(line, cursor[1] - 1) + let start = characterIndex(line, this.option.colnr - 1) + if (start < idx) { + let text = line.substring(start, idx) + if (doc.isWord(text)) return + } + } + this.stop() + }, null, this.disposables) + events.on('InsertEnter', this.onInsertEnter, this, this.disposables) + events.on('TextChangedP', this.onTextChangedP, this, this.disposables) + events.on('TextChangedI', this.onTextChangedI, this, this.disposables) + events.on('CompleteDone', async item => { + this.previousItem = this.popupEvent?.completed_item + this.popupEvent = null + this.hasInsert = false + if (!this.activated || item.closed) return + this.cancelResolve() + if (item.close) return this.stop() + if (!Is.vimCompleteItem(item)) { + let ev = await waitInsertEvent() + if (ev == 'CursorMovedI') this.stop() + } else { + await this.onCompleteDone(item) + } + }, null, this.disposables) + events.on('MenuPopupChanged', async ev => { + if (!this.activated || this.document?.isCommandLine) return + if (equals(this.popupEvent, ev)) return + this.cancelResolve() + this.popupEvent = ev + await this.onPumChange() + }, null, this.disposables) + } + + public get option(): CompleteOption { + if (!this.complete) return null + return this.complete.option + } + + private get selectedItem(): VimCompleteItem | null { + if (!this.popupEvent) return null + let { completed_item } = this.popupEvent + return Is.vimCompleteItem(completed_item) ? completed_item : null + } + + public get isActivated(): boolean { + return this.activated + } + + private get document(): Document | null { + if (!this.option) return null + return workspace.getDocument(this.option.bufnr) + } + + private getCompleteConfig(): CompleteConfig { + let suggest = workspace.getConfiguration('suggest') + function getConfig(key, defaultValue: T): T { + return suggest.get(key, defaultValue) + } + let keepCompleteopt = getConfig('keepCompleteopt', false) + let autoTrigger = getConfig('autoTrigger', 'always') + if (keepCompleteopt && autoTrigger != 'none') { + let { completeOpt } = workspace + if (!completeOpt.includes('noinsert') && !completeOpt.includes('noselect')) { + keepCompleteopt = false + this.nvim.echoError('suggest.keepCompleteopt disabled, completeopt should includes noinsert or noselect') + } + } + let floatEnable = workspace.floatSupported && getConfig('floatEnable', true) + let acceptSuggestionOnCommitCharacter = workspace.env.pumevent && getConfig('acceptSuggestionOnCommitCharacter', false) + return { + autoTrigger, + floatEnable, + keepCompleteopt, + selection: getConfig<'none' | 'recentlyUsed' | 'recentlyUsedByPrefix'>('selection', 'recentlyUsed'), + floatConfig: getConfig('floatConfig', {}), + defaultSortMethod: getConfig('defaultSortMethod', 'length'), + removeDuplicateItems: getConfig('removeDuplicateItems', false), + disableMenuShortcut: getConfig('disableMenuShortcut', false), + acceptSuggestionOnCommitCharacter, + disableKind: getConfig('disableKind', false), + disableMenu: getConfig('disableMenu', false), + previewIsKeyword: getConfig('previewIsKeyword', '@,48-57,_192-255'), + enablePreview: getConfig('enablePreview', false), + enablePreselect: getConfig('enablePreselect', false), + triggerCompletionWait: getConfig('triggerCompletionWait', 0), + labelMaxLength: getConfig('labelMaxLength', 200), + triggerAfterInsertEnter: getConfig('triggerAfterInsertEnter', false), + noselect: getConfig('noselect', true), + maxItemCount: getConfig('maxCompleteItemCount', 50), + timeout: getConfig('timeout', 500), + minTriggerInputLength: getConfig('minTriggerInputLength', 1), + snippetIndicator: getConfig('snippetIndicator', '~'), + fixInsertedWord: getConfig('fixInsertedWord', true), + localityBonus: getConfig('localityBonus', true), + highPrioritySourceLimit: getConfig('highPrioritySourceLimit', null), + lowPrioritySourceLimit: getConfig('lowPrioritySourceLimit', null), + ignoreRegexps: getConfig('ignoreRegexps', []), + asciiCharactersOnly: getConfig('asciiCharactersOnly', false) + } + } + + public async startCompletion(option: CompleteOption, sourceList?: ISource[]): Promise { + try { + let doc = workspace.getAttachedDocument(option.bufnr) + option.filetype = doc.filetype + logger.debug('trigger completion with', option) + this.stop() + this.pretext = byteSlice(option.line, 0, option.colnr - 1) + sourceList = sourceList ?? this.getSources(option) + if (!sourceList || sourceList.length === 0) return + events.completing = true + this.changedtick = option.changedtick + let complete = this.complete = new Complete( + option, + doc, + this.config, + sourceList, + this.mru, + this.nvim) + complete.onDidRefresh(async () => { + if (this.triggerTimer != null) { + clearTimeout(this.triggerTimer) + } + if (complete.isEmpty) { + this.stop() + return + } + if (this.hasInsert) return + await this.filterResults() + }) + await complete.doComplete() + } catch (e) { + this.stop() + this.nvim.echoError(e) + } + } + + public getSources(option: CompleteOption): ISource[] { + let { source } = option + if (source) { + let s = sources.getSource(source) + return s ? [s] : [] + } + return sources.getCompleteSources(option) + } + + public hasSelected(): boolean { + if (workspace.env.pumevent) return this.selectedItem != null + // it's not correct + if (!this.config.noselect) return true + return false + } + + private showCompletion(items: ExtendedCompleteItem[]): void { + let { nvim, option, changedtick } = this + if (!option) return + let { disableKind, labelMaxLength, disableMenuShortcut, disableMenu } = this.config + let preselect = this.config.enablePreselect ? items.findIndex(o => o.preselect) : -1 + let validKeys = completeItemKeys.slice() + if (disableKind) validKeys = validKeys.filter(s => s != 'kind') + if (disableMenu) validKeys = validKeys.filter(s => s != 'menu') + let vimItems = items.map(item => { + let obj = { word: item.word, equal: 1 } + for (let key of validKeys) { + if (item.hasOwnProperty(key)) { + if (disableMenuShortcut && key == 'menu') { + obj[key] = item[key].replace(/\[.+\]$/, '') + } else if (key == 'abbr' && item[key].length > labelMaxLength) { + obj[key] = item[key].slice(0, labelMaxLength) + } else { + obj[key] = item[key] + } + } + } + return obj + }) + nvim.pauseNotification() + if (vimItems.length) this.start() + nvim.call('coc#_do_complete', [option.col, vimItems, preselect, changedtick], true) + nvim.resumeNotification(false, true) + } + + private async onTextChangedP(bufnr: number, info: InsertChange): Promise { + let { option, document } = this + if (!option || option.bufnr != bufnr) return + if ((info.insertChar || this.pretext == info.pre) && shouldIndent(option.indentkeys, info.pre)) { + logger.debug(`trigger indent by ${info.pre}`) + let indentChanged = await this.nvim.call('coc#complete_indent', []) + if (indentChanged) return + } + this.changedtick = info.changedtick + if (this.pretext == info.pre) return + let pretext = this.pretext = info.pre + if (info.pre.match(/^\s*/)[0] !== option.line.match(/^\s*/)[0]) { + this.stop() + let res = await events.race(['TextChangedI', 'InsertCharPre'], 50) + if (res.name === 'TextChangedI') { + await this.triggerCompletion(document, res.args[1] as InsertChange) + } + return + } + // Avoid resume when TextChangedP caused by or + if (this.selectedItem && !info.insertChar) { + let expected = byteSlice(option.line, 0, option.col) + this.selectedItem.word + if (expected == pretext) { + this.hasInsert = true + return + } + } + await this.filterResults() + } + + private async onTextChangedI(bufnr: number, info: InsertChange): Promise { + if (!workspace.isAttached(bufnr) || this.config.autoTrigger === 'none') return + if (this.option && shouldStop(bufnr, this.pretext, info, this.option)) { + this.stop() + if (!info.insertChar) return + } + this.changedtick = info.changedtick + if (info.pre === this.pretext) return + if (this.triggerTimer) clearTimeout(this.triggerTimer) + let pretext = this.pretext = info.pre + let doc = workspace.getDocument(bufnr) + // check commit + if (this.activated && this.config.acceptSuggestionOnCommitCharacter && Is.vimCompleteItem(this.previousItem)) { + let resolvedItem = this.getCompleteItem(this.previousItem) + let last = pretext.slice(-1) + if (sources.shouldCommit(resolvedItem, last)) { + logger.debug('commit by commit character.') + let { linenr, col, line, colnr } = this.option + this.stop() + let { word } = resolvedItem + let newLine = `${line.slice(0, col)}${word}${info.insertChar}${line.slice(colnr - 1)}` + await this.nvim.call('coc#util#setline', [linenr, newLine]) + let curcol = col + word.length + 2 + await this.nvim.call('cursor', [linenr, curcol]) + await doc.patchChange() + return + } + } + // trigger character + if (info.insertChar && !isWord(info.insertChar)) { + let disabled = doc.getVar('disabled_sources', []) + let triggerSources = sources.getTriggerSources(pretext, doc.filetype, doc.uri, disabled) + if (triggerSources.length > 0) { + await this.triggerCompletion(doc, info, triggerSources) + return + } + } + // trigger by normal character + if (!this.complete) { + if (!info.insertChar) return + await this.triggerCompletion(doc, info) + return + } + if (info.insertChar && this.complete.isEmpty) { + // triggering without results + this.triggerTimer = setTimeout(async () => { + await this.triggerCompletion(doc, info) + }, 200) + return + } + await this.filterResults() + } + + private async triggerCompletion(doc: Document, info: InsertChange, sources?: ISource[]): Promise { + let { minTriggerInputLength } = this.config + let { pre } = info + // check trigger + if (!sources) { + let shouldTrigger = this.shouldTrigger(doc, pre) + if (!shouldTrigger) return false + } + let disable = doc.getVar('suggest_disable') + if (disable) { + logger.warn(`Completion of ${doc.bufnr} disabled by b:coc_suggest_disable`) + return false + } + let input = this.getInput(doc, pre) + let option: CompleteOption = { + input, + line: info.line, + filetype: doc.filetype, + linenr: info.lnum, + col: info.col - 1 - byteLength(input), + colnr: info.col, + bufnr: doc.bufnr, + word: input + this.getPrependWord(doc, info.line.slice(pre.length)), + changedtick: info.changedtick, + indentkeys: doc.indentkeys, + synname: '', + filepath: doc.schema === 'file' ? URI.parse(doc.uri).fsPath : '', + triggerCharacter: pre.length ? pre.slice(-1) : undefined, + blacklist: doc.getVar('suggest_blacklist', []), + disabled: doc.getVar('disabled_sources', []), + } + if (sources == null && input.length < minTriggerInputLength) { + logger.warn(`Suggest not triggered with input "${input}", minimal trigger input length: ${minTriggerInputLength}`) + return false + } + if (option.blacklist && option.blacklist.includes(option.input)) { + logger.warn(`Suggest disabled by b:coc_suggest_blacklist`, option.blacklist) + return false + } + if (this.config.ignoreRegexps.length > 0 && option.input.length > 0) { + const ignore = this.config.ignoreRegexps.some(regexp => { + if (new RegExp(regexp).test(option.input)) { + logger.warn(`Suggest disabled by ignore regexp: ${regexp}`) + return true + } + }) + if (ignore) return false + } + // if (pre.length) option.triggerCharacter = pre[pre.length - 1] + await this.startCompletion(option, sources) + return true + } + + private async onCompleteDone(item: VimCompleteItem): Promise { + let { document, complete } = this + if (!document || !Is.vimCompleteItem(item)) return + let input = complete.input + let opt = Object.assign({}, this.option) + let resolvedItem = this.getCompleteItem(item) + this.stop() + if (!resolvedItem) return + this.mru.add(input, resolvedItem) + let insertChange = await waitTextChangedI() + if (typeof insertChange === 'string') return + if (insertChange && (insertChange.lnum != opt.linenr || insertChange.pre !== byteSlice(opt.line, 0, opt.col) + item.word)) return + let res = await events.race(['InsertCharPre', 'CursorMovedI'], 20) + if (res) return + let source = new CancellationTokenSource() + let { token } = source + await this.doCompleteResolve(resolvedItem, source) + if (token.isCancellationRequested) return + await this.doCompleteDone(resolvedItem, opt) + } + + private doCompleteResolve(item: ExtendedCompleteItem, tokenSource: CancellationTokenSource): Promise { + let source = sources.getSource(item.source) + return new Promise(resolve => { + if (source && typeof source.onCompleteResolve === 'function') { + let timer = setTimeout(() => { + tokenSource.cancel() + logger.warn(`Resolve timeout after 500ms: ${source.name}`) + resolve() + }, 500) + Promise.resolve(source.onCompleteResolve(item, tokenSource.token)).then(() => { + clearTimeout(timer) + resolve() + }, e => { + logger.error(`Error on complete resolve: ${e.message}`, e) + clearTimeout(timer) + resolve() + }) + } else { + resolve() + } + }) + } + + public async doCompleteDone(item: ExtendedCompleteItem, opt: CompleteOption): Promise { + let source = sources.getSource(item.source) + if (source && typeof source.onCompleteDone === 'function') { + await Promise.resolve(source.onCompleteDone(item, opt)) + } + } + + private async onInsertEnter(bufnr: number): Promise { + if (!this.config.triggerAfterInsertEnter || this.config.autoTrigger !== 'always') return + if (!workspace.isAttached(bufnr)) return + let change = await this.nvim.call('coc#util#change_info') as InsertChange + change.pre = byteSlice(change.line, 0, change.col - 1) + if (!change.pre) return + let doc = workspace.getDocument(bufnr) + await this.triggerCompletion(doc, change) + } + + public shouldTrigger(doc: Document, pre: string): boolean { + let { autoTrigger } = this.config + if (autoTrigger == 'none') return false + if (sources.shouldTrigger(pre, doc.filetype, doc.uri)) return true + if (autoTrigger !== 'always') return false + return true + } + + private async onPumChange(): Promise { + if (!this.popupEvent) return + let { col, row, height, width, scrollbar } = this.popupEvent + let bounding: PumBounding = { col, row, height, width, scrollbar } + let resolvedItem = this.getCompleteItem(this.selectedItem) + if (!resolvedItem) { + this.floating.close() + return + } + let source = this.resolveTokenSource = new CancellationTokenSource() + let { token } = source + await this.doCompleteResolve(resolvedItem, source) + if (token.isCancellationRequested) return + let docs = resolvedItem.documentation + if (!docs && resolvedItem.info) { + let { info } = resolvedItem + let isText = /^[\w-\s.,\t]+$/.test(info) + docs = [{ filetype: isText ? 'txt' : this.document.filetype, content: info }] + } + if (!this.config.floatEnable) return + if (!docs || docs.length == 0) { + this.floating.close() + } else { + let excludeImages = workspace.getConfiguration('coc.preferences').get('excludeImageLinksInMarkdownDocument') + let config = Object.assign({}, this.config.floatConfig, { excludeImages }) + await this.floating.show(docs, bounding, config) + } + } + + public start(): void { + if (this.activated) return + this.activated = true + if (!this.config.keepCompleteopt) { + this.nvim.command(`noa set completeopt=${this.completeOpt}`, true) + } + } + + private cancelResolve(): void { + if (this.resolveTokenSource) { + this.resolveTokenSource.cancel() + this.resolveTokenSource.dispose() + this.resolveTokenSource = null + } + } + + public stop(): void { + events.completing = false + this.cancel() + if (this.activated) { + this.activated = false + let { nvim, config } = this + let completeOpt = config.keepCompleteopt ? '' : workspace.completeOpt + nvim.call('coc#_cancel', [1, completeOpt], true) + nvim.redrawVim() + } + } + + public getInput(document: Document, pre: string): string { + let { asciiCharactersOnly } = this.config + let len = 0 + for (let i = pre.length - 1; i >= 0; i--) { + let ch = pre[i] + let word = document.isWord(ch) && (asciiCharactersOnly ? ch.charCodeAt(0) < 255 : true) + if (word) { + len += 1 + } else { + break + } + } + return len == 0 ? '' : pre.slice(-len) + } + + private getPrependWord(document: Document, remain: string): string { + let idx = 0 + for (let i = 0; i < remain.length; i++) { + if (document.isWord(remain[i])) { + idx = i + 1 + } else { + break + } + } + return idx == 0 ? '' : remain.slice(0, idx) + } + + public getResumeInput(): string { + let { option, pretext, document } = this + if (!option || !document) return null + let buf = Buffer.from(pretext, 'utf8') + if (buf.length < option.colnr - 1) return null + let pre = byteSlice(option.line, 0, option.colnr - 1) + if (!pretext.startsWith(pre)) return null + let remain = pretext.slice(pre.length) + if (remain.includes(' ')) return null + let input = buf.slice(option.col).toString('utf8') + if (input.length > 0 && option.blacklist && option.blacklist.includes(input)) return null + return input + } + + private async filterResults(): Promise { + let { complete } = this + let search = this.getResumeInput() + if (search == null) { + this.stop() + return + } + let items = await complete.filterResults(search) + // cancelled + if (items === undefined) return + if (items.length == 0) { + if (!complete.isCompleting) this.stop() + return + } + this.showCompletion(items) + } + + private get completeOpt(): string { + let { noselect, enablePreview } = this.config + let preview = enablePreview && !workspace.env.pumevent ? ',preview' : '' + if (noselect) return `noselect,menuone${preview}` + return `noinsert,menuone${preview}` + } + + private getCompleteItem(item: VimCompleteItem | {} | null): ExtendedCompleteItem | null { + if (!this.complete || !Is.vimCompleteItem(item)) return null + return this.complete.resolveCompletionItem(item) + } + + private cancel(): void { + if (this.complete != null) { + this.complete.dispose() + this.complete = null + } + if (this.triggerTimer != null) { + clearTimeout(this.triggerTimer) + this.triggerTimer = null + } + this.cancelResolve() + this.previousItem = undefined + this.pretext = undefined + this.hasInsert = false + } + + public dispose(): void { + this.cancelResolve() + disposeAll(this.disposables) + } +} + +export default new Completion() diff --git a/sources_non_forked/coc.nvim/src/completion/match.ts b/sources_non_forked/coc.nvim/src/completion/match.ts new file mode 100644 index 00000000..837d0930 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/match.ts @@ -0,0 +1,98 @@ +'use strict' +import { findIndex } from '../util/array' +import { getCharCodes, wordChar } from '../util/fuzzy' +import { getNextWord } from '../util/string' + +export function caseScore(input: number, curr: number, divide = 1): number { + if (input === curr) return 1 / divide + if (curr + 32 === input) return 0.5 / divide + return 0 +} + +/** + * Rules: + * - First strict 5, first case match 2.5 + * - First word character strict 2.5, first word character case 2 + * - First fuzzy match strict 1, first fuzzy case 0.5 + * - Follow strict 1, follow case 0.5 + * - Follow word start 1, follow word case 0.75 + * - First fuzzy strict 0.1, first fuzzy case 0.05 + * + * @public + * @param {string} word + * @param {number[]} input + * @returns {number} + */ +export function matchScore(word: string, input: number[]): number { + if (input.length == 0 || word.length < input.length) return 0 + let next = nextScore(getCharCodes(word), 0, input, []) + return next == null ? 0 : next[0] +} + +export function matchScoreWithPositions(word: string, input: number[]): [number, ReadonlyArray] | undefined { + if (input.length == 0 || word.length < input.length) return undefined + return nextScore(getCharCodes(word), 0, input, []) +} + +/** + * Return score and positions. + */ +function nextScore(codes: ReadonlyArray, index: number, inputCodes: ReadonlyArray, positions: ReadonlyArray): [number, ReadonlyArray] | undefined { + if (inputCodes.length === 0) return [0, positions] + let len = codes.length + if (index >= len) return undefined + let input = inputCodes[0] + let nextCodes = inputCodes.slice(1) + // not alphabet + if (!wordChar(input)) { + let idx = findIndex(codes, input, index) + if (idx == -1) return undefined + let score = idx == 0 ? 5 : 1 + let next = nextScore(codes, idx + 1, nextCodes, [...positions, idx]) + return next === undefined ? undefined : [score + next[0], next[1]] + } + // check beginning + let isStart = positions.length == 0 + let score = caseScore(input, codes[index], isStart ? 0.2 : 1) + if (score > 0) { + let next = nextScore(codes, index + 1, nextCodes, [...positions, index]) + return next === undefined ? undefined : [score + next[0], next[1]] + } + // check next word + let positionMap: Map> = new Map() + let word = getNextWord(codes, index + 1) + if (word != null) { + let score = caseScore(input, word[1], isStart ? 0.5 : 1) + if (score > 0) { + let ps = [...positions, word[0]] + if (score === 0.5) score = 0.75 + let next = nextScore(codes, word[0] + 1, nextCodes, ps) + if (next !== undefined) positionMap.set(score + next[0], next[1]) + } + } + // find fuzzy + for (let i = index + 1; i < len; i++) { + let score = caseScore(input, codes[i], isStart ? 1 : 10) + if (score > 0) { + let next = nextScore(codes, i + 1, nextCodes, [...positions, i]) + if (next !== undefined) positionMap.set(score + next[0], next[1]) + break + } + } + if (positionMap.size == 0) { + // Try match previous position + if (positions.length > 0) { + let last = positions[positions.length - 1] + if (last > 0 && codes[last] !== input && codes[last - 1] === input) { + let ps = positions.slice() + ps.splice(positions.length - 1, 0, last - 1) + let next = nextScore(codes, last + 1, nextCodes, ps) + if (next === undefined) return undefined + return [0.5 + next[0], next[1]] + } + } + return undefined + } + let max = Math.max(...positionMap.keys()) + return [max, positionMap.get(max)] +} diff --git a/sources_non_forked/coc.nvim/src/completion/mru.ts b/sources_non_forked/coc.nvim/src/completion/mru.ts new file mode 100644 index 00000000..f7966d95 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/mru.ts @@ -0,0 +1,56 @@ +'use strict' +import Mru from '../model/mru' +import { ExtendedCompleteItem } from '../types' + +export type Selection = 'none' | 'recentlyUsed' | 'recentlyUsedByPrefix' + +export default class MruLoader { + private mru: Mru + private max = 0 + private items: Map = new Map() + private itemsNoPrefex: Map = new Map() + constructor(private selection: Selection) { + this.mru = new Mru(`suggest${globalThis.__TEST__ ? process.pid : ''}.txt`, process.env.COC_DATA_HOME, 1000) + } + + public async load(): Promise { + let { selection } = this + if (selection == 'none') return + let lines = await this.mru.load() + let total = lines.length + for (let i = total - 1; i >= 0; i--) { + let line = lines[i] + if (!line.includes('|')) continue + let [_prefix, label, source, kind] = line.split('|') + if (!source) continue + this.items.set(line, total - 1 - i) + this.itemsNoPrefex.set(`${label}|${source}|${kind || ''}`, total - 1 - i) + } + this.max = total - 1 + } + + public getScore(input: string, item: ExtendedCompleteItem): number { + let key = toItemKey(item) + if (input.length == 0) return this.itemsNoPrefex.get(key) ?? -1 + if (this.selection === 'recentlyUsedByPrefix') key = `${input}|${key}` + let map = this.selection === 'recentlyUsed' ? this.itemsNoPrefex : this.items + return map.get(key) ?? -1 + } + + public add(prefix: string, item: ExtendedCompleteItem): void { + if (this.selection == 'none') return + let key = toItemKey(item) + let line = `${prefix}|key` + this.items.set(line, this.max) + this.itemsNoPrefex.set(key, this.max) + this.max += 1 + void this.mru.add(line) + } +} + +function toItemKey(item: ExtendedCompleteItem): string { + let label = item.filterText + let source = item.source + let kind = item.kind ?? '' + return `${label}|${source}|${kind}` +} diff --git a/sources_non_forked/coc.nvim/src/completion/util.ts b/sources_non_forked/coc.nvim/src/completion/util.ts new file mode 100644 index 00000000..0b4e6b12 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/completion/util.ts @@ -0,0 +1,50 @@ +'use strict' +import events, { InsertChange } from '../events' +import { CompleteOption } from '../types' +import { byteSlice } from '../util/string' +const logger = require('../util/logger')('completion-util') + +export async function waitInsertEvent(): Promise { + let res = await events.race(['InsertLeave', 'CursorMovedI', 'MenuPopupChanged', 'TextChangedI', 'InsertCharPre'], 300) + return res?.name +} + +export async function waitTextChangedI(): Promise { + let res = await events.race(['InsertCharPre', 'CursorMoved', 'InsertLeave', 'TextChangedI'], 100) + if (!res || res.name !== 'TextChangedI') return res ? res.name : undefined + return res.args[1] as InsertChange +} + +export function shouldIndent(indentkeys = '', pretext: string): boolean { + if (!indentkeys) return false + for (let part of indentkeys.split(',')) { + if (part.indexOf('=') > -1) { + let [pre, post] = part.split('=') + let word = post.startsWith('~') ? post.slice(1) : post + if (pretext.length < word.length || + (pretext.length > word.length && !/^\s/.test(pretext.slice(-word.length - 1)))) { + continue + } + let matched = post.startsWith('~') ? pretext.toLowerCase().endsWith(word) : pretext.endsWith(word) + if (!matched) { + continue + } + if (pre == '') { + return true + } + if (pre == '0' && (pretext.length == word.length || /^\s*$/.test(pretext.slice(0, pretext.length - word.length)))) { + return true + } + } + } + return false +} + +export function shouldStop(bufnr: number, pretext: string, info: InsertChange, option: Pick): boolean { + let { pre } = info + if (pre.length === 0 || pre[pre.length - 1] === ' ' || pre.length < pretext.length) return true + if (option.bufnr != bufnr) return true + let text = byteSlice(option.line, 0, option.colnr - 1) + if (option.linenr != info.lnum || !pre.startsWith(text)) return true + return false +} diff --git a/sources_non_forked/coc.nvim/src/configuration/configuration.ts b/sources_non_forked/coc.nvim/src/configuration/configuration.ts new file mode 100644 index 00000000..b9f7d822 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/configuration/configuration.ts @@ -0,0 +1,71 @@ +'use strict' +import { ConfigurationModel } from './model' +import { IConfigurationData } from '../types' +export class Configuration { + private _consolidateConfiguration: ConfigurationModel + + constructor( + private _defaultConfiguration: ConfigurationModel, + private _userConfiguration: ConfigurationModel, + private _workspaceConfiguration: ConfigurationModel, + private _memoryConfiguration: ConfigurationModel = new ConfigurationModel(), + ) { + } + + private getConsolidateConfiguration(): ConfigurationModel { + if (!this._consolidateConfiguration) { + this._consolidateConfiguration = this._defaultConfiguration.merge(this._userConfiguration, this._workspaceConfiguration, this._memoryConfiguration) + this._consolidateConfiguration = this._consolidateConfiguration.freeze() + } + return this._consolidateConfiguration + } + + public getValue(section?: string): any { + let configuration = this.getConsolidateConfiguration() + return configuration.getValue(section) + } + + public inspect(key: string): { + default: C + user: C + workspace: C + memory?: C + value: C + } { + const consolidateConfigurationModel = this.getConsolidateConfiguration() + const { _workspaceConfiguration, _memoryConfiguration } = this + return { + default: this._defaultConfiguration.freeze().getValue(key), + user: this._userConfiguration.freeze().getValue(key), + workspace: _workspaceConfiguration.freeze().getValue(key), + memory: _memoryConfiguration.freeze().getValue(key), + value: consolidateConfigurationModel.getValue(key) + } + } + + public get defaults(): ConfigurationModel { + return this._defaultConfiguration + } + + public get user(): ConfigurationModel { + return this._userConfiguration + } + + public get workspace(): ConfigurationModel { + return this._workspaceConfiguration + } + + public toData(): IConfigurationData { + return { + defaults: { + contents: this._defaultConfiguration.contents + }, + user: { + contents: this._userConfiguration.contents + }, + workspace: { + contents: this._workspaceConfiguration.contents + } + } + } +} diff --git a/sources_non_forked/coc.nvim/src/configuration/index.ts b/sources_non_forked/coc.nvim/src/configuration/index.ts new file mode 100644 index 00000000..b9a6b1b8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/configuration/index.ts @@ -0,0 +1,417 @@ +'use strict' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import { ConfigurationChangeEvent, ConfigurationInspect, ConfigurationShape, ConfigurationTarget, ErrorItem, IConfigurationData, IConfigurationModel, WorkspaceConfiguration } from '../types' +import { CONFIG_FILE_NAME, disposeAll, watchFile } from '../util' +import { findUp, isParentFolder, sameFile } from '../util/fs' +import { objectLiteral } from '../util/is' +import { deepClone, deepFreeze, mixin } from '../util/object' +import { Configuration } from './configuration' +import { ConfigurationModel } from './model' +import { addToValueTree, getChangedKeys, loadDefaultConfigurations, parseContentFromFile } from './util' +const logger = require('../util/logger')('configurations') + +function lookUp(tree: any, key: string): any { + if (key) { + if (tree && tree.hasOwnProperty(key)) return tree[key] + const parts = key.split('.') + let node = tree + for (let i = 0; node && i < parts.length; i++) { + node = node[parts[i]] + } + return node + } + return tree +} + +export default class Configurations { + public cwd = process.cwd() + private _configuration: Configuration + private _errorItems: ErrorItem[] = [] + private _folderConfigurations: Map = new Map() + private _onError = new Emitter() + private _onChange = new Emitter() + private disposables: Disposable[] = [] + private workspaceConfigFile: string | undefined + + public readonly onError: Event = this._onError.event + public readonly onDidChange: Event = this._onChange.event + + constructor( + private userConfigFile?: string | null, + private readonly _proxy?: ConfigurationShape + ) { + let user = this.parseContentFromFile(userConfigFile) + let data: IConfigurationData = { + defaults: loadDefaultConfigurations(), + user, + workspace: { contents: {} } + } + this._configuration = Configurations.parse(data) + this.watchFile(userConfigFile, ConfigurationTarget.User) + this.addFolderFromCwd() + } + + private parseContentFromFile(filepath: string): IConfigurationModel { + if (!filepath) return { contents: {} } + let uri = URI.file(filepath).toString() + this._errorItems = this._errorItems.filter(o => o.location.uri != uri) + let res = parseContentFromFile(filepath, errors => { + this._errorItems.push(...errors) + }) + this._onError.fire(this._errorItems) + return res + } + + public get errorItems(): ErrorItem[] { + return this._errorItems + } + + public get foldConfigurations(): Map { + return this._folderConfigurations + } + + // used for extensions, no change event fired + public extendsDefaults(props: { [key: string]: any }): void { + let { defaults } = this._configuration + let { contents } = defaults + contents = deepClone(contents) + Object.keys(props).forEach(key => { + addToValueTree(contents, key, props[key], msg => { + logger.error(msg) + }) + }) + let data: IConfigurationData = { + defaults: { contents }, + user: this._configuration.user, + workspace: this._configuration.workspace + } + this._configuration = Configurations.parse(data) + } + + // change user configuration, without change file + public updateUserConfig(props: { [key: string]: any }): void { + if (!props || Object.keys(props).length == 0) return + let { user } = this._configuration + let model = user.clone() + Object.keys(props).forEach(key => { + let val = props[key] + if (val === undefined) { + model.removeValue(key) + } else if (objectLiteral(val)) { + for (let k of Object.keys(val)) { + model.setValue(`${key}.${k}`, val[k]) + } + } else { + model.setValue(key, val) + } + }) + this.changeConfiguration(ConfigurationTarget.User, model, undefined) + } + + public get defaults(): ConfigurationModel { + return this._configuration.defaults + } + + public get user(): ConfigurationModel { + return this._configuration.user + } + + public get workspace(): ConfigurationModel { + return this._configuration.workspace + } + + public addFolderFile(filepath: string, change = true, fromCwd = false): boolean { + if (!fs.existsSync(filepath)) return false + if (sameFile(this.userConfigFile, filepath)) return false + if (sameFile(filepath, path.join(os.homedir(), `.vim/${CONFIG_FILE_NAME}`))) return false + if (!this._folderConfigurations.has(filepath)) { + this.watchFile(filepath, ConfigurationTarget.Workspace) + } + let model = this.updateFolderConfiguration(filepath) + logger.info(`Add folder configuration from ${fromCwd ? 'cwd' : 'file'}:`, filepath) + if (!change) return true + if (this.workspaceConfigFile !== filepath) { + this.workspaceConfigFile = filepath + logger.info(`Change folder configuration from ${fromCwd ? 'cwd' : 'file'} to:`, filepath) + this.changeConfiguration(ConfigurationTarget.Workspace, model, filepath) + } + return true + } + + public addFolderFromCwd(): void { + let filepath = path.join(this.cwd, `.vim/${CONFIG_FILE_NAME}`) + this.addFolderFile(filepath, true, true) + } + + private watchFile(filepath: string, target: ConfigurationTarget): void { + if (!fs.existsSync(filepath) || global.__TEST__) return + let isWorkspace = target === ConfigurationTarget.Workspace + let disposable = watchFile(filepath, () => { + let model = this.parseContentFromFile(filepath) + if (isWorkspace) { + this._folderConfigurations.set(filepath, new ConfigurationModel(model.contents)) + if (sameFile(this.workspaceConfigFile, filepath)) { + this.changeConfiguration(target, model, filepath) + } + } else { + this.changeConfiguration(target, model, filepath) + } + }) + this.disposables.push(disposable) + } + + private updateFolderConfiguration(configFile: string): IConfigurationModel { + let model = this.parseContentFromFile(configFile) + this._folderConfigurations.set(configFile, new ConfigurationModel(model.contents)) + return model + } + + // create new configuration and fire change event + private changeConfiguration(target: ConfigurationTarget, model: IConfigurationModel, folderConfigFile: string | undefined): void { + let { defaults, user, workspace } = this._configuration + let data: IConfigurationData = { + defaults: target == ConfigurationTarget.Global ? model : defaults, + user: target == ConfigurationTarget.User ? model : user, + workspace: target == ConfigurationTarget.Workspace ? model : workspace, + } + let configuration = Configurations.parse(data) + let changed = getChangedKeys(this._configuration.getValue(), configuration.getValue()) + if (changed.length == 0) return + this._configuration = configuration + this._onChange.fire({ + affectsConfiguration: (section, resource) => { + if (!resource || !resource.startsWith('file:') || target != ConfigurationTarget.Workspace) { + return changed.includes(section) + } + let u = URI.parse(resource) + let filepath = u.fsPath + if (folderConfigFile && !isParentFolder(path.resolve(folderConfigFile, '../..'), filepath)) { + return false + } + return changed.includes(section) + } + }) + } + + private getFolderConfigFile(filepath: string): string | undefined { + let { folders } = this + let folder = folders.find(f => isParentFolder(f, filepath, true)) + return folder ? path.join(folder, `.vim/${CONFIG_FILE_NAME}`) : undefined + } + + public getConfigFile(target: ConfigurationTarget): string { + if (target == ConfigurationTarget.Global) return null + if (target == ConfigurationTarget.User) return this.userConfigFile + return this.workspaceConfigFile + } + + private get folders(): string[] { + let res: string[] = [] + let { _folderConfigurations } = this + for (let folder of _folderConfigurations.keys()) { + res.push(path.resolve(folder, '../..')) + } + return res + } + + public get configuration(): Configuration { + return this._configuration + } + + public getWorkspaceConfigUri(resource?: string): URI { + let uri: URI + if (!resource) { + uri = this.workspaceConfigFile ? URI.file(this.workspaceConfigFile) : undefined + } + if (!uri && this._proxy && typeof this._proxy.getWorkspaceConfig === 'function') { + // fallback to check workspace folder. + uri = this._proxy.getWorkspaceConfig(resource) + if (uri && sameFile(this.userConfigFile, uri.fsPath)) { + uri = undefined + } + } + return uri + } + + /** + * getConfiguration + * + * @public + * @param {string} section + * @returns {WorkspaceConfiguration} + */ + public getConfiguration(section?: string, resource?: string): WorkspaceConfiguration { + let configuration: Configuration + let localConfig: URI | undefined + if (resource) { + let { defaults, user } = this._configuration + let [configUri, model] = this.getFolderConfiguration(resource) + localConfig = configUri + configuration = new Configuration(defaults, user, model) + } else { + localConfig = this.workspaceConfigFile ? URI.file(this.workspaceConfigFile) : undefined + configuration = this._configuration + } + const config = Object.freeze(lookUp(configuration.getValue(null), section)) + const result: WorkspaceConfiguration = { + has(key: string): boolean { + return typeof lookUp(config, key) !== 'undefined' + }, + get: (key: string, defaultValue?: T) => { + let result: T = lookUp(config, key) + if (result == null) return defaultValue + return result + }, + update: (key: string, value?: any, isUser = false) => { + let s = section ? `${section}.${key}` : key + let target = isUser ? ConfigurationTarget.User : ConfigurationTarget.Workspace + let model = target == ConfigurationTarget.User ? this.user.clone() : this.workspace.clone() + if (value === undefined) { + model.removeValue(s) + } else { + model.setValue(s, value) + } + if (!localConfig) localConfig = this.getWorkspaceConfigUri(resource) + if (localConfig && !sameFile(this.workspaceConfigFile, localConfig.fsPath)) { + logger.info(`Change folder configuration ${resource ? 'by ' + resource : ''} to:`, localConfig.fsPath) + this.workspaceConfigFile = localConfig.fsPath + } + this.changeConfiguration(target, model, target == ConfigurationTarget.Workspace ? this.workspaceConfigFile : this.userConfigFile) + if (!isUser && !localConfig) { + if (!global.__TEST__) console.error(`Unable to locate workspace configuration ${resource ? 'for ' + resource : ''}, workspace folder not resolved.`) + logger.error(`Unable to locate workspace configuration`, resource) + return + } + let uri: URI = isUser ? URI.parse(this.userConfigFile) : localConfig + if (this._proxy && !global.__TEST__) { + if (value === undefined) { + this._proxy.$removeConfigurationOption(target, s, { resource: uri }) + } else { + this._proxy.$updateConfigurationOption(target, s, value, { resource: uri }) + } + } + if (!isUser && localConfig) this.addFolderFile(localConfig.fsPath, false) + }, + inspect: (key: string): ConfigurationInspect => { + key = section ? `${section}.${key}` : key + const config = this._configuration.inspect(key) + return { + key, + defaultValue: config.default, + globalValue: config.user, + workspaceValue: config.workspace, + } + } + } + Object.defineProperty(result, 'has', { + enumerable: false + }) + Object.defineProperty(result, 'get', { + enumerable: false + }) + Object.defineProperty(result, 'update', { + enumerable: false + }) + Object.defineProperty(result, 'inspect', { + enumerable: false + }) + + if (typeof config === 'object') { + mixin(result, config, false) + } + return deepFreeze(result) + } + + /** + * Get folder configuration URI & model, create model when configuration file found. + */ + public getFolderConfiguration(uri: string): [URI | undefined, ConfigurationModel] { + let u = URI.parse(uri) + let dir: string + if (u.scheme != 'file') { + dir = this.cwd + } else { + dir = u.fsPath + } + for (let [configFile, model] of this.foldConfigurations) { + let root = path.resolve(configFile, '../..') + if (isParentFolder(root, dir, true)) return [URI.file(configFile), model] + } + return [undefined, new ConfigurationModel()] + } + + /** + * Resolve folder configuration from uri, returns resolved config file path. + */ + public resolveFolderConfigution(uri: string): string | undefined { + let u = URI.parse(uri) + if (u.scheme != 'file') return + let rootPath = path.dirname(u.fsPath) + let configFile = this.getFolderConfigFile(rootPath) + if (configFile) return configFile + let folder = findUp('.vim', rootPath) + if (!folder) return + let filepath = path.join(folder, CONFIG_FILE_NAME) + let added = this.addFolderFile(filepath, false) + if (!added) return + return filepath + } + + /** + * Try to change current workspace configuration by uri + */ + public setFolderConfiguration(uri: string): void { + let u = URI.parse(uri) + if (u.scheme != 'file') return + let filepath = u.fsPath + for (let [configFile, model] of this.foldConfigurations) { + let root = path.resolve(configFile, '../..') + if (isParentFolder(root, filepath, true)) { + if (this.workspaceConfigFile != configFile) { + this.workspaceConfigFile = configFile + logger.info(`Change folder configuration to:`, configFile) + this.changeConfiguration(ConfigurationTarget.Workspace, model, configFile) + } + break + } + } + } + + private static parse(data: IConfigurationData): Configuration { + const defaultConfiguration = new ConfigurationModel(data.defaults.contents) + const userConfiguration = new ConfigurationModel(data.user.contents) + const workspaceConfiguration = new ConfigurationModel(data.workspace.contents) + return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration, new ConfigurationModel()) + } + + /** + * Reset configurations + */ + public reset(): void { + this._errorItems = [] + this._folderConfigurations.clear() + let user = this.parseContentFromFile(this.userConfigFile) + let data: IConfigurationData = { + defaults: loadDefaultConfigurations(), + user, + workspace: { contents: {} } + } + this._configuration = Configurations.parse(data) + this._onChange.fire({ + affectsConfiguration: () => { + return true + } + }) + } + + public dispose(): void { + this._folderConfigurations.clear() + this._onError.dispose() + this._onChange.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/configuration/model.ts b/sources_non_forked/coc.nvim/src/configuration/model.ts new file mode 100644 index 00000000..8e3b881c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/configuration/model.ts @@ -0,0 +1,65 @@ +'use strict' +import { IConfigurationModel } from '../types' +import { objectLiteral } from '../util/is' +import { deepClone } from '../util/object' +import { addToValueTree, getConfigurationValue, removeFromValueTree } from './util' + +export class ConfigurationModel implements IConfigurationModel { + + constructor(private _contents: any = {}) { } + + public get contents(): any { + return this._contents + } + + public clone(): ConfigurationModel { + return new ConfigurationModel(deepClone(this._contents)) + } + + public getValue(section: string): V { + let res = section + ? getConfigurationValue(this.contents, section) + : this.contents + return res + } + + public merge(...others: ConfigurationModel[]): ConfigurationModel { + const contents = deepClone(this.contents) + + for (const other of others) { + this.mergeContents(contents, other.contents) + } + return new ConfigurationModel(contents) + } + + public freeze(): ConfigurationModel { + if (!Object.isFrozen(this._contents)) { + Object.freeze(this._contents) + } + return this + } + + private mergeContents(source: any, target: any): void { + for (const key of Object.keys(target)) { + if (key in source) { + if (objectLiteral(source[key]) && objectLiteral(target[key])) { + this.mergeContents(source[key], target[key]) + continue + } + } + source[key] = deepClone(target[key]) + } + } + + // Update methods + + public setValue(key: string, value: any): void { + addToValueTree(this.contents, key, value, message => { + console.error(message) + }) + } + + public removeValue(key: string): void { + removeFromValueTree(this.contents, key) + } +} diff --git a/sources_non_forked/coc.nvim/src/configuration/shape.ts b/sources_non_forked/coc.nvim/src/configuration/shape.ts new file mode 100644 index 00000000..dbec8e27 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/configuration/shape.ts @@ -0,0 +1,61 @@ +'use strict' +import fs from 'fs' +import { applyEdits, modify } from 'jsonc-parser' +import os from 'os' +import path from 'path' +import { WorkspaceFolder } from 'vscode-languageserver-protocol' +import { FormattingOptions } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import { ConfigurationShape, ConfigurationTarget, IConfigurationOverrides } from '../types' +import { CONFIG_FILE_NAME } from '../util' +import { sameFile } from '../util/fs' +const logger = require('../util/logger')('configuration-shape') + +interface IFolderController { + root?: string + getWorkspaceFolder?: (resource: string) => WorkspaceFolder +} + +export default class ConfigurationProxy implements ConfigurationShape { + + constructor(private resolver: IFolderController) { + } + + public modifyConfiguration(uri: URI | undefined, key: string, value?: any): void { + if (!uri || uri.scheme !== 'file') return + logger.info('modify configuration file:', uri.fsPath) + let file = uri.fsPath + let dir = path.dirname(file) + let formattingOptions: FormattingOptions = { tabSize: 2, insertSpaces: true } + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }) + let content = fs.readFileSync(file, { encoding: 'utf8', flag: 'a+' }) + content = content || '{}' + let edits = modify(content, [key], value, { formattingOptions }) + content = applyEdits(content, edits) + fs.writeFileSync(file, content, 'utf8') + } + + public getWorkspaceConfig(resource?: string): URI | undefined { + let folder: string + if (resource) { + if (typeof this.resolver.getWorkspaceFolder === 'function') { + let workspaceFolder = this.resolver.getWorkspaceFolder(resource) + if (workspaceFolder) folder = URI.parse(workspaceFolder.uri).fsPath + } + } else { + folder = this.resolver.root + } + if (folder && !sameFile(folder, os.homedir())) { + return URI.file(path.join(folder, '.vim', CONFIG_FILE_NAME)) + } + return undefined + } + + public $updateConfigurationOption(_target: ConfigurationTarget, key: string, value: any, overrides?: IConfigurationOverrides): void { + this.modifyConfiguration(overrides?.resource, key, value) + } + + public $removeConfigurationOption(_target: ConfigurationTarget, key: string, overrides?: IConfigurationOverrides): void { + this.modifyConfiguration(overrides?.resource, key) + } +} diff --git a/sources_non_forked/coc.nvim/src/configuration/util.ts b/sources_non_forked/coc.nvim/src/configuration/util.ts new file mode 100644 index 00000000..62f768b1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/configuration/util.ts @@ -0,0 +1,292 @@ +'use strict' +import { Location, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { parse, ParseError } from 'jsonc-parser' +import { IConfigurationModel, ErrorItem } from '../types' +import { emptyObject, objectLiteral } from '../util/is' +import { equals } from '../util/object' +import fs from 'fs' +import { URI } from 'vscode-uri' +import path, { dirname, resolve } from 'path' +const logger = require('../util/logger')('configuration-util') +declare const ESBUILD + +const pluginRoot = typeof ESBUILD === 'undefined' ? resolve(__dirname, '../..') : dirname(__dirname) + +export type ShowError = (errors: ErrorItem[]) => void + +export function mergeConfigProperties(obj: any): any { + let res = {} + for (let key of Object.keys(obj)) { + if (key.indexOf('.') == -1) { + res[key] = obj[key] + } else { + let parts = key.split('.') + let pre = res + let len = parts.length + for (let i = 0; i < len; i++) { + let k = parts[i] + if (i == len - 1) { + pre[k] = obj[key] + } else { + pre[k] = pre[k] || {} + pre = pre[k] + } + } + } + } + return res +} + +export function parseContentFromFile(filepath: string | null, onError?: ShowError): IConfigurationModel { + if (!filepath || !fs.existsSync(filepath)) return { contents: {} } + let content: string + let uri = URI.file(filepath).toString() + try { + content = fs.readFileSync(filepath, 'utf8') + } catch (_e) { + content = '' + } + let [errors, contents] = parseConfiguration(content) + if (errors && errors.length) { + onError(convertErrors(uri, content, errors)) + } + return { contents } +} + +export function parseConfiguration(content: string): [ParseError[], any] { + if (content.length == 0) return [[], {}] + let errors: ParseError[] = [] + let data = parse(content, errors, { allowTrailingComma: true }) + function addProperty(current: object, key: string, remains: string[], value: any): void { + if (remains.length == 0) { + current[key] = convert(value) + } else { + if (!current[key]) current[key] = {} + let o = current[key] + let first = remains.shift() + addProperty(o, first, remains, value) + } + } + + function convert(obj: any, split = false): any { + if (!objectLiteral(obj)) return obj + if (emptyObject(obj)) return {} + let dest = {} + for (let key of Object.keys(obj)) { + // not split uri + if (split && key.includes('.') && !/^.+:\//.test(key)) { + let parts = key.split('.') + let first = parts.shift() + addProperty(dest, first, parts, obj[key]) + } else { + dest[key] = convert(obj[key]) + } + } + return dest + } + return [errors, convert(data, true)] +} + +export function convertErrors(uri: string, content: string, errors: ParseError[]): ErrorItem[] { + let items: ErrorItem[] = [] + let document = TextDocument.create(uri, 'json', 0, content) + for (let err of errors) { + let msg = 'parse error' + switch (err.error) { + case 2: + msg = 'invalid number' + break + case 8: + msg = 'close brace expected' + break + case 5: + msg = 'colon expected' + break + case 6: + msg = 'comma expected' + break + case 9: + msg = 'end of file expected' + break + case 16: + msg = 'invaliad character' + break + case 10: + msg = 'invalid comment token' + break + case 15: + msg = 'invalid escape character' + break + case 1: + msg = 'invalid symbol' + break + case 14: + msg = 'invalid unicode' + break + case 3: + msg = 'property name expected' + break + case 13: + msg = 'unexpected end of number' + break + case 12: + msg = 'unexpected end of string' + break + case 11: + msg = 'unexpected end of comment' + break + case 4: + msg = 'value expected' + break + default: + msg = 'Unknown error' + break + } + let range: Range = { + start: document.positionAt(err.offset), + end: document.positionAt(err.offset + err.length), + } + let loc = Location.create(uri, range) + items.push({ location: loc, message: msg }) + } + return items +} + +export function addToValueTree( + settingsTreeRoot: any, + key: string, + value: any, + conflictReporter: (message: string) => void +): void { + const segments = key.split('.') + const last = segments.pop() + + let curr = settingsTreeRoot + for (let i = 0; i < segments.length; i++) { + let s = segments[i] + let obj = curr[s] + switch (typeof obj) { + case 'function': { + obj = curr[s] = {} + break + } + case 'undefined': { + obj = curr[s] = {} + break + } + case 'object': + break + default: + conflictReporter( + `Ignoring ${key} as ${segments + .slice(0, i + 1) + .join('.')} is ${JSON.stringify(obj)}` + ) + return + } + curr = obj + } + + if (typeof curr === 'object') { + curr[last] = value // workaround https://github.com/Microsoft/vscode/issues/13606 + } else { + conflictReporter( + `Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}` + ) + } +} + +export function removeFromValueTree(valueTree: any, key: string): void { + const segments = key.split('.') + doRemoveFromValueTree(valueTree, segments) +} + +function doRemoveFromValueTree(valueTree: any, segments: string[]): void { + const first = segments.shift() + if (segments.length === 0) { + // Reached last segment + delete valueTree[first] + return + } + + if (Object.keys(valueTree).includes(first)) { + const value = valueTree[first] + if (typeof value === 'object' && !Array.isArray(value)) { + doRemoveFromValueTree(value, segments) + if (Object.keys(value).length === 0) { + delete valueTree[first] + } + } + } +} + +export function getConfigurationValue( + config: any, + settingPath: string, + defaultValue?: T +): T { + function accessSetting(config: any, path: string[]): any { + let current = config + for (let i = 0; i < path.length; i++) { + if (typeof current !== 'object' || current === null) { + return undefined + } + current = current[path[i]] + } + return current as T + } + + const path = settingPath.split('.') + const result = accessSetting(config, path) + + return typeof result === 'undefined' ? defaultValue : result +} + +export function loadDefaultConfigurations(): IConfigurationModel { + let file = path.join(pluginRoot, 'data/schema.json') + let content = fs.readFileSync(file, 'utf8') + let { properties } = JSON.parse(content) + let config = {} + Object.keys(properties).forEach(key => { + let value = properties[key].default + if (value !== undefined) { + addToValueTree(config, key, value, message => { + logger.error(message) + }) + } + }) + return { contents: config } +} + +export function getKeys(obj: { [key: string]: any }, curr?: string): string[] { + let keys: string[] = [] + for (let key of Object.keys(obj)) { + let val = obj[key] + let newKey = curr ? `${curr}.${key}` : key + keys.push(newKey) + if (objectLiteral(val)) { + keys.push(...getKeys(val, newKey)) + } + } + return keys +} + +export function getChangedKeys(from: { [key: string]: any }, to: { [key: string]: any }): string[] { + let keys: string[] = [] + let fromKeys = getKeys(from) + let toKeys = getKeys(to) + const added = toKeys.filter(key => !fromKeys.includes(key)) + const removed = fromKeys.filter(key => !toKeys.includes(key)) + keys.push(...added) + keys.push(...removed) + for (const key of fromKeys) { + if (!toKeys.includes(key)) continue + const value1 = getConfigurationValue(from, key) + const value2 = getConfigurationValue(to, key) + if (!equals(value1, value2)) { + keys.push(key) + } + } + return keys +} diff --git a/sources_non_forked/coc.nvim/src/core/autocmds.ts b/sources_non_forked/coc.nvim/src/core/autocmds.ts new file mode 100644 index 00000000..1c93a546 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/autocmds.ts @@ -0,0 +1,105 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { Disposable } from 'vscode-languageserver-protocol' +import { Autocmd } from '../types' +import { disposeAll, platform } from '../util' +import ContentProvider from './contentProvider' +import Watchers from './watchers' +const logger = require('../util/logger')('core-autocmds') + +interface PartialEnv { + isCygwin: boolean +} + +export default class Autocmds implements Disposable { + private _dynAutocmd = false + private autocmdMaxId = 0 + public readonly autocmds: Map = new Map() + private nvim: Neovim + private env: PartialEnv + private disposables: Disposable[] = [] + constructor( + private contentProvider: ContentProvider, + private watchers: Watchers + ) { + this.contentProvider.onDidProviderChange(() => { + this.setupDynamicAutocmd() + }, null, this.disposables) + this.watchers.onDidOptionChange(() => { + this.setupDynamicAutocmd() + }, null, this.disposables) + } + + public attach(nvim: Neovim, env: PartialEnv): void { + this.nvim = nvim + this.env = env + } + + public async doAutocmd(id: number, args: any[]): Promise { + let autocmd = this.autocmds.get(id) + if (autocmd) { + let ev = Array.isArray(autocmd.event) ? autocmd.event.join(',') : autocmd.event + logger.debug(`invoke ${autocmd.request ? 'request' : 'notify'} autocmd:`, ev) + await Promise.resolve(autocmd.callback.apply(autocmd.thisArg, args)) + } + } + + public registerAutocmd(autocmd: Autocmd): Disposable { + this.autocmdMaxId += 1 + let id = this.autocmdMaxId + this.autocmds.set(id, autocmd) + this.setupDynamicAutocmd() + return Disposable.create(() => { + this.autocmds.delete(id) + this.setupDynamicAutocmd() + }) + } + + public setupDynamicAutocmd(force = false): void { + if (!force && !this._dynAutocmd) return + this._dynAutocmd = true + let schemes = this.contentProvider.schemes + let cmds: string[] = [] + for (let scheme of schemes) { + cmds.push(`autocmd BufReadCmd,FileReadCmd,SourceCmd ${scheme}:/* call coc#rpc#request('CocAutocmd', ['BufReadCmd','${scheme}', expand('')])`) + } + for (let [id, autocmd] of this.autocmds.entries()) { + let args = autocmd.arglist && autocmd.arglist.length ? ', ' + autocmd.arglist.join(', ') : '' + let event = Array.isArray(autocmd.event) ? autocmd.event.join(',') : autocmd.event + let pattern = autocmd.pattern != null ? autocmd.pattern : '*' + if (/\buser\b/i.test(event)) { + pattern = '' + } + cmds.push(`autocmd ${event} ${pattern} call coc#rpc#${autocmd.request ? 'request' : 'notify'}('doAutocmd', [${id}${args}])`) + } + for (let key of this.watchers.options) { + cmds.push(`autocmd OptionSet ${key} call coc#rpc#notify('OptionSet',[expand(''), v:option_old, v:option_new])`) + } + let content = ` +augroup coc_dynamic_autocmd + autocmd! + ${cmds.join('\n ')} +augroup end` + if (this.nvim.hasFunction('nvim_exec')) { + void this.nvim.exec(content, false) + } else { + let dir = path.join(process.env.TMPDIR || os.tmpdir(), `coc.nvim-${process.pid}.vim`) + fs.mkdirSync(dir, { recursive: true }) + let filepath = path.join(dir, `coc-${process.pid}.vim`) + fs.writeFileSync(filepath, content, 'utf8') + let cmd = `source ${filepath}` + if (this.env.isCygwin && platform.isWindows) { + cmd = `execute "source" . substitute(system('cygpath ${filepath.replace(/\\/g, '/')}'), '\\n', '', 'g')` + } + void this.nvim.command(cmd) + } + } + + public dispose(): void { + this.nvim.command(`augroup coc_dynamic_autocmd| autocmd!|augroup end`, true) + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/core/channels.ts b/sources_non_forked/coc.nvim/src/core/channels.ts new file mode 100644 index 00000000..ed731825 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/channels.ts @@ -0,0 +1,80 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events from '../events' +import BufferChannel from '../model/outputChannel' +import { TextDocumentContentProvider } from '../provider' +import { OutputChannel } from '../types' +const logger = require('../util/logger')('core-channels') + +export class Channels { + private outputChannels: Map = new Map() + private bufnrs: Map = new Map() + private disposable: Disposable + constructor() { + this.disposable = events.on('BufUnload', bufnr => { + let name = this.bufnrs.get(bufnr) + if (name) { + let channel = this.outputChannels.get(name) + if (channel) channel.created = false + } + }) + } + + /** + * Get text document provider + */ + public getProvider(nvim: Neovim): TextDocumentContentProvider { + let provider: TextDocumentContentProvider = { + onDidChange: null, + provideTextDocumentContent: async (uri: URI) => { + let channel = this.get(uri.path.slice(1)) + if (!channel) return '' + nvim.pauseNotification() + nvim.call('bufnr', ['%'], true) + nvim.command('setlocal nospell nofoldenable nowrap noswapfile', true) + nvim.command('setlocal buftype=nofile bufhidden=hide', true) + nvim.command('setfiletype log', true) + let res = await nvim.resumeNotification() + this.bufnrs.set(res[0][0] as number, channel.name) + channel.created = true + return channel.content + } + } + return provider + } + + public get names(): string[] { + return Array.from(this.outputChannels.keys()) + } + + public get(channelName: string): BufferChannel | null { + return this.outputChannels.get(channelName) + } + + public create(name: string, nvim: Neovim): OutputChannel | null { + if (this.outputChannels.has(name)) return this.outputChannels.get(name) + let channel = new BufferChannel(name, nvim, () => { + this.outputChannels.delete(name) + }) + this.outputChannels.set(name, channel) + return channel + } + + public show(name: string, cmd: string, preserveFocus?: boolean): void { + let channel = this.outputChannels.get(name) + if (!channel) return + channel.show(preserveFocus, cmd) + } + + public dispose(): void { + this.disposable.dispose() + for (let channel of this.outputChannels.values()) { + channel.dispose() + } + this.outputChannels.clear() + } +} + +export default new Channels() diff --git a/sources_non_forked/coc.nvim/src/core/contentProvider.ts b/sources_non_forked/coc.nvim/src/core/contentProvider.ts new file mode 100644 index 00000000..0dd9204a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/contentProvider.ts @@ -0,0 +1,74 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events from '../events' +import { TextDocumentContentProvider } from '../provider' +import { disposeAll } from '../util' +import Documents from './documents' + +export default class ContentProvider implements Disposable { + private nvim: Neovim + private disposables: Disposable[] = [] + private providers: Map = new Map() + private readonly _onDidProviderChange = new Emitter() + public readonly onDidProviderChange: Event = this._onDidProviderChange.event + constructor( + private documents: Documents + ) { + } + + public attach(nvim: Neovim): void { + this.nvim = nvim + events.on('BufReadCmd', this.onBufReadCmd, this, this.disposables) + } + + public get schemes(): string[] { + return Array.from(this.providers.keys()) + } + + private async onBufReadCmd(scheme: string, uri: string): Promise { + let provider = this.providers.get(scheme) + if (!provider) return + let tokenSource = new CancellationTokenSource() + let content = await Promise.resolve(provider.provideTextDocumentContent(URI.parse(uri), tokenSource.token)) + let buf = await this.nvim.buffer + await buf.setLines(content.split(/\r?\n/), { + start: 0, + end: -1, + strictIndexing: false + }) + process.nextTick(() => { + void events.fire('BufCreate', [buf.id]) + }) + } + + public registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable { + this.providers.set(scheme, provider) + this._onDidProviderChange.fire() + let disposables: Disposable[] = [] + if (provider.onDidChange) { + provider.onDidChange(async uri => { + let { buffer } = this.documents.getDocument(uri.toString()) + let tokenSource = new CancellationTokenSource() + let content = await Promise.resolve(provider.provideTextDocumentContent(uri, tokenSource.token)) + await buffer.setLines(content.split(/\r?\n/), { + start: 0, + end: -1, + strictIndexing: false + }) + }, null, disposables) + } + return Disposable.create(() => { + this.providers.delete(scheme) + disposeAll(disposables) + this._onDidProviderChange.fire() + }) + } + + public dispose(): void { + disposeAll(this.disposables) + this._onDidProviderChange.dispose() + this.providers.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/core/documents.ts b/sources_non_forked/coc.nvim/src/core/documents.ts new file mode 100644 index 00000000..78d9eec1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/documents.ts @@ -0,0 +1,592 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import bytes from 'bytes' +import fs from 'fs' +import os from 'os' +import path from 'path' +import { Disposable, Emitter, Event, FormattingOptions, Location, LocationLink, TextDocumentSaveReason, TextEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import Configurations from '../configuration' +import events, { InsertChange } from '../events' +import Document from '../model/document' +import { LinesTextDocument } from '../model/textdocument' +import { BufferOption, DidChangeTextDocumentParams, Env, QuickfixItem, TextDocumentWillSaveEvent } from '../types' +import { disposeAll, platform } from '../util' +import { readFileLine } from '../util/fs' +import { byteIndex } from '../util/string' +import WorkspaceFolder from './workspaceFolder' +const logger = require('../util/logger')('core-documents') + +interface StateInfo { + bufnr: number + winid: number + bufnrs: number[] + winids: number[] +} + +export default class Documents implements Disposable { + private _cwd: string + private _env: Env + private _bufnr: number + private _root: string + private _initialized = false + private _attached = false + private _currentResolve = false + private nvim: Neovim + private maxFileSize: number + private disposables: Disposable[] = [] + private creating: Map> = new Map() + private buffers: Map = new Map() + private winids: Set = new Set() + private resolves: ((doc: Document) => void)[] = [] + private readonly _onDidOpenTextDocument = new Emitter() + private readonly _onDidCloseDocument = new Emitter() + private readonly _onDidChangeDocument = new Emitter() + private readonly _onDidSaveDocument = new Emitter() + private readonly _onWillSaveDocument = new Emitter() + + public readonly onDidOpenTextDocument: Event = this._onDidOpenTextDocument.event + public readonly onDidCloseDocument: Event = this._onDidCloseDocument.event + public readonly onDidChangeDocument: Event = this._onDidChangeDocument.event + public readonly onDidSaveTextDocument: Event = this._onDidSaveDocument.event + public readonly onWillSaveTextDocument: Event = this._onWillSaveDocument.event + + constructor( + private readonly configurations: Configurations, + private readonly workspaceFolder: WorkspaceFolder, + ) { + this._cwd = process.cwd() + } + + public async attach(nvim: Neovim, env: Env): Promise { + if (this._attached) return + this.nvim = nvim + this._env = env + this._attached = true + let preferences = this.configurations.getConfiguration('coc.preferences') + let maxFileSize = preferences.get('maxFileSize', '10MB') + this.maxFileSize = bytes.parse(maxFileSize) + nvim.setVar('coc_max_filesize', this.maxFileSize, true) + let { bufnrs, winid, bufnr, winids } = await this.nvim.call('coc#util#all_state') as StateInfo + this.winids = new Set(winids) + this._bufnr = bufnr + await Promise.all(bufnrs.map(bufnr => this.createDocument(bufnr))) + events.on('BufDetach', this.onBufDetach, this, this.disposables) + events.on('VimLeavePre', () => { + this.resolveCurrent(undefined) + }, null, this.disposables) + events.on('WinEnter', (winid: number) => { + this.winids.add(winid) + }, null, this.disposables) + events.on('BufWinEnter', (_, winid: number) => { + this.winids.add(winid) + }, null, this.disposables) + events.on('DirChanged', cwd => { + this._cwd = cwd + }, null, this.disposables) + // check unloaded buffers + events.on('CursorHold', async () => { + let { bufnrs, winids } = await this.nvim.call('coc#util#all_state') as StateInfo + for (let bufnr of this.buffers.keys()) { + if (!bufnrs.includes(bufnr)) void events.fire('BufUnload', [bufnr]) + } + for (let winid of this.winids) { + if (!winids.includes(winid)) void events.fire('WinClosed', [winid]) + } + this.winids = new Set(winids) + }, null, this.disposables) + const checkCurrentBuffer = (bufnr: number) => { + this._bufnr = bufnr + void this.createDocument(bufnr) + } + events.on('CursorMoved', checkCurrentBuffer, null, this.disposables) + events.on('CursorMovedI', checkCurrentBuffer, null, this.disposables) + events.on('BufUnload', this.onBufUnload, this, this.disposables) + events.on('BufEnter', this.onBufEnter, this, this.disposables) + events.on('BufCreate', this.onBufCreate, this, this.disposables) + events.on('TermOpen', this.onBufCreate, this, this.disposables) + events.on('BufWritePost', this.onBufWritePost, this, this.disposables) + events.on('BufWritePre', this.onBufWritePre, this, this.disposables) + events.on('FileType', this.onFileTypeChange, this, this.disposables) + void events.fire('BufEnter', [bufnr]) + void events.fire('BufWinEnter', [bufnr, winid]) + events.on('BufEnter', (bufnr: number) => { + void this.createDocument(bufnr) + }, null, this.disposables) + events.on('CursorHold', (bufnr: number, _, variables) => { + let buf = this.getDocument(bufnr) + if (buf) buf.onCursorHold(variables) + }, null, this.disposables) + if (this._env.isVim) { + ['TextChangedP', 'TextChangedI', 'TextChanged'].forEach(event => { + events.on(event as any, (bufnr: number, info?: InsertChange) => { + let doc = this.buffers.get(bufnr) + if (doc?.attached) doc.onTextChange(event, info) + }, null, this.disposables) + }) + } else { + events.on('CompleteDone', async () => { + let ev = await events.race(['TextChangedI', 'TextChanged', 'MenuPopupChanged'], 100) + if (ev && (ev.name === 'TextChangedI' || ev.name === 'TextChanged')) { + let doc = this.buffers.get(events.bufnr) + if (doc?.attached) doc._forceSync() + } + }, null, this.disposables) + } + this._initialized = true + } + + public get bufnr(): number { + return this._bufnr + } + + public get root(): string { + return this._root + } + + public get cwd(): string { + return this._cwd + } + + public get documents(): Document[] { + return Array.from(this.buffers.values()).filter(o => o.attached && !o.isCommandLine) + } + + public get bufnrs(): number[] { + return Array.from(this.buffers.keys()) + } + + public detach(): void { + if (!this._attached) return + this._attached = false + for (let bufnr of this.buffers.keys()) { + this.onBufUnload(bufnr) + } + disposeAll(this.disposables) + } + + public get textDocuments(): LinesTextDocument[] { + let docs: LinesTextDocument[] = [] + for (let b of this.buffers.values()) { + if (b.attached) docs.push(b.textDocument) + } + return docs + } + + public getDocument(uri: number | string): Document | null { + if (typeof uri === 'number') { + return this.buffers.get(uri) + } + const caseInsensitive = platform.isWindows || platform.isMacintosh + uri = URI.parse(uri).toString() + for (let doc of this.buffers.values()) { + if (doc.uri === uri) return doc + if (caseInsensitive && doc.uri.toLowerCase() === uri.toLowerCase()) return doc + } + return null + } + + /** + * Expand filepath with `~` and/or environment placeholders + */ + public expand(input: string): string { + if (input.startsWith('~')) { + input = os.homedir() + input.slice(1) + } + if (input.includes('$')) { + let doc = this.getDocument(this.bufnr) + let fsPath = doc ? URI.parse(doc.uri).fsPath : '' + input = input.replace(/\$\{(.*?)\}/g, (match: string, name: string) => { + if (name.startsWith('env:')) { + let key = name.split(':')[1] + let val = key ? process.env[key] : '' + return val + } + switch (name) { + case 'workspace': + case 'workspaceRoot': + case 'workspaceFolder': + return this._root + case 'workspaceFolderBasename': + return path.dirname(this._root) + case 'cwd': + return this._cwd + case 'file': + return fsPath + case 'fileDirname': + return fsPath ? path.dirname(fsPath) : '' + case 'fileExtname': + return fsPath ? path.extname(fsPath) : '' + case 'fileBasename': + return fsPath ? path.basename(fsPath) : '' + case 'fileBasenameNoExtension': { + let basename = fsPath ? path.basename(fsPath) : '' + return basename ? basename.slice(0, basename.length - path.extname(basename).length) : '' + } + default: + return match + } + }) + input = input.replace(/\$[\w]+/g, match => { + if (match == '$HOME') return os.homedir() + return process.env[match.slice(1)] || match + }) + } + return input + } + + /** + * Current document. + */ + public get document(): Promise { + if (this._currentResolve) { + return new Promise(resolve => { + this.resolves.push(resolve) + }) + } + this._currentResolve = true + return new Promise((resolve, reject) => { + this.nvim.eval('coc#util#get_bufoptions(bufnr("%"))').then((opts: BufferOption) => { + let doc: Document | undefined + if (opts != null) { + this.creating.delete(opts.bufnr) + doc = this._createDocument(opts) + } + this.resolveCurrent(doc) + resolve(doc) + this._currentResolve = false + }, reject) + }) + } + + private resolveCurrent(document: Document | undefined): void { + if (this.resolves.length > 0) { + while (this.resolves.length) { + const fn = this.resolves.pop() + if (fn) fn(document) + } + } + } + + public get uri(): string { + let { bufnr } = this + if (bufnr) { + let doc = this.getDocument(bufnr) + if (doc) return doc.uri + } + return null + } + + /** + * Current filetypes. + */ + public get filetypes(): Set { + let res = new Set() + for (let doc of this.documents) { + res.add(doc.filetype) + } + return res + } + + /** + * Current languageIds. + */ + public get languageIds(): Set { + let res = new Set() + for (let doc of this.documents) { + res.add(doc.languageId) + } + return res + } + + /** + * Get format options + */ + public async getFormatOptions(uri?: string): Promise { + let doc: Document + if (uri) doc = this.getDocument(uri) + let bufnr = doc ? doc.bufnr : 0 + let res = await this.nvim.call('coc#util#get_format_opts', [bufnr]) as any + let obj: FormattingOptions = { tabSize: res.tabsize, insertSpaces: res.expandtab == 1 } + obj.insertFinalNewline = res.insertFinalNewline == 1 + if (res.trimTrailingWhitespace) obj.trimTrailingWhitespace = true + if (res.trimFinalNewlines) obj.trimFinalNewlines = true + return obj + } + + /** + * Create document by bufnr. + */ + public async createDocument(bufnr: number): Promise { + let doc = this.buffers.get(bufnr) + if (doc) return doc + if (this.creating.has(bufnr)) return await this.creating.get(bufnr) + let promise = new Promise(resolve => { + this.nvim.call('coc#util#get_bufoptions', [bufnr]).then(opts => { + if (!this.creating.has(bufnr)) { + resolve(undefined) + return + } + this.creating.delete(bufnr) + if (!opts) { + resolve(undefined) + return + } + doc = this._createDocument(opts) + resolve(doc) + }, () => { + this.creating.delete(bufnr) + resolve(undefined) + }) + }) + this.creating.set(bufnr, promise) + return await promise + } + + public async onBufCreate(bufnr: number): Promise { + this.onBufUnload(bufnr) + await this.createDocument(bufnr) + } + + private _createDocument(opts: BufferOption): Document { + let { bufnr } = opts + if (this.buffers.has(bufnr)) return this.buffers.get(bufnr) + let buffer = this.nvim.createBuffer(bufnr) + let doc = new Document(buffer, this._env, this.nvim, opts) + this.buffers.set(bufnr, doc) + if (doc.attached) { + if (doc.schema == 'file') { + let configfile = this.configurations.resolveFolderConfigution(doc.uri) + let root = this.workspaceFolder.resolveRoot(doc, this._cwd, this._initialized, this.expand.bind(this)) + if (bufnr == this._bufnr) { + if (configfile) this.configurations.setFolderConfiguration(doc.uri) + if (root) this._root = root + } + } + this._onDidOpenTextDocument.fire(doc.textDocument) + doc.onDocumentChange(e => this._onDidChangeDocument.fire(e)) + } + logger.debug('buffer created', bufnr, doc.attached, doc.uri) + return doc + } + + private onBufEnter(bufnr: number): void { + this._bufnr = bufnr + let doc = this.buffers.get(bufnr) + if (doc) { + this.configurations.setFolderConfiguration(doc.uri) + let workspaceFolder = this.workspaceFolder.getWorkspaceFolder(URI.parse(doc.uri)) + if (workspaceFolder) this._root = URI.parse(workspaceFolder.uri).fsPath + } + } + + private onBufUnload(bufnr: number): void { + this.creating.delete(bufnr) + void this.onBufDetach(bufnr, false) + } + + private async onBufDetach(bufnr: number, checkReload = true): Promise { + this.detachBuffer(bufnr) + if (checkReload) { + let loaded = await this.nvim.call('bufloaded', [bufnr]) + if (loaded) await this.createDocument(bufnr) + } + } + + private detachBuffer(bufnr: number): void { + let doc = this.buffers.get(bufnr) + if (!doc) return + logger.debug('document detach', bufnr, doc.uri) + this._onDidCloseDocument.fire(doc.textDocument) + this.buffers.delete(bufnr) + doc.detach() + } + + private async onBufWritePost(bufnr: number, changedtick: number): Promise { + let doc = this.buffers.get(bufnr) + if (doc) { + if (doc.changedtick != changedtick) await doc.patchChange() + this._onDidSaveDocument.fire(doc.textDocument) + } + } + + private async onBufWritePre(bufnr: number, bufname: string, changedtick: number): Promise { + let doc = this.buffers.get(bufnr) + if (!doc || !doc.attached) return + if (doc.bufname != bufname) { + this.detachBuffer(bufnr) + doc = await this.createDocument(bufnr) + if (!doc.attached) return + } + if (doc.changedtick != changedtick) { + await doc.synchronize() + } else { + await doc.patchChange() + } + let firing = true + let thenables: Thenable[] = [] + let event: TextDocumentWillSaveEvent = { + document: doc.textDocument, + reason: TextDocumentSaveReason.Manual, + waitUntil: (thenable: Thenable) => { + if (!firing) { + logger.error(`Can't call waitUntil in async manner:`, Error().stack) + this.nvim.echoError(`waitUntil can't be used in async manner, check log for details`) + } else { + thenables.push(thenable) + } + } + } + this._onWillSaveDocument.fire(event) + firing = false + let total = thenables.length + if (total) { + let promise = new Promise(resolve => { + const preferences = this.configurations.getConfiguration('coc.preferences') + const willSaveHandlerTimeout = preferences.get('willSaveHandlerTimeout', 500) + let timer = setTimeout(() => { + this.nvim.outWriteLine(`Will save handler timeout after ${willSaveHandlerTimeout}ms`) + resolve(undefined) + }, willSaveHandlerTimeout) + let i = 0 + let called = false + for (let p of thenables) { + let cb = (res: any) => { + if (called) return + called = true + clearTimeout(timer) + resolve(res) + } + p.then(res => { + if (Array.isArray(res) && res.length && TextEdit.is(res[0])) { + return cb(res) + } + i = i + 1 + if (i == total) cb(undefined) + }, e => { + logger.error(`Error on will save handler:`, e) + i = i + 1 + if (i == total) cb(undefined) + }) + } + }) + let edits = await promise + if (edits) await doc.applyEdits(edits, false, this.bufnr === doc.bufnr) + } + } + + private onFileTypeChange(filetype: string, bufnr: number): void { + let doc = this.getDocument(bufnr) + if (!doc) return + let converted = doc.convertFiletype(filetype) + if (converted == doc.filetype) return + this._onDidCloseDocument.fire(doc.textDocument) + doc.setFiletype(filetype) + this._onDidOpenTextDocument.fire(doc.textDocument) + } + + public async getQuickfixList(locations: Location[]): Promise> { + let filesLines: { [fsPath: string]: string[] } = {} + let filepathList = locations.reduce((pre: string[], curr) => { + let u = URI.parse(curr.uri) + if (u.scheme == 'file' && !pre.includes(u.fsPath) && !this.getDocument(curr.uri)) { + pre.push(u.fsPath) + } + return pre + }, []) + + await Promise.all(filepathList.map(fsPath => { + return new Promise(resolve => { + fs.readFile(fsPath, 'utf8', (err, content) => { + if (err) return resolve(undefined) + filesLines[fsPath] = content.split(/\r?\n/) + resolve(undefined) + }) + }) + })) + return await Promise.all(locations.map(loc => { + let { uri, range } = loc + let { fsPath } = URI.parse(uri) + let text: string | undefined + let lines = filesLines[fsPath] + if (lines) text = lines[range.start.line] + return this.getQuickfixItem(loc, text) + })) + } + + /** + * Convert location to quickfix item. + */ + public async getQuickfixItem(loc: Location | LocationLink, text?: string, type = '', module?: string): Promise { + if (LocationLink.is(loc)) { + loc = Location.create(loc.targetUri, loc.targetRange) + } + let doc = this.getDocument(loc.uri) + let { uri, range } = loc + let { start, end } = range + let u = URI.parse(uri) + if (!text && u.scheme == 'file') { + text = await this.getLine(uri, start.line) + } + let endLine = start.line == end.line ? text : await this.getLine(uri, end.line) + let item: QuickfixItem = { + uri, + filename: u.scheme == 'file' ? u.fsPath : uri, + lnum: start.line + 1, + end_lnum: end.line + 1, + col: text ? byteIndex(text, start.character) + 1 : start.character + 1, + end_col: endLine ? byteIndex(endLine, end.character) + 1 : end.character + 1, + text: text || '', + range + } + if (module) item.module = module + if (type) item.type = type + if (doc) item.bufnr = doc.bufnr + return item + } + + /** + * Get content of line by uri and line. + */ + public async getLine(uri: string, line: number): Promise { + let document = this.getDocument(uri) + if (document && document.attached) return document.getline(line) || '' + if (!uri.startsWith('file:')) return '' + let fsPath = URI.parse(uri).fsPath + if (!fs.existsSync(fsPath)) return '' + return await readFileLine(fsPath, line) + } + + /** + * Get content from buffer or file by uri. + */ + public async readFile(uri: string): Promise { + let document = this.getDocument(uri) + if (document) { + await document.patchChange() + return document.content + } + let u = URI.parse(uri) + if (u.scheme != 'file') return '' + let lines = await this.nvim.call('readfile', [u.fsPath]) as string[] + return lines.join('\n') + '\n' + } + + public reset(): void { + this.creating.clear() + for (let bufnr of this.buffers.keys()) { + this.onBufUnload(bufnr) + } + this.buffers.clear() + this._root = process.cwd() + } + + public dispose(): void { + for (let bufnr of this.buffers.keys()) { + this.onBufUnload(bufnr) + } + this._attached = false + this.buffers.clear() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/core/editors.ts b/sources_non_forked/coc.nvim/src/core/editors.ts new file mode 100644 index 00000000..9447ff42 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/editors.ts @@ -0,0 +1,142 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event, Range } from 'vscode-languageserver-protocol' +import events from '../events' +import Document from '../model/document' +import Documents from './documents' +import window from '../window' +const logger = require('../util/logger')('core-editors') + +interface EditorOption { + bufnr: number + winid: number + tabpagenr: number + winnr: number + visibleRanges: [number, number][] + tabSize: number + insertSpaces: boolean + winids: number[] +} + +export interface TextEditorOptions { + tabSize: number + insertSpaces: boolean +} + +export interface TextEditor { + readonly tabpagenr: number + readonly winid: number + readonly winnr: number + readonly document: Document + readonly visibleRanges: readonly Range[] + options: TextEditorOptions +} + +export default class Editors { + private disposables: Disposable[] = [] + private winid: number + private previousId: string + private nvim: Neovim + private editors: Map = new Map() + private readonly _onDidChangeActiveTextEditor = new Emitter() + private readonly _onDidChangeVisibleTextEditors = new Emitter>() + public readonly onDidChangeActiveTextEditor: Event = this._onDidChangeActiveTextEditor.event + public readonly onDidChangeVisibleTextEditors: Event> = this._onDidChangeVisibleTextEditors.event + constructor(private documents: Documents) { + } + + public get activeTextEditor(): TextEditor | undefined { + return this.editors.get(this.winid) + } + + public get visibleTextEditors(): TextEditor[] { + return Array.from(this.editors.values()) + } + + private onChange(editor: TextEditor | undefined): void { + let id = `${editor.winid}-${editor.document.bufnr}-${editor.document.uri}` + if (id == this.previousId) return + this.previousId = id + this._onDidChangeActiveTextEditor.fire(editor) + } + + public async attach(nvim: Neovim): Promise { + this.nvim = nvim + let { documents } = this + let doc = documents.getDocument(documents.bufnr) + if (doc && doc.winid > 0) { + this.winid = doc.winid + await this.createTextEditor(this.winid) + } + events.on('WinEnter', (winid: number) => { + this.winid = winid + let editor = this.editors.get(winid) + if (editor) this.onChange(editor) + }, null, this.disposables) + events.on('CursorHold', async () => { + let [winid, buftype, isFloat] = await nvim.eval(`[win_getid(),&buftype,coc#window#is_float(win_getid())]`) as [number, string, number] + let changed = false + if (!isFloat && ['', 'acwrite'].includes(buftype) && !this.editors.has(winid)) { + let created = await this.createTextEditor(winid) + if (created) changed = true + } + if (changed) this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors) + }, null, this.disposables) + events.on('WinClosed', (winid: number) => { + if (this.editors.has(winid)) { + this.editors.delete(winid) + this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors) + } + }, null, this.disposables) + events.on('BufWinEnter', async (_: number, winid: number) => { + this.winid = winid + await this.createTextEditor(winid, true) + }, null, this.disposables) + } + + private async createTextEditor(winid: number, check = false): Promise { + let { documents, nvim } = this + let opts = await nvim.call('coc#util#get_editoroption', [winid]) as EditorOption + if (!opts) return false + let changed = false + if (check) { + for (let winid of this.editors.keys()) { + if (!opts.winids.includes(winid)) { + changed = true + this.editors.delete(winid) + } + } + } + let doc = documents.getDocument(opts.bufnr) + if (doc) { + let editor = this.fromOptions(opts, doc) + this.editors.set(winid, editor) + if (winid == this.winid) this.onChange(editor) + this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors) + logger.debug('editor created winid & bufnr & tabnr: ', winid, opts.bufnr, opts.tabpagenr) + return true + } else if (changed) { + this._onDidChangeVisibleTextEditors.fire(this.visibleTextEditors) + } + logger.error(`document not found for window: ${winid}`) + return false + } + + private fromOptions(opts: EditorOption, document: Document): TextEditor { + let { visibleRanges } = opts + let tid = window.getTabId(opts.tabpagenr) + return { + get tabpagenr() { + return window.getTabNumber(tid) + }, + winid: opts.winid, + winnr: opts.winnr, + document, + visibleRanges: visibleRanges.map(o => Range.create(o[0] - 1, 0, o[1], 0)), + options: { + tabSize: opts.tabSize, + insertSpaces: !!opts.insertSpaces + } + } + } +} diff --git a/sources_non_forked/coc.nvim/src/core/fileSystemWatcher.ts b/sources_non_forked/coc.nvim/src/core/fileSystemWatcher.ts new file mode 100644 index 00000000..0ab89d70 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/fileSystemWatcher.ts @@ -0,0 +1,197 @@ +'use strict' +import minimatch from 'minimatch' +import path from 'path' +import { Disposable, Emitter, WorkspaceFolder, Event } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import { OutputChannel } from '../types' +import { disposeAll } from '../util' +import { splitArray } from '../util/array' +import Watchman, { FileChange } from './watchman' +import WorkspaceFolderControl from './workspaceFolder' +const logger = require('../util/logger')('filesystem-watcher') + +export interface RenameEvent { + oldUri: URI + newUri: URI +} + +export class FileSystemWatcherManager { + private clientsMap: Map = new Map() + private disposables: Disposable[] = [] + private channel: OutputChannel | undefined + private creating: Set = new Set() + public static watchers: Set = new Set() + private readonly _onDidCreateClient = new Emitter() + public readonly onDidCreateClient: Event = this._onDidCreateClient.event + constructor( + private workspaceFolder: WorkspaceFolderControl, + private watchmanPath: string | null + ) { + } + + public attach(channel: OutputChannel): void { + this.channel = channel + let createClient = (folder: WorkspaceFolder) => { + let root = URI.parse(folder.uri).fsPath + if (this.creating.has(root)) return + this.creating.add(root) + this.createClient(root).finally(() => { + this.creating.delete(root) + }) + } + this.workspaceFolder.workspaceFolders.forEach(folder => { + createClient(folder) + }) + this.workspaceFolder.onDidChangeWorkspaceFolders(e => { + e.added.forEach(folder => { + createClient(folder) + }) + e.removed.forEach(folder => { + let root = URI.parse(folder.uri).fsPath + let client = this.clientsMap.get(root) + if (client) { + this.clientsMap.delete(root) + client.dispose() + } + }) + }, null, this.disposables) + } + + public waitClient(root: string): Promise { + if (this.clientsMap.has(root)) return Promise.resolve() + return new Promise(resolve => { + let disposable = this.onDidCreateClient(r => { + if (r == root) { + disposable.dispose() + resolve() + } + }) + }) + } + + public async createClient(root: string): Promise { + if (this.watchmanPath == null || this.clientsMap.has(root)) return + try { + let client = await Watchman.createClient(this.watchmanPath, root, this.channel) + if (!client) return + this.clientsMap.set(root, client) + for (let watcher of FileSystemWatcherManager.watchers) { + watcher.listen(client) + } + this._onDidCreateClient.fire(root) + } catch (e) { + if (this.channel) this.channel.appendLine(`Error on create watchman client:` + e) + } + } + + public createFileSystemWatcher( + globPattern: string, + ignoreCreateEvents: boolean, + ignoreChangeEvents: boolean, + ignoreDeleteEvents: boolean): FileSystemWatcher { + let fileWatcher = new FileSystemWatcher(globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents) + for (let client of this.clientsMap.values()) { + fileWatcher.listen(client) + } + FileSystemWatcherManager.watchers.add(fileWatcher) + return fileWatcher + } + + public dispose(): void { + this._onDidCreateClient.dispose() + for (let client of this.clientsMap.values()) { + if (client) client.dispose() + } + this.clientsMap.clear() + FileSystemWatcherManager.watchers.clear() + disposeAll(this.disposables) + } +} + +/* + * FileSystemWatcher for watch workspace folders. + */ +export class FileSystemWatcher implements Disposable { + private _onDidCreate = new Emitter() + private _onDidChange = new Emitter() + private _onDidDelete = new Emitter() + private _onDidRename = new Emitter() + private disposables: Disposable[] = [] + private _disposed = false + public subscribe: string + public readonly onDidCreate: Event = this._onDidCreate.event + public readonly onDidChange: Event = this._onDidChange.event + public readonly onDidDelete: Event = this._onDidDelete.event + public readonly onDidRename: Event = this._onDidRename.event + + constructor( + private globPattern: string, + public ignoreCreateEvents: boolean, + public ignoreChangeEvents: boolean, + public ignoreDeleteEvents: boolean, + ) { + } + + public listen(client: Watchman): void { + let { globPattern, + ignoreCreateEvents, + ignoreChangeEvents, + ignoreDeleteEvents } = this + const onChange = (change: FileChange) => { + let { root, files } = change + files = files.filter(f => f.type == 'f' && minimatch(f.name, globPattern, { dot: true })) + for (let file of files) { + let uri = URI.file(path.join(root, file.name)) + if (!file.exists) { + if (!ignoreDeleteEvents) this._onDidDelete.fire(uri) + } else { + if (file.new === true) { + if (!ignoreCreateEvents) this._onDidCreate.fire(uri) + } else { + if (!ignoreChangeEvents) this._onDidChange.fire(uri) + } + } + } + // file rename + if (files.length == 2 && !files[0].exists && files[1].exists) { + let oldFile = files[0] + let newFile = files[1] + if (oldFile.size == newFile.size) { + this._onDidRename.fire({ + oldUri: URI.file(path.join(root, oldFile.name)), + newUri: URI.file(path.join(root, newFile.name)) + }) + } + } + // detect folder rename + if (files.length >= 2) { + let [oldFiles, newFiles] = splitArray(files, o => o.exists === false) + if (oldFiles.length == newFiles.length) { + for (let oldFile of oldFiles) { + let newFile = newFiles.find(o => o.size == oldFile.size && o.mtime_ms == oldFile.mtime_ms) + if (newFile) { + this._onDidRename.fire({ + oldUri: URI.file(path.join(root, oldFile.name)), + newUri: URI.file(path.join(root, newFile.name)) + }) + } + } + } + } + } + client.subscribe(globPattern, onChange).then(disposable => { + this.subscribe = disposable.subscribe + if (this._disposed) return disposable.dispose() + this.disposables.push(disposable) + }).logError() + } + + public dispose(): void { + this._disposed = true + FileSystemWatcherManager.watchers.delete(this) + this._onDidRename.dispose() + this._onDidCreate.dispose() + this._onDidChange.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/core/files.ts b/sources_non_forked/coc.nvim/src/core/files.ts new file mode 100644 index 00000000..5b49e261 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/files.ts @@ -0,0 +1,526 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs-extra' +import glob from 'glob' +import minimatch from 'minimatch' +import os from 'os' +import path from 'path' +import { promisify } from 'util' +import { v4 as uuid } from 'uuid' +import { CancellationToken, CancellationTokenSource, CreateFile, CreateFileOptions, DeleteFile, DeleteFileOptions, Emitter, Event, Position, RenameFile, RenameFileOptions, TextDocumentEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import Configurations from '../configuration' +import events from '../events' +import Document from '../model/document' +import EditInspect, { EditState, RecoverFunc } from '../model/editInspect' +import RelativePattern from '../model/relativePattern' +import { DocumentChange, Env, FileCreateEvent, FileDeleteEvent, FileRenameEvent, FileWillCreateEvent, FileWillDeleteEvent, FileWillRenameEvent, LinesChange } from '../types' +import * as errors from '../util/errors' +import { fixDriver, isFile, isParentFolder, statAsync } from '../util/fs' +import { byteLength } from '../util/string' +import { getAnnotationKey, getConfirmAnnotations, toDocumentChanges } from '../util/textedit' +import type { Window } from '../window' +import Documents from './documents' +import type Keymaps from './keymaps' +import * as ui from './ui' +import WorkspaceFolderController from './workspaceFolder' + +export type GlobPattern = string | RelativePattern + +interface WaitUntilEvent { + waitUntil(thenable: Thenable): void +} + +const logger = require('../util/logger')('core-files') + +export default class Files { + private nvim: Neovim + private env: Env + private window: Window + private editState: EditState | undefined + private operationTimeout = 500 + private _onDidCreateFiles = new Emitter() + private _onDidRenameFiles = new Emitter() + private _onDidDeleteFiles = new Emitter() + private _onWillCreateFiles = new Emitter() + private _onWillRenameFiles = new Emitter() + private _onWillDeleteFiles = new Emitter() + + public readonly onDidCreateFiles: Event = this._onDidCreateFiles.event + public readonly onDidRenameFiles: Event = this._onDidRenameFiles.event + public readonly onDidDeleteFiles: Event = this._onDidDeleteFiles.event + public readonly onWillCreateFiles: Event = this._onWillCreateFiles.event + public readonly onWillRenameFiles: Event = this._onWillRenameFiles.event + public readonly onWillDeleteFiles: Event = this._onWillDeleteFiles.event + constructor( + private documents: Documents, + private configurations: Configurations, + private workspaceFolderControl: WorkspaceFolderController, + private keymaps: Keymaps + ) { + } + + public attach(nvim: Neovim, env: Env, window: Window): void { + this.nvim = nvim + this.env = env + this.window = window + } + + public async openTextDocument(uri: URI | string): Promise { + uri = typeof uri === 'string' ? URI.file(uri) : uri + let doc = this.documents.getDocument(uri.toString()) + if (doc) { + await this.jumpTo(uri.toString(), null, 'drop') + return doc + } + const scheme = uri.scheme + if (scheme == 'file') { + if (!fs.existsSync(uri.fsPath)) throw errors.fileNotExists(uri.fsPath) + fs.accessSync(uri.fsPath, fs.constants.R_OK) + } + if (scheme == 'untitled') { + await this.nvim.call('coc#util#open_file', ['tab drop', uri.path]) + return await this.documents.document + } + return await this.loadResource(uri.toString()) + } + + public async jumpTo(uri: string, position?: Position | null, openCommand?: string): Promise { + const preferences = this.configurations.getConfiguration('coc.preferences') + let jumpCommand = openCommand || preferences.get('jumpCommand', 'edit') + let { nvim } = this + let doc = this.documents.getDocument(uri) + let bufnr = doc ? doc.bufnr : -1 + if (bufnr != -1 && jumpCommand == 'edit') { + // use buffer command since edit command would reload the buffer + nvim.pauseNotification() + nvim.command(`silent! normal! m'`, true) + nvim.command(`buffer ${bufnr}`, true) + nvim.command(`if &filetype ==# '' | filetype detect | endif`, true) + if (position) { + let line = doc.getline(position.line) + let col = byteLength(line.slice(0, position.character)) + 1 + nvim.call('cursor', [position.line + 1, col], true) + } + await nvim.resumeNotification(true) + } else { + let { fsPath, scheme } = URI.parse(uri) + let pos = position == null ? null : [position.line, position.character] + if (scheme == 'file') { + let bufname = fixDriver(path.normalize(fsPath)) + await this.nvim.call('coc#util#jump', [jumpCommand, bufname, pos]) + } else { + if (nvim.isVim && os.platform() == 'win32') { + uri = uri.replace(/\/?/, '?') + } + await this.nvim.call('coc#util#jump', [jumpCommand, uri, pos]) + } + } + } + + /** + * Open resource by uri + */ + public async openResource(uri: string): Promise { + let { nvim } = this + let u = URI.parse(uri) + if (/^https?/.test(u.scheme)) { + await nvim.call('coc#ui#open_url', uri) + return + } + let wildignore = await nvim.getOption('wildignore') + await nvim.setOption('wildignore', '') + await this.jumpTo(uri) + await nvim.setOption('wildignore', wildignore) + } + + /** + * Load uri as document. + */ + public async loadResource(uri: string): Promise { + let doc = this.documents.getDocument(uri) + if (doc) return doc + const preferences = this.configurations.getConfiguration('workspace') + let cmd = preferences.get('openResourceCommand', 'tab drop') + let u = URI.parse(uri) + let bufname = u.scheme === 'file' ? u.fsPath : uri + let bufnr: number + if (cmd) { + let winid = await this.nvim.call('win_getid') + bufnr = await this.nvim.call('coc#util#open_file', [cmd, bufname]) + await this.nvim.call('win_gotoid', [winid]) + } else { + let arr = await this.nvim.call('coc#ui#open_files', [[bufname]]) + bufnr = arr[0] + } + return await this.documents.createDocument(bufnr) + } + + /** + * Load the files that not loaded + */ + public async loadResources(uris: string[]): Promise<(Document | undefined)[]> { + let { documents } = this + let files = uris.map(uri => { + let u = URI.parse(uri) + return u.scheme == 'file' ? u.fsPath : uri + }) + let bufnrs = await this.nvim.call('coc#ui#open_files', [files]) as number[] + return await Promise.all(bufnrs.map(bufnr => { + return documents.createDocument(bufnr) + })) + } + + /** + * Create a file in vim and disk + */ + public async createFile(filepath: string, opts: CreateFileOptions = {}, recovers?: RecoverFunc[]): Promise { + let { nvim } = this + let exists = fs.existsSync(filepath) + if (exists && !opts.overwrite && !opts.ignoreIfExists) { + throw errors.fileExists(filepath) + } + if (!exists || opts.overwrite) { + let tokenSource = new CancellationTokenSource() + await this.fireWaitUntilEvent(this._onWillCreateFiles, { + files: [URI.file(filepath)], + token: tokenSource.token + }, recovers) + tokenSource.cancel() + let dir = path.dirname(filepath) + if (!fs.existsSync(dir)) { + let folder: string + let curr = dir + while (!['.', '/', path.parse(dir).root].includes(curr)) { + if (fs.existsSync(path.dirname(curr))) { + folder = curr + break + } + curr = path.dirname(curr) + } + await fs.mkdirp(dir) + recovers && recovers.push(async () => { + if (fs.existsSync(folder)) { + await fs.remove(folder) + } + }) + } + fs.writeFileSync(filepath, '', 'utf8') + recovers && recovers.push(async () => { + if (fs.existsSync(filepath)) { + await fs.unlink(filepath) + } + }) + let doc = await this.loadResource(filepath) + let bufnr = doc.bufnr + recovers && recovers.push(() => { + void events.fire('BufUnload', [bufnr]) + return nvim.command(`silent! bd! ${bufnr}`) + }) + this._onDidCreateFiles.fire({ files: [URI.file(filepath)] }) + } + } + + /** + * Delete a file or folder from vim and disk. + */ + public async deleteFile(filepath: string, opts: DeleteFileOptions = {}, recovers?: RecoverFunc[]): Promise { + let { ignoreIfNotExists, recursive } = opts + let stat = await statAsync(filepath) + let isDir = stat && stat.isDirectory() + if (!stat && !ignoreIfNotExists) { + throw errors.fileNotExists(filepath) + } + if (stat == null) return + let uri = URI.file(filepath) + await this.fireWaitUntilEvent(this._onWillDeleteFiles, { files: [uri] }, recovers) + if (!isDir) { + let bufnr = await this.nvim.call('bufnr', [filepath]) + if (bufnr) { + void events.fire('BufUnload', [bufnr]) + await this.nvim.command(`silent! bwipeout ${bufnr}`) + recovers && recovers.push(() => { + return this.loadResource(uri.toString()) + }) + } + } + if (isDir && recursive) { + // copy files for recover + let folder = path.join(os.tmpdir(), 'coc-' + uuid()) + await fs.mkdir(folder) + await fs.copy(filepath, folder, { recursive: true }) + await fs.remove(filepath) + recovers && recovers.push(async () => { + await fs.mkdir(filepath) + await fs.copy(folder, filepath, { recursive: true }) + await fs.remove(folder) + }) + } else if (isDir) { + await fs.rmdir(filepath) + recovers && recovers.push(() => { + return fs.mkdir(filepath) + }) + } else { + let dest = path.join(os.tmpdir(), 'coc-' + uuid()) + await fs.copyFile(filepath, dest) + await fs.unlink(filepath) + recovers && recovers.push(() => { + return fs.move(dest, filepath, { overwrite: true }) + }) + } + this._onDidDeleteFiles.fire({ files: [uri] }) + } + + /** + * Rename a file or folder on vim and disk + */ + public async renameFile(oldPath: string, newPath: string, opts: RenameFileOptions & { skipEvent?: boolean } = {}, recovers?: RecoverFunc[]): Promise { + let { nvim } = this + let { overwrite, ignoreIfExists } = opts + if (newPath === oldPath) return + let exists = fs.existsSync(newPath) + if (exists && ignoreIfExists && !overwrite) return + if (exists && !overwrite) throw errors.fileExists(newPath) + let oldStat = await statAsync(oldPath) + let loaded = (oldStat && oldStat.isDirectory()) ? 0 : await nvim.call('bufloaded', [oldPath]) + if (!loaded && !oldStat) throw errors.fileNotExists(oldPath) + let file = { newUri: URI.parse(newPath), oldUri: URI.parse(oldPath) } + if (!opts.skipEvent) await this.fireWaitUntilEvent(this._onWillRenameFiles, { files: [file] }, recovers) + if (loaded) { + let bufnr = await nvim.call('coc#ui#rename_file', [oldPath, newPath, oldStat != null]) + await this.documents.onBufCreate(bufnr) + } else { + if (oldStat?.isDirectory()) { + for (let doc of this.documents.documents) { + let u = URI.parse(doc.uri) + if (u.scheme === 'file' && isParentFolder(oldPath, u.fsPath, false)) { + let filepath = u.fsPath.replace(oldPath, newPath) + let bufnr = await nvim.call('coc#ui#rename_file', [u.fsPath, filepath, false]) + await this.documents.onBufCreate(bufnr) + } + } + } + fs.renameSync(oldPath, newPath) + } + recovers && recovers.push(() => { + return this.renameFile(newPath, oldPath, { skipEvent: true }) + }) + if (!opts.skipEvent) this._onDidRenameFiles.fire({ files: [file] }) + } + + public async renameCurrent(): Promise { + let { nvim } = this + let oldPath = await nvim.call('expand', ['%:p']) + // await nvim.callAsync() + let newPath = await nvim.callAsync('coc#util#with_callback', ['input', ['New path: ', oldPath, 'file']]) + newPath = newPath ? newPath.trim() : null + if (newPath === oldPath || !newPath) return + if (oldPath.toLowerCase() != newPath.toLowerCase() && fs.existsSync(newPath)) { + let overwrite = await ui.showPrompt(this.nvim, `${newPath} exists, overwrite?`) + if (!overwrite) return + } + await this.renameFile(oldPath, newPath, { overwrite: true }) + } + + private get currentUri(): string { + let document = this.documents.getDocument(this.documents.bufnr) + return document ? document.uri : null + } + + /** + * Apply WorkspaceEdit. + */ + public async applyEdit(edit: WorkspaceEdit, nested?: boolean): Promise { + let documentChanges = toDocumentChanges(edit) + let recovers: RecoverFunc[] = [] + let currentOnly = false + try { + let { changeAnnotations } = edit + let { currentUri } = this + let toConfirm = changeAnnotations ? getConfirmAnnotations(documentChanges, changeAnnotations) : [] + let changes: { [uri: string]: LinesChange } = {} + let denied: string[] = [] + for (let key of toConfirm) { + let annotation = changeAnnotations[key] + annotation.needsConfirmation = false + let res = await this.window.showMenuPicker(['Yes', 'No'], { + position: 'center', + title: 'Confirm edits', + content: annotation.label + (annotation.description ? ' ' + annotation.description : '') + }) + if (res !== 0) denied.push(key) + } + documentChanges = documentChanges.filter(c => !denied.includes(getAnnotationKey(c))) + if (!documentChanges.length) return true + currentOnly = documentChanges.every(o => TextDocumentEdit.is(o) && o.textDocument.uri === currentUri) + this.validateChanges(documentChanges) + for (const change of documentChanges) { + if (TextDocumentEdit.is(change)) { + let { textDocument, edits } = change + let { uri } = textDocument + let doc = await this.loadResource(uri) + let revertEdit = await doc.applyEdits(edits, false, uri === currentUri) + if (revertEdit) { + let version = doc.version + let { newText, range } = revertEdit + changes[uri] = { + uri, + lnum: range.start.line + 1, + newLines: doc.getLines(range.start.line, range.end.line), + oldLines: newText.endsWith('\n') ? newText.slice(0, -1).split('\n') : newText.split('\n') + } + recovers.push(async () => { + let doc = this.documents.getDocument(uri) + if (!doc || !doc.attached || doc.version !== version) return + await doc.applyEdits([revertEdit]) + textDocument.version = doc.version + }) + } + } else if (CreateFile.is(change)) { + await this.createFile(fsPath(change.uri), change.options, recovers) + } else if (DeleteFile.is(change)) { + await this.deleteFile(fsPath(change.uri), change.options, recovers) + } else if (RenameFile.is(change)) { + await this.renameFile(fsPath(change.oldUri), fsPath(change.newUri), change.options, recovers) + } + } + // nothing changed + if (recovers.length === 0) return true + if (!nested) this.editState = { edit: { documentChanges, changeAnnotations: edit.changeAnnotations }, changes, recovers, applied: true } + this.nvim.redrawVim() + } catch (e) { + logger.error('Error on applyEdits:', edit, e) + await this.undoChanges(recovers) + if (!nested) void this.window.showErrorMessage(`Error on applyEdits: ${e}`) + return false + } + // avoid message when change current file only. + if (nested || currentOnly) return true + void this.window.showInformationMessage(`Use ':wa' to save changes or ':CocCommand workspace.inspectEdit' to inspect.`) + return true + } + + private async undoChanges(recovers: RecoverFunc[]): Promise { + while (recovers.length > 0) { + let fn = recovers.pop() + await fn() + } + } + + public async inspectEdit(): Promise { + if (!this.editState) { + void this.window.showWarningMessage('No workspace edit to inspect') + return + } + let inspect = new EditInspect(this.nvim, this.keymaps) + await inspect.show(this.editState) + } + + public async undoWorkspaceEdit(): Promise { + let { editState } = this + if (!editState || !editState.applied) { + void this.window.showWarningMessage(`No workspace edit to undo`) + return + } + editState.applied = false + await this.undoChanges(editState.recovers) + } + + public async redoWorkspaceEdit(): Promise { + let { editState } = this + if (!editState || editState.applied) { + void this.window.showWarningMessage(`No workspace edit to redo`) + return + } + this.editState = undefined + await this.applyEdit(editState.edit) + } + + private validateChanges(documentChanges: ReadonlyArray): void { + let { documents } = this + for (let change of documentChanges) { + if (TextDocumentEdit.is(change)) { + let { uri, version } = change.textDocument + let doc = documents.getDocument(uri) + if (typeof version === 'number' && version > 0) { + if (!doc) throw new Error(`File ${uri} not loaded`) + if (doc.version != version) throw new Error(`${uri} changed before apply edit`) + } else if (!doc) { + if (!isFile(uri)) throw errors.badScheme(URI.parse(uri).scheme) + } + } else if (CreateFile.is(change) || DeleteFile.is(change)) { + if (!isFile(change.uri)) throw errors.badScheme(URI.parse(change.uri).scheme) + } else if (RenameFile.is(change)) { + if (!isFile(change.oldUri) || !isFile(change.newUri)) { + throw errors.badScheme(URI.parse(change.oldUri).scheme) + } + } + } + } + + public async findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Promise { + let folders = this.workspaceFolderControl.workspaceFolders + if (token?.isCancellationRequested || !folders.length || maxResults === 0) return [] + maxResults = maxResults ?? Infinity + let roots = folders.map(o => URI.parse(o.uri).fsPath) + if (typeof include !== 'string') { + let base = include.baseUri.fsPath + roots = roots.filter(r => isParentFolder(base, r, true)) + } + let pattern = typeof include === 'string' ? include : include.pattern + let res: URI[] = [] + for (let root of roots) { + if (res.length >= maxResults) break + let files = await promisify(glob)(pattern, { + dot: true, + cwd: root, + nodir: true, + absolute: false + }) + if (token?.isCancellationRequested) return [] + for (let file of files) { + if (exclude && fileMatch(root, file, exclude)) continue + res.push(URI.file(path.join(root, file))) + if (res.length === maxResults) break + } + } + return res + } + + private async fireWaitUntilEvent(emitter: Emitter, properties: Omit, recovers?: RecoverFunc[]): Promise { + let firing = true + let promises: Promise[] = [] + emitter.fire({ + ...properties, + waitUntil: thenable => { + if (!firing) throw errors.shouldNotAsync('waitUntil') + let tp = new Promise(resolve => { + setTimeout(resolve, this.operationTimeout) + }) + let promise = Promise.race([thenable, tp]).then(edit => { + if (edit && WorkspaceEdit.is(edit)) { + return this.applyEdit(edit, true) + } + }) + promises.push(promise) + } + } as any) + firing = false + await Promise.all(promises) + } +} + +function fileMatch(root: string, relpath: string, pattern: GlobPattern): boolean { + let filepath = path.join(root, relpath) + if (typeof pattern !== 'string') { + let base = pattern.baseUri.fsPath + if (!isParentFolder(base, filepath)) return false + let rp = path.relative(base, filepath) + return minimatch(rp, pattern.pattern, { dot: true }) + } + return minimatch(relpath, pattern, { dot: true }) +} + +function fsPath(uri: string): string { + return URI.parse(uri).fsPath +} diff --git a/sources_non_forked/coc.nvim/src/core/funcs.ts b/sources_non_forked/coc.nvim/src/core/funcs.ts new file mode 100644 index 00000000..184e7b12 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/funcs.ts @@ -0,0 +1,158 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import minimatch from 'minimatch' +import os from 'os' +import path from 'path' +import semver from 'semver' +import { DocumentFilter, DocumentSelector } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import which from 'which' +import Configurations from '../configuration' +import Resolver from '../model/resolver' +import * as fs from '../util/fs' +import * as platform from '../util/platform' +let NAME_SPACE = 2000 +const resolver = new Resolver() + +const namespaceMap: Map = new Map() + +interface PartialEnv { + isVim: boolean + version: string +} + +/** + * Like vim's has(), but for version check only. + * Check patch on neovim and check nvim on vim would return false. + * + * For example: + * - has('nvim-0.6.0') + * - has('patch-7.4.248') + */ +export function has(env: PartialEnv, feature: string): boolean { + if (!feature.startsWith('nvim-') && !feature.startsWith('patch-')) { + throw new Error('Feature param could only starts with nvim and patch') + } + if (!env.isVim && feature.startsWith('patch-')) { + return false + } + if (env.isVim && feature.startsWith('nvim-')) { + return false + } + if (env.isVim) { + let [_, major, minor, patch] = env.version.match(/^(\d)(\d{2})(\d+)$/) + let version = `${major}.${parseInt(minor, 10)}.${parseInt(patch, 10)}` + return semver.gte(version, feature.slice(6)) + } + return semver.gte(env.version, feature.slice(5)) +} + +/* + * Create namespace id. + * + * @deprecated + */ +export function createNameSpace(name = ''): number { + if (namespaceMap.has(name)) return namespaceMap.get(name) + NAME_SPACE = NAME_SPACE + 1 + namespaceMap.set(name, NAME_SPACE) + return NAME_SPACE +} + +/** + * Resolve watchman path. + */ +export function getWatchmanPath(configurations: Configurations): string | null { + const preferences = configurations.getConfiguration('coc.preferences') + let watchmanPath = preferences.get('watchmanPath', 'watchman') + try { + return which.sync(watchmanPath) + } catch (e) { + return null + } +} + +export async function findUp(nvim: Neovim, cwd: string, filename: string | string[]): Promise { + let filepath = await nvim.call('expand', '%:p') as string + filepath = path.normalize(filepath) + let isFile = filepath && path.isAbsolute(filepath) + if (isFile && !fs.isParentFolder(cwd, filepath, true)) { + // can't use cwd + return fs.findUp(filename, path.dirname(filepath)) + } + let res = fs.findUp(filename, cwd) + if (res && res != os.homedir()) return res + if (isFile) return fs.findUp(filename, path.dirname(filepath)) + return null +} + +export function resolveModule(name: string): Promise { + return resolver.resolveModule(name) +} + +export function score(selector: DocumentSelector | DocumentFilter | string, uri: string, languageId: string): number { + if (Array.isArray(selector)) { + // array -> take max individual value + let ret = 0 + for (const filter of selector) { + const value = score(filter, uri, languageId) + if (value === 10) { + return value // already at the highest + } + if (value > ret) { + ret = value + } + } + return ret + } else if (typeof selector === 'string') { + // short-hand notion, desugars to + // 'fooLang' -> { language: 'fooLang'} + // '*' -> { language: '*' } + if (selector === '*') { + return 5 + } else if (selector === languageId) { + return 10 + } else { + return 0 + } + } else if (selector) { + let u = URI.parse(uri) + // filter -> select accordingly, use defaults for scheme + const { language, pattern, scheme } = selector + let ret = 0 + if (scheme) { + if (scheme === u.scheme) { + ret = 5 + } else if (scheme === '*') { + ret = 3 + } else { + return 0 + } + } + + if (language) { + if (language === languageId) { + ret = 10 + } else if (language === '*') { + ret = Math.max(ret, 5) + } else { + return 0 + } + } + + if (pattern) { + let caseInsensitive = platform.isWindows || platform.isMacintosh + let p = caseInsensitive ? pattern.toLowerCase() : pattern + let f = caseInsensitive ? u.fsPath.toLowerCase() : u.fsPath + if (p === f || minimatch(f, p, { dot: true })) { + ret = 5 + } else { + return 0 + } + } + + return ret + } else { + return 0 + } +} diff --git a/sources_non_forked/coc.nvim/src/core/keymaps.ts b/sources_non_forked/coc.nvim/src/core/keymaps.ts new file mode 100644 index 00000000..3595271e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/keymaps.ts @@ -0,0 +1,98 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { v1 as uuid } from 'uuid' +import { Disposable } from 'vscode-languageserver-protocol' +import { KeymapOption } from '../types' +import { getKeymapModifier, MapMode } from '../util' +import Documents from './documents' +const logger = require('../util/logger')('core-keymaps') + +export default class Keymaps { + private readonly keymaps: Map = new Map() + private nvim: Neovim + constructor(private documents: Documents) { + } + + public attach(nvim: Neovim): void { + this.nvim = nvim + } + + public async doKeymap(key: string, defaultReturn = '', pressed?: string): Promise { + let keymap = this.keymaps.get(key) + if (!keymap) { + logger.error(`keymap for ${key} not found`) + if (pressed) this.nvim.command(`silent! unmap ${pressed.startsWith('{') && pressed.endsWith('}') ? `<${pressed.slice(1, -1)}>` : pressed}`, true) + return defaultReturn + } + let [fn, repeat] = keymap + let res = await Promise.resolve(fn()) + if (repeat) await this.nvim.command(`silent! call repeat#set("\\(coc-${key})", -1)`) + return res ?? defaultReturn + } + + /** + * Register (coc-${key}) key mapping. + */ + public registerKeymap(modes: MapMode[], key: string, fn: Function, opts: Partial = {}): Disposable { + if (!key) throw new Error(`Invalid key ${key} of registerKeymap`) + if (this.keymaps.has(key)) throw new Error(`${key} already exists.`) + opts = Object.assign({ sync: true, cancel: true, silent: true, repeat: false }, opts) + let { nvim } = this + this.keymaps.set(key, [fn, !!opts.repeat]) + let method = opts.sync ? 'request' : 'notify' + let silent = opts.silent ? '' : '' + for (let m of modes) { + if (m == 'i') { + nvim.command(`inoremap ${silent} (coc-${key}) coc#_insert_key('${method}', '${key}', ${opts.cancel ? 1 : 0})`, true) + } else { + let modify = getKeymapModifier(m) + nvim.command(`${m}noremap ${silent} (coc-${key}) :${modify}call coc#rpc#${method}('doKeymap', ['${key}'])`, true) + } + } + return Disposable.create(() => { + this.keymaps.delete(key) + for (let m of modes) { + nvim.command(`${m}unmap (coc-${key})`, true) + } + }) + } + + public registerExprKeymap(mode: 'i' | 'n' | 'v' | 's' | 'x', key: string, fn: Function, buffer = false): Disposable { + let id = `${mode}${global.Buffer.from(key).toString('base64')}${buffer ? '1' : '0'}` + let { nvim } = this + this.keymaps.set(id, [fn, false]) + if (mode == 'i') { + nvim.command(`inoremap ${buffer ? '' : ''} ${key} coc#_insert_key('request', '${id}')`, true) + } else { + nvim.command(`${mode}noremap ${buffer ? '' : ''} ${key} coc#rpc#request('doKeymap', ['${id}'])`, true) + } + return Disposable.create(() => { + this.keymaps.delete(id) + nvim.command(`${mode}unmap ${buffer ? '' : ''} ${key}`, true) + }) + } + + public registerLocalKeymap(mode: 'n' | 'v' | 's' | 'x', key: string, fn: Function, notify = false): Disposable { + let id = uuid() + let { nvim } = this + let bufnr = this.documents.bufnr + this.keymaps.set(id, [fn, false]) + let method = notify ? 'notify' : 'request' + let modify = getKeymapModifier(mode) + // neoivm's bug '<' can't be used. + let escaped = key.startsWith('<') && key.endsWith('>') ? `{${key.slice(1, -1)}}` : key + if (this.nvim.hasFunction('nvim_buf_set_keymap') && !global.hasOwnProperty('__TEST__')) { + nvim.call('nvim_buf_set_keymap', [0, mode, key, `:${modify}call coc#rpc#${method}('doKeymap', ['${id}', '', '${escaped}'])`, { + silent: true, + nowait: true + }], true) + } else { + let cmd = `${mode}noremap ${key} :${modify}call coc#rpc#${method}('doKeymap', ['${id}', '', '${escaped}'])` + nvim.command(cmd, true) + } + return Disposable.create(() => { + this.keymaps.delete(id) + nvim.call('coc#compat#buf_del_keymap', [bufnr, mode, key], true) + }) + } +} diff --git a/sources_non_forked/coc.nvim/src/core/locations.ts b/sources_non_forked/coc.nvim/src/core/locations.ts new file mode 100644 index 00000000..912b3f16 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/locations.ts @@ -0,0 +1,56 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Location } from 'vscode-languageserver-protocol' +import Configurations from '../configuration' +import { Env } from '../types' +import { disposeAll } from '../util' +import ContentProvider from './contentProvider' +import Documents from './documents' +const logger = require('../util/logger')('core-locations') + +export default class Locations implements Disposable { + private nvim: Neovim + private env: Env + private disposables: Disposable[] = [] + constructor( + private configurations: Configurations, + private documents: Documents, + private contentProvider: ContentProvider + ) { + } + + public attach(nvim: Neovim, env: Env): void { + this.nvim = nvim + this.env = env + } + + /** + * Populate locations to UI. + */ + public async showLocations(locations: Location[]): Promise { + let { documents, nvim, env, configurations } = this + let items = await documents.getQuickfixList(locations) + const preferences = configurations.getConfiguration('coc.preferences') + if (preferences.get('useQuickfixForLocations', false)) { + let openCommand = await nvim.getVar('coc_quickfix_open_command') as string + if (typeof openCommand != 'string') { + openCommand = items.length < 10 ? `copen ${items.length}` : 'copen' + } + nvim.pauseNotification() + nvim.call('setqflist', [items], true) + nvim.command(openCommand, true) + nvim.resumeNotification(false, true) + } else { + await nvim.setVar('coc_jump_locations', items) + if (env.locationlist) { + nvim.command('CocList --normal --auto-preview location', true) + } else { + nvim.call('coc#util#do_autocmd', ['CocLocationsChange'], true) + } + } + } + + public dispose(): void { + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/core/terminals.ts b/sources_non_forked/coc.nvim/src/core/terminals.ts new file mode 100644 index 00000000..45d019e2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/terminals.ts @@ -0,0 +1,65 @@ +'use strict' +import TerminalModel, { TerminalOptions } from '../model/terminal' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { Neovim } from '@chemzqm/neovim' +import { disposeAll } from '../util' +import events from '../events' +const logger = require('../util/logger')('core-terminals') + +export default class Terminals { + private _terminals: Map = new Map() + private disposables: Disposable[] = [] + private readonly _onDidOpenTerminal = new Emitter() + private readonly _onDidCloseTerminal = new Emitter() + public readonly onDidCloseTerminal: Event = this._onDidCloseTerminal.event + public readonly onDidOpenTerminal: Event = this._onDidOpenTerminal.event + + constructor() { + events.on('BufUnload', bufnr => { + if (this._terminals.has(bufnr)) { + logger.debug('terminal detach', bufnr) + let terminal = this._terminals.get(bufnr) + this._onDidCloseTerminal.fire(terminal) + this._terminals.delete(bufnr) + } + }, null, this.disposables) + events.on('TermExit', (bufnr, status) => { + let terminal = this._terminals.get(bufnr) + if (terminal) { + terminal.onExit(status) + terminal.dispose() + } + }, null, this.disposables) + } + + public get terminals(): ReadonlyArray { + return Array.from(this._terminals.values()) + } + + public async createTerminal(nvim: Neovim, opts: TerminalOptions): Promise { + let cwd = opts.cwd + let cmd = opts.shellPath + let args = opts.shellArgs + if (!cmd) cmd = await nvim.getOption('shell') as string + if (!cwd) cwd = await nvim.call('getcwd') as string + let terminal = new TerminalModel(cmd, args || [], nvim, opts.name, opts.strictEnv) + await terminal.start(cwd, opts.env) + this._terminals.set(terminal.bufnr, terminal) + this._onDidOpenTerminal.fire(terminal) + return terminal + } + + public reset(): void { + for (let terminal of this._terminals.values()) { + terminal.dispose() + } + this._terminals.clear() + } + + public dispose(): void { + this._onDidOpenTerminal.dispose() + this._onDidCloseTerminal.dispose() + disposeAll(this.disposables) + this.reset() + } +} diff --git a/sources_non_forked/coc.nvim/src/core/ui.ts b/sources_non_forked/coc.nvim/src/core/ui.ts new file mode 100644 index 00000000..ae10ac88 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/ui.ts @@ -0,0 +1,104 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Position, Range } from 'vscode-languageserver-protocol' +import { ScreenPosition } from '../types' +import { byteLength } from '../util/string' + +const isVim = process.env.VIM_NODE_RPC == '1' + +export async function getCursorPosition(nvim: Neovim): Promise { + // vim can't count utf16 + let [line, content] = await nvim.eval(`[line('.')-1, strpart(getline('.'), 0, col('.') - 1)]`) as [number, string] + return Position.create(line, content.length) +} + +/** + * Prompt user for confirm, a float/popup window would be used when possible, + * use vim's |confirm()| function as callback. + * + * @param title The prompt text. + * @returns Result of confirm. + */ +export async function showPrompt(nvim: Neovim, title: string): Promise { + let res = await nvim.callAsync('coc#dialog#prompt_confirm', [title]) + return res == 1 +} + +/** + * Move cursor to position. + * + * @param position LSP position. + */ +export async function moveTo(nvim: Neovim, position: Position, redraw: boolean): Promise { + await nvim.call('coc#cursor#move_to', [position.line, position.character]) + if (redraw) nvim.command('redraw', true) +} + +/** + * Get current cursor character offset in document, + * length of line break would always be 1. + * + * @returns Character offset. + */ +export async function getOffset(nvim: Neovim): Promise { + return await nvim.call('coc#cursor#char_offset') as number +} + +/** + * Get screen position of current cursor(relative to editor), + * both `row` and `col` are 0 based. + * + * @returns Cursor screen position. + */ +export async function getCursorScreenPosition(nvim: Neovim): Promise { + let [row, col] = await nvim.call('coc#cursor#screen_pos') as [number, number] + return { row, col } +} + +/** + * Reveal message with highlight. + */ +export function showMessage(nvim: Neovim, msg: string, hl: 'MoreMsg' | 'Error' | 'ErrorMsg' | 'WarningMsg' = 'MoreMsg', forceTimer = false): void { + let method = forceTimer || isVim ? 'callTimer' : 'call' + nvim[method]('coc#ui#echo_messages', [hl, ('[coc.nvim] ' + msg).split('\n')], true) +} + +/** + * Mode could be 'char', 'line', 'cursor', 'v', 'V', '\x16' + */ +export async function getSelection(nvim: Neovim, mode: string): Promise { + if (mode === 'line') { + let line = await nvim.call('line', ['.']) + return Range.create(line - 1, 0, line, 0) + } + if (mode === 'cursor') { + let [line, character] = await nvim.eval("coc#cursor#position()") as [number, number] + return Range.create(line, character, line, character) + } + let res = await nvim.call('coc#cursor#get_selection', [mode === 'char' ? 1 : 0]) + if (!res) return null + return Range.create(res[0], res[1], res[2], res[3]) +} + +export async function selectRange(nvim: Neovim, range: Range, redraw: boolean): Promise { + let { start, end } = range + let [line, endLine] = await nvim.eval(`[getline(${start.line + 1}),getline(${end.line + 1})]`) as [string, string] + let col = line.length > 0 ? byteLength(line.slice(0, start.character)) : 0 + let endCol: number + let endLnum: number + let toEnd = end.character == 0 + if (toEnd) { + endLnum = end.line == 0 ? 0 : end.line - 1 + let pre = await nvim.call('getline', [endLnum + 1]) as string + endCol = byteLength(pre) + } else { + endLnum = end.line + endCol = endLine.length > 0 ? byteLength(endLine.slice(0, end.character)) : 0 + } + nvim.pauseNotification() + nvim.command(`noa call cursor(${start.line + 1},${col + 1})`, true) + nvim.command('normal! v', true) + nvim.command(`noa call cursor(${endLnum + 1},${endCol})`, true) + if (toEnd) nvim.command('normal! $', true) + await nvim.resumeNotification(redraw) +} diff --git a/sources_non_forked/coc.nvim/src/core/watchers.ts b/sources_non_forked/coc.nvim/src/core/watchers.ts new file mode 100644 index 00000000..85cf9d5f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/watchers.ts @@ -0,0 +1,90 @@ +'use strict' +import events from '../events' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { Env } from '../types' +import { disposeAll } from '../util' +const logger = require('../util/logger')('core-watchers') + +export default class Watchers implements Disposable { + private nvim: Neovim + private env: Env + private watchedOptions: Set = new Set() + private disposables: Disposable[] = [] + private _onDidRuntimePathChange = new Emitter() + private readonly _onDidOptionChange = new Emitter() + + public readonly onDidRuntimePathChange: Event = this._onDidRuntimePathChange.event + public readonly onDidOptionChange: Event = this._onDidOptionChange.event + + public get options(): string[] { + return Array.from(this.watchedOptions) + } + + public attach(nvim: Neovim, env: Env): void { + this.nvim = nvim + this.env = env + this.watchOption('runtimepath', (oldValue, newValue: string) => { + let oldList: string[] = oldValue.split(',') + let newList: string[] = newValue.split(',') + let paths = newList.filter(x => !oldList.includes(x)) + if (paths.length > 0) { + this._onDidRuntimePathChange.fire(paths) + } + this.env.runtimepath = newValue + }, this.disposables) + } + + /** + * Watch for option change. + */ + public watchOption(key: string, callback: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void { + let watching = this.watchedOptions.has(key) + if (!watching) { + this.watchedOptions.add(key) + this._onDidOptionChange.fire() + } + let disposable = events.on('OptionSet', async (changed: string, oldValue: any, newValue: any) => { + if (changed == key && callback) { + await Promise.resolve(callback(oldValue, newValue)) + } + }) + if (disposables) { + disposables.push( + Disposable.create(() => { + disposable.dispose() + if (watching) return + this.watchedOptions.delete(key) + this._onDidOptionChange.fire() + }) + ) + } + } + + /** + * Watch global variable, works on neovim only. + */ + public watchGlobal(key: string, callback: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void { + let { nvim } = this + nvim.call('coc#_watch', key, true) + let disposable = events.on('GlobalChange', async (changed: string, oldValue: any, newValue: any) => { + if (changed == key) { + await Promise.resolve(callback(oldValue, newValue)) + } + }) + if (disposables) { + disposables.push( + Disposable.create(() => { + disposable.dispose() + nvim.call('coc#_unwatch', key, true) + }) + ) + } + } + + public dispose(): void { + disposeAll(this.disposables) + this._onDidOptionChange.dispose() + this._onDidRuntimePathChange.dispose() + } +} diff --git a/sources_non_forked/coc.nvim/src/core/watchman.ts b/sources_non_forked/coc.nvim/src/core/watchman.ts new file mode 100644 index 00000000..4b6278b1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/watchman.ts @@ -0,0 +1,184 @@ +'use strict' +import watchman, { Client } from 'fb-watchman' +import minimatch from 'minimatch' +import os from 'os' +import path from 'path' +import { v1 as uuidv1 } from 'uuid' +import { Disposable } from 'vscode-languageserver-protocol' +import { OutputChannel } from '../types' +import { isParentFolder } from '../util/fs' +const logger = require('../util/logger')('core-watchman') +const requiredCapabilities = ['relative_root', 'cmd-watch-project', 'wildmatch', 'field-new'] + +export interface WatchResponse { + warning?: string + watcher: string + watch: string + relative_path?: string +} + +export interface FileChangeItem { + size: number + name: string + exists: boolean + new: boolean + type: 'f' | 'd' + mtime_ms: number +} + +export interface FileChange { + root: string + subscription: string + files: FileChangeItem[] +} + +export type ChangeCallback = (FileChange) => void + +/** + * Watchman wrapper for fb-watchman client + * + * @public + */ +export default class Watchman { + private client: Client + private watch: string | undefined + private relative_path: string | undefined + private _disposed = false + + constructor(binaryPath: string, private channel?: OutputChannel) { + this.client = new watchman.Client({ + watchmanBinaryPath: binaryPath + }) + this.client.setMaxListeners(300) + } + + public checkCapability(): Promise { + let { client } = this + return new Promise((resolve, reject) => { + client.capabilityCheck({ + optional: [], + required: requiredCapabilities + }, (error, resp) => { + if (error) return resolve(false) + let { capabilities } = resp + for (let key of Object.keys(capabilities)) { + if (!capabilities[key]) return resolve(false) + } + resolve(true) + }) + }) + } + + public async watchProject(root: string): Promise { + let resp = await this.command(['watch-project', root]) + let { watch, warning, relative_path } = resp as WatchResponse + if (!watch) return false + if (warning) logger.warn(warning) + this.watch = watch + this.relative_path = relative_path + logger.info(`watchman watching project: ${root}`) + this.appendOutput(`watchman watching project: ${root}`) + return true + } + + private command(args: any[]): Promise { + return new Promise((resolve, reject) => { + this.client.command(args, (error, resp) => { + if (error) return reject(error) + resolve(resp) + }) + }) + } + + public async subscribe(globPattern: string, cb: ChangeCallback): Promise { + let { watch, relative_path } = this + if (!watch) throw new Error('watchman not watching') + let { clock } = await this.command(['clock', watch]) + let uid = uuidv1() + let sub: any = { + expression: ['allof', ['match', '**/*', 'wholename']], + fields: ['name', 'size', 'new', 'exists', 'type', 'mtime_ms', 'ctime_ms'], + since: clock, + } + let root = watch + if (relative_path) { + sub.relative_root = relative_path + root = path.join(watch, relative_path) + } + let { subscribe } = await this.command(['subscribe', watch, uid, sub]) + this.appendOutput(`subscribing "${globPattern}" in ${root}`) + this.client.on('subscription', resp => { + if (!resp || resp.subscription != uid) return + let { files } = resp as FileChange + if (!files) return + files = files.filter(f => f.type == 'f' && minimatch(f.name, globPattern, { dot: true })) + if (!files.length) return + let ev: FileChange = Object.assign({}, resp) + if (this.relative_path) ev.root = path.resolve(resp.root, this.relative_path) + this.appendOutput(`file change detected: ${JSON.stringify(ev, null, 2)}`) + cb(ev) + }) + // return Disposable.create(() => ) + return { + dispose: () => { + void this.unsubscribe(subscribe) + }, + subscribe + } + } + + public unsubscribe(subscription: string): Promise { + if (this._disposed) return Promise.resolve() + let { watch } = this + if (!watch) return + this.appendOutput(`unsubscribe "${subscription}" in: ${watch}`) + return this.command(['unsubscribe', watch, subscription]).catch(e => { + if (e.message?.includes('The client was ended')) logger.error(e) + }) + } + + public dispose(): void { + if (this._disposed) return + this._disposed = true + if (this.client) { + this.client.removeAllListeners() + this.client.end() + this.client = undefined + } + } + + private appendOutput(message: string, type = "Info"): void { + if (this.channel) { + this.channel.appendLine(`[${type} - ${(new Date().toLocaleTimeString())}] ${message}`) + } + } + + public static async createClient(binaryPath: string, root: string, channel?: OutputChannel): Promise { + if (!isValidWatchRoot(root)) return null + let watchman: Watchman + try { + watchman = new Watchman(binaryPath, channel) + let valid = await watchman.checkCapability() + if (!valid) throw new Error('required capabilities do not exist.') + let watching = await watchman.watchProject(root) + if (!watching) throw new Error('unable to watch') + return watchman + } catch (e) { + if (watchman) watchman.dispose() + logger.error(`Error on watchman create`, e) + return null + } + } +} + +/** + * Exclude user's home, driver, tmpdir + */ +export function isValidWatchRoot(root: string): boolean { + if (root == '/' || root == '/tmp' || root == '/private/tmp') return false + if (isParentFolder(root, os.homedir(), true)) return false + if (path.parse(root).base == root) return false + if (root.startsWith('/tmp/') || root.startsWith('/private/tmp/')) return false + if (isParentFolder(os.tmpdir(), root, true)) return false + return true +} diff --git a/sources_non_forked/coc.nvim/src/core/workspaceFolder.ts b/sources_non_forked/coc.nvim/src/core/workspaceFolder.ts new file mode 100644 index 00000000..dc473d07 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/core/workspaceFolder.ts @@ -0,0 +1,186 @@ +'use strict' +import path from 'path' +import { Emitter, Event, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import Configurations from '../configuration' +import Document from '../model/document' +import { PatternType } from '../types' +import { distinct } from '../util/array' +import { isParentFolder, resolveRoot } from '../util/fs' + +function toWorkspaceFolder(fsPath: string): WorkspaceFolder | undefined { + if (!fsPath || !path.isAbsolute(fsPath)) return undefined + return { + name: path.basename(fsPath), + uri: URI.file(fsPath).toString() + } +} + +export default class WorkspaceFolderController { + private _onDidChangeWorkspaceFolders = new Emitter() + public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event + // filetype => patterns + private rootPatterns: Map = new Map() + private _workspaceFolders: WorkspaceFolder[] = [] + constructor( + private readonly configurations: Configurations + ) { + } + + public setWorkspaceFolders(folders: string[] | undefined): void { + if (!folders || !Array.isArray(folders)) return + let arr = folders.map(f => toWorkspaceFolder(f)) + this._workspaceFolders = arr.filter(o => o != null) + } + + public getWorkspaceFolder(uri: URI): WorkspaceFolder | undefined { + if (uri.scheme !== 'file') return undefined + let folders = Array.from(this._workspaceFolders).map(o => URI.parse(o.uri).fsPath) + folders.sort((a, b) => b.length - a.length) + let fsPath = uri.fsPath + let folder = folders.find(f => isParentFolder(f, fsPath, true)) + return toWorkspaceFolder(folder) + } + + public getRelativePath(pathOrUri: string | URI, includeWorkspace?: boolean): string { + let resource: URI | undefined + let p = '' + if (typeof pathOrUri === 'string') { + resource = URI.file(pathOrUri) + p = pathOrUri + } else if (typeof pathOrUri !== 'undefined') { + resource = pathOrUri + p = pathOrUri.fsPath + } + if (!resource) return p + const folder = this.getWorkspaceFolder(resource) + if (!folder) return p + if (typeof includeWorkspace === 'undefined' && this._workspaceFolders) { + includeWorkspace = this._workspaceFolders.length > 1 + } + let result = path.relative(URI.parse(folder.uri).fsPath, resource.fsPath) + result = result == '' ? resource.fsPath : result + if (includeWorkspace && folder.name) { + result = `${folder.name}/${result}` + } + return result! + } + + public get workspaceFolders(): ReadonlyArray { + return this._workspaceFolders + } + + public addRootPattern(filetype: string, rootPatterns: string[]): void { + let patterns = this.rootPatterns.get(filetype) || [] + for (let p of rootPatterns) { + if (!patterns.includes(p)) { + patterns.push(p) + } + } + this.rootPatterns.set(filetype, patterns) + } + + public resolveRoot(document: Document, cwd: string, fireEvent: boolean, expand: ((input: string) => string)): string | null { + if (document.buftype !== '' || document.schema !== 'file' || !document.enabled) return null + let types = [PatternType.Buffer, PatternType.LanguageServer, PatternType.Global] + let u = URI.parse(document.uri) + let dir = path.dirname(u.fsPath) + let config = this.configurations.getConfiguration('workspace', document.uri) + let ignoredFiletypes = config.get('ignoredFiletypes', []) + let bottomUpFiletypes = config.get('bottomUpFiletypes', []) + let checkCwd = config.get('workspaceFolderCheckCwd', true) + let ignored = config.get('ignoredFolders', []) + let fallbackCwd = config.get('workspaceFolderFallbackCwd', true) + if (ignoredFiletypes?.includes(document.filetype)) return null + let curr = this.getWorkspaceFolder(URI.parse(document.uri)) + if (curr) return URI.parse(curr.uri).fsPath + ignored = Array.isArray(ignored) ? ignored.filter(s => s && s.length > 0).map(s => expand(s)) : [] + let res: string | null = null + for (let patternType of types) { + let patterns = this.getRootPatterns(document, patternType) + if (patterns && patterns.length) { + let isBottomUp = bottomUpFiletypes.includes('*') || bottomUpFiletypes.includes(document.filetype) + let root = resolveRoot(dir, patterns, cwd, isBottomUp, checkCwd, ignored) + if (root) { + res = root + break + } + } + } + if (fallbackCwd && !res && !ignored.includes(cwd) && isParentFolder(cwd, dir, true)) { + res = cwd + } + if (res) this.addWorkspaceFolder(res, fireEvent) + return res + } + + public addWorkspaceFolder(folder: string, fireEvent: boolean): WorkspaceFolder | undefined { + let workspaceFolder: WorkspaceFolder = toWorkspaceFolder(folder) + if (!workspaceFolder) return undefined + if (this._workspaceFolders.findIndex(o => o.uri == workspaceFolder.uri) == -1) { + this._workspaceFolders.push(workspaceFolder) + if (fireEvent) { + this._onDidChangeWorkspaceFolders.fire({ + added: [workspaceFolder], + removed: [] + }) + } + } + return workspaceFolder + } + + public renameWorkspaceFolder(oldPath: string, newPath: string): void { + let added: WorkspaceFolder = toWorkspaceFolder(newPath) + if (!added) return + let idx = this._workspaceFolders.findIndex(f => URI.parse(f.uri).fsPath == oldPath) + if (idx == -1) return + let removed = this.workspaceFolders[idx] + this._workspaceFolders.splice(idx, 1, added) + this._onDidChangeWorkspaceFolders.fire({ + removed: [removed], + added: [added] + }) + } + + public removeWorkspaceFolder(fsPath: string): void { + let removed = toWorkspaceFolder(fsPath) + if (!removed) return + let idx = this._workspaceFolders.findIndex(f => f.uri == removed.uri) + if (idx == -1) return + this._workspaceFolders.splice(idx, 1) + this._onDidChangeWorkspaceFolders.fire({ + removed: [removed], + added: [] + }) + } + + public getRootPatterns(document: Document, patternType: PatternType): string[] { + let { uri } = document + if (patternType == PatternType.Buffer) return document.getVar('root_patterns', []) || [] + if (patternType == PatternType.LanguageServer) return this.getServerRootPatterns(document.languageId) + const preferences = this.configurations.getConfiguration('coc.preferences', uri) + return preferences.get('rootPatterns', ['.git', '.hg', '.projections.json']).slice() + } + + public reset(): void { + this.rootPatterns.clear() + this._workspaceFolders = [] + } + + /** + * Get rootPatterns of filetype by languageserver configuration and extension configuration. + */ + private getServerRootPatterns(filetype: string): string[] { + let lspConfig = this.configurations.getConfiguration().get<{ [key: string]: unknown }>('languageserver', {}) + let patterns: string[] = [] + for (let key of Object.keys(lspConfig)) { + let config: any = lspConfig[key] + let { filetypes, rootPatterns } = config + if (Array.isArray(filetypes) && rootPatterns && filetypes.includes(filetype)) { + patterns.push(...rootPatterns) + } + } + patterns = patterns.concat(this.rootPatterns.get(filetype) || []) + return patterns.length ? distinct(patterns) : [] + } +} diff --git a/sources_non_forked/coc.nvim/src/cursors/index.ts b/sources_non_forked/coc.nvim/src/cursors/index.ts new file mode 100644 index 00000000..dd9c611c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/cursors/index.ts @@ -0,0 +1,126 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Range } from 'vscode-languageserver-protocol' +import Document from '../model/document' +import { comparePosition } from '../util/position' +import window from '../window' +import workspace from '../workspace' +import CursorSession from './session' +import { getVisualRanges, splitRange } from './util' +const logger = require('../util/logger')('cursors') + +export default class Cursors { + private sessionsMap: Map = new Map() + private disposables: Disposable[] = [] + constructor(private nvim: Neovim) { + workspace.onDidCloseTextDocument(e => { + let session = this.getSession(e.bufnr) + if (!session) return + this.sessionsMap.delete(e.bufnr) + session.cancel() + }, null, this.disposables) + } + + public cancel(uri: number | string): void { + let doc = workspace.getDocument(uri) + if (!doc) return + let session = this.getSession(doc.bufnr) + if (session) session.cancel() + } + + public getSession(bufnr: number): CursorSession | undefined { + return this.sessionsMap.get(bufnr) + } + + public async isActivated(): Promise { + let bufnr = await this.nvim.call('bufnr', ['%']) as number + return this.sessionsMap.get(bufnr) != null + } + + public async select(bufnr: number, kind: string, mode: string): Promise { + let doc = workspace.getAttachedDocument(bufnr) + let { nvim } = this + let session = this.createSession(doc) + let pos = await window.getCursorPosition() + let range: Range + if (kind == 'operator') { + await nvim.command(`normal! ${mode == 'line' ? `'[` : '`['}`) + let start = await window.getCursorPosition() + await nvim.command(`normal! ${mode == 'line' ? `']` : '`]'}`) + let end = await window.getCursorPosition() + await window.moveTo(pos) + let relative = comparePosition(start, end) + // do nothing for empty range + if (relative == 0) return + if (relative >= 0) [start, end] = [end, start] + // include end character + let line = doc.getline(end.line) + if (end.character < line.length) { + end.character = end.character + 1 + } + let ranges = splitRange(doc, Range.create(start, end)) + session.addRanges(ranges) + } else if (kind == 'word') { + range = doc.getWordRangeAtPosition(pos) + if (!range) { + let line = doc.getline(pos.line) + if (pos.character == line.length) { + range = Range.create(pos.line, Math.max(0, line.length - 1), pos.line, line.length) + } else { + range = Range.create(pos.line, pos.character, pos.line, pos.character + 1) + } + } + session.addRange(range) + await nvim.command(`silent! call repeat#set("\\(coc-cursors-${kind})", -1)`) + } else if (kind == 'position') { + // make sure range contains character for highlight + let line = doc.getline(pos.line) + if (pos.character >= line.length) { + range = Range.create(pos.line, line.length - 1, pos.line, line.length) + } else { + range = Range.create(pos.line, pos.character, pos.line, pos.character + 1) + } + session.addRange(range) + await nvim.command(`silent! call repeat#set("\\(coc-cursors-${kind})", -1)`) + } else if (kind == 'range') { + await nvim.call('eval', 'feedkeys("\\", "in")') + let range = await window.getSelectedRange(mode) + if (!range) return + let ranges = mode == '\x16' ? getVisualRanges(doc, range) : splitRange(doc, range) + for (let r of ranges) { + session.addRange(r) + } + } else { + throw new Error(`select kind "${kind}" not supported`) + } + } + + public createSession(doc: Document): CursorSession { + let { bufnr } = doc + let session = this.getSession(bufnr) + if (session) return session + session = new CursorSession(this.nvim, doc) + this.sessionsMap.set(bufnr, session) + session.onDidCancel(() => { + session.dispose() + this.sessionsMap.delete(bufnr) + }) + return session + } + + // Add ranges to current document + public async addRanges(ranges: Range[]): Promise { + let { nvim } = this + let bufnr = await nvim.call('bufnr', ['%']) as number + let doc = workspace.getAttachedDocument(bufnr) + let session = this.createSession(doc) + return session.addRanges(ranges) + } + + public reset(): void { + for (let session of this.sessionsMap.values()) { + session.cancel() + } + this.sessionsMap.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/cursors/session.ts b/sources_non_forked/coc.nvim/src/cursors/session.ts new file mode 100644 index 00000000..16994ef0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/cursors/session.ts @@ -0,0 +1,391 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fastDiff from 'fast-diff' +import { Disposable, Emitter, Event, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import Document from '../model/document' +import { DidChangeTextDocumentParams, HighlightItem } from '../types' +import { disposeAll } from '../util' +import { comparePosition, emptyRange, rangeAdjacent, rangeInRange, rangeIntersect, rangeOverlap } from '../util/position' +import { lineCountChange } from '../util/textedit' +import window from '../window' +import workspace from '../workspace' +import TextRange from './textRange' +import { getBeforeCount, getChange, getDelta, SurrondChange, TextChange } from './util' +const logger = require('../util/logger')('cursors-session') + +export interface Config { + cancelKey: string + previousKey: string + nextKey: string + wrapscan: boolean +} + +export interface DiffItem { + offset: number + add?: string + remove?: string +} + +/** + * Cursor session for single buffer + */ +export default class CursorSession { + private readonly _onDidCancel = new Emitter() + private readonly _onDidUpdate = new Emitter() + public readonly onDidCancel: Event = this._onDidCancel.event + public readonly onDidUpdate: Event = this._onDidUpdate.event + private disposables: Disposable[] = [] + private ranges: TextRange[] = [] + private activated = true + private changing = false + private config: Config + constructor(private nvim: Neovim, private doc: Document) { + doc.buffer.setVar('coc_cursors_activated', 1, true) + this.loadConfig() + let { cancelKey, nextKey, previousKey } = this.config + this.disposables.push(workspace.registerLocalKeymap('n', cancelKey, () => { + this.cancel() + })) + this.disposables.push(workspace.registerLocalKeymap('n', nextKey, async () => { + let ranges = this.ranges.map(o => o.range) + let curr = await window.getCursorPosition() + for (let r of ranges) { + if (comparePosition(r.start, curr) > 0) { + await window.moveTo(r.start) + return + } + } + let wrap = this.config.wrapscan + if (ranges.length && wrap) await window.moveTo(ranges[0].start) + })) + this.disposables.push(workspace.registerLocalKeymap('n', previousKey, async () => { + let ranges = this.ranges.map(o => o.range) + let curr = await window.getCursorPosition() + for (let i = ranges.length - 1; i >= 0; i--) { + let r = ranges[i] + if (comparePosition(r.end, curr) < 0) { + await window.moveTo(r.start) + return + } + } + let wrap = this.config.wrapscan + if (ranges.length && wrap) await window.moveTo(ranges[ranges.length - 1].start) + })) + this.doc.onDocumentChange(async e => { + await this.onChange(e) + if (this.activated && !this.changing) { + this._onDidUpdate.fire() + } + }, this, this.disposables) + } + + private loadConfig(): void { + let config = workspace.getConfiguration('cursors', this.doc.uri) + this.config = { + nextKey: config.get('nextKey', ''), + previousKey: config.get('previousKey', ''), + cancelKey: config.get('cancelKey', ''), + wrapscan: config.get('wrapscan', true), + } + } + + /** + * Add or remove range. + */ + public addRange(range: Range): void { + let { ranges } = this + let idx = ranges.findIndex(o => rangeIntersect(o.range, range)) + // remove range when intersect + if (idx !== -1) { + ranges.splice(idx, 1) + } else { + this.createRange(range) + ranges.sort((a, b) => comparePosition(a.range.start, b.range.start)) + } + if (this.ranges.length == 0) { + this.cancel() + } else { + this.doHighlights() + } + } + + public addRanges(ranges: Range[]): boolean { + this.doc._forceSync() + // filter overlap ranges + this.ranges = this.ranges.filter(r => { + return !ranges.some(range => rangeOverlap(range, r.range)) + }) + for (let range of ranges) { + this.createRange(range) + } + this.ranges.sort((a, b) => comparePosition(a.range.start, b.range.start)) + this.doHighlights() + return true + } + + private createRange(range: Range): void { + let { textDocument } = this.doc + let { line, character } = range.start + let text = textDocument.getText(range) + this.ranges.push(new TextRange(line, character, text)) + } + + public async onChange(e: DidChangeTextDocumentParams): Promise { + if (!this.activated || this.changing) return + if (e.contentChanges.length === 0) { + this.doHighlights() + return + } + let change = e.contentChanges[0] + let { text, range } = change + let affected = this.ranges.filter(r => { + if (!rangeIntersect(range, r.range)) return false + if (rangeAdjacent(range, r.range)) { + if (text.includes('\n') || !emptyRange(range)) return false + } + return true + }) + if (emptyRange(range) && affected.length > 0) { + affected = affected.slice(0, 1) + } + if (affected.length == 0) { + logger.debug('no affected ranges') + this.ranges.forEach(r => { + r.adjustFromEdit({ range, newText: text }) + }) + this.doHighlights() + } else if (affected.length == 1 && rangeInRange(range, affected[0].range)) { + logger.debug('affected single range') + if (text.includes('\n')) { + this.cancel() + return + } + // change textRange + await this.applySingleEdit(affected[0], { range, newText: text }) + } else if (!text.length || !this.validChange(range, text)) { + logger.debug('filter affected ranges.') + let ranges = this.ranges.filter(r => !affected.includes(r)) + if (ranges.length > 0) { + this.ranges = ranges + ranges.forEach(r => { + r.adjustFromEdit({ range, newText: text }) + }) + this.doHighlights() + } else { + this.cancel() + } + } else { + logger.debug('Check undo & redo') + let first = this.ranges[0] + let last = this.ranges[this.ranges.length - 1] + let originalLines = e.originalLines.slice(first.line, last.line + 1) + let newLines = this.doc.textDocument.lines.slice(first.line, last.line + 1) + this.applyComposedEdit(originalLines, newLines) + } + } + + public validChange(range: Range, text: string): boolean { + if (lineCountChange(TextEdit.replace(range, text)) != 0) return false + if (!rangeInRange(range, this.range)) return false + let first = this.ranges[0] + let last = this.ranges[this.ranges.length - 1] + if (range.start.line != first.position.line || range.end.line != last.position.line) return false + return true + } + + public get range(): Range { + let first = this.ranges[0] + let last = this.ranges[this.ranges.length - 1] + return Range.create(first.position, last.range.end) + } + + private doHighlights(): void { + let { nvim, ranges, doc } = this + let buffer = doc.buffer + let items: HighlightItem[] = [] + ranges.forEach(r => { + doc.addHighlights(items, 'CocCursorRange', r.range, { + combine: false, + start_incl: true, + end_incl: true + }) + }) + items.sort((a, b) => { + if (a.lnum != b.lnum) return a.lnum - b.lnum + if (a.colStart != b.colStart) return a.colStart - b.colStart + return 0 + }) + buffer.updateHighlights('cursors', items, { priority: 4096 }) + nvim.redrawVim() + } + + public get currentRanges(): Range[] { + return this.ranges.map(r => r.range) + } + + /** + * Cancel session and highlights + */ + public cancel(): void { + if (!this.activated) return + logger.debug('cursors cancel') + let { nvim, doc } = this + let buffer = doc.buffer + this.activated = false + this.ranges = [] + nvim.pauseNotification() + buffer.clearNamespace('cursors') + buffer.setVar('coc_cursors_activated', 0, true) + nvim.resumeNotification(true, true) + this._onDidUpdate.fire() + this._onDidCancel.fire() + } + + /** + * Called on buffer unload or cancel + */ + public dispose(): void { + if (!this.doc) return + this._onDidCancel.dispose() + this._onDidUpdate.dispose() + disposeAll(this.disposables) + this.ranges = [] + this.doc = null + } + + private async applySingleEdit(textRange: TextRange, edit: TextEdit): Promise { + // single range change, calculate & apply changes for all ranges + let { doc, ranges } = this + let after = ranges.filter(r => r !== textRange && r.position.line == textRange.position.line) + after.forEach(r => r.adjustFromEdit(edit)) + let change = getChange(textRange, edit.range, edit.newText) + let delta = getDelta(change) + ranges.forEach(r => r.applyChange(change)) + let edits = ranges.filter(r => r !== textRange).map(o => o.textEdit) + // logger.debug('edits:', JSON.stringify(edits, null, 2)) + this.changing = true + await doc.applyEdits(edits, true, true) + this.changing = false + if (delta != 0) { + for (let r of ranges) { + let n = getBeforeCount(r, this.ranges, textRange) + r.move(n * delta) + } + } + this.doHighlights() + } + + public applyComposedEdit(originalLines: string[], newLines: string[]): boolean { + // check complex edit + let diffs = fastDiff(originalLines[0], newLines[0]) + let first = this.ranges[0] + // let ranges = this.ranges.filter(o => o.line == first.line) + let s = first.position.character + let firstLine = first.position.line + let len = first.text.length + let diff = diffs[0] + if (s > 0 && (diff[0] != fastDiff.EQUAL || !diff[1].startsWith(originalLines[0].slice(0, s)))) { + this.cancel() + return false + } + let used = 0 + let invalid = false + let changes: DiffItem[] = [] + for (let i = 0; i < diffs.length; i++) { + let [kind, text] = diffs[i] + if (i == 0 && s > 0) { + text = text.slice(s) + } + if (kind == fastDiff.EQUAL) { + used += text.length + if (used > len) break + } else if (kind == fastDiff.DELETE) { + let offset = used + used += text.length + if (used > len) { + invalid = true + break + } + changes.push({ offset, remove: text }) + } else { + let prev = diffs[i - 1] + if (prev && prev[0] == fastDiff.DELETE) { + changes[changes.length - 1].add = text + } else { + changes.push({ offset: used, add: text }) + } + } + } + if (invalid || !changes.length) { + this.cancel() + return false + } + let doc = TextDocument.create('file:///1', '', 0, originalLines.join('\n')) + let change: TextChange | SurrondChange + if (changes.length == 1) { + change = { + offset: changes[0].offset, + remove: changes[0].remove ? changes[0].remove.length : 0, + insert: changes[0].add ?? '' + } + } else if (surrondChanges(changes, len)) { + change = { + prepend: [changes[0].remove ? changes[0].remove.length : 0, changes[0].add ?? ''], + append: [changes[1].remove ? changes[1].remove.length : 0, changes[1].add ?? ''] + } + } else { + let text = first.text + let oldText = '' + let newText = '' + let offset = changes[0].offset + for (let c of changes) { + if (c.offset > offset + oldText.length) { + let s = text.slice(offset + oldText.length, c.offset) + oldText += s + newText += s + } + if (c.add) { + newText += c.add + } + if (c.remove) { + oldText += c.remove + } + } + change = { + offset, + remove: oldText.length, + insert: newText + } + } + let edits: TextEdit[] = this.ranges.map(o => { + let line = o.position.line - firstLine + let { start, end } = o.range + let range = Range.create(line, start.character, line, end.character) + o.applyChange(change) + return TextEdit.replace(range, o.text) + }) + let content = TextDocument.applyEdits(doc, edits) + if (content !== newLines.join('\n')) { + this.cancel() + return false + } + + let delta = getDelta(change) + if (delta != 0) { + for (let r of this.ranges) { + let n = getBeforeCount(r, this.ranges) + r.move(n * delta) + } + } + this.doHighlights() + return true + } +} + +export function surrondChanges(changes: DiffItem[], len: number): boolean { + if (changes.length != 2 || changes[0].offset != 0) return false + let end = changes[1].offset + (changes[1].remove ? changes[1].remove.length : 0) + if (end !== len) return false + return true +} diff --git a/sources_non_forked/coc.nvim/src/cursors/textRange.ts b/sources_non_forked/coc.nvim/src/cursors/textRange.ts new file mode 100644 index 00000000..e9ada938 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/cursors/textRange.ts @@ -0,0 +1,93 @@ +'use strict' +import { Position, Range, TextEdit } from 'vscode-languageserver-types' +import { getEnd } from '../util/position' +import { getChangedPosition } from '../util/textedit' +import { isSurrondChange, SurrondChange, TextChange } from './util' +const logger = require('../util/logger')('cursors-range') + +export default class TextRange { + private start: Position + private end: Position + private _text: string + + constructor(line: number, character: number, text: string) { + this.start = Position.create(line, character) + this._text = text + this.end = getEnd(this.start, this._text) + } + + public get position(): Position { + return this.start + } + + public get line(): number { + return this.start.line + } + + public get text(): string { + return this._text + } + + public get range(): Range { + return Range.create(this.start, this.end) + } + + public get textEdit(): TextEdit { + return { + range: this.range, + newText: this.text + } + } + + public applyChange(change: SurrondChange | TextChange): void { + if (isSurrondChange(change)) { + this.applySurrondChange(change) + } else { + this.applyTextChange(change) + } + } + + public applySurrondChange(change: SurrondChange): void { + let { prepend, append } = change + let len = this._text.length + let text = this._text.substring(prepend[0], len - append[0]) + this._text = `${prepend[1]}${text}${append[1]}` + } + + public applyTextChange(change: TextChange): void { + let { text } = this + let { offset, remove, fromEnd, insert } = change + if (fromEnd) offset = -offset + let pre = text.slice(0, fromEnd && offset == 0 ? text.length : offset) + let after = text.slice(pre.length) + if (remove) after = after.slice(remove) + this._text = `${pre}${insert || ''}${after}` + } + + /** + * Adjust range + */ + public move(delta: number): void { + if (delta != 0) { + let { line, character } = this.start + this.start = Position.create(line, character + delta) + } + this.end = getEnd(this.start, this._text) + } + + public adjustFromEdit(edit: TextEdit): number { + let changed = getChangedPosition(this.start, edit) + if (changed.line || changed.character) { + let { line, character } = this.start + this.start = Position.create(line + changed.line, character + changed.character) + this.end = getEnd(this.start, this._text) + } + return changed.character + } + + public isBefore(range: TextRange): boolean { + let { position } = range + let { line, character } = this.start + return position.line == line && position.character > character + } +} diff --git a/sources_non_forked/coc.nvim/src/cursors/util.ts b/sources_non_forked/coc.nvim/src/cursors/util.ts new file mode 100644 index 00000000..67b10204 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/cursors/util.ts @@ -0,0 +1,110 @@ +'use strict' +import { Range } from 'vscode-languageserver-protocol' +import Document from '../model/document' +import { equals } from '../util/object' +import { getWellformedRange } from '../util/textedit' +import type TextRange from './textRange' + +export interface TextChange { + offset: number + remove: number + insert: string + fromEnd?: boolean +} + +export interface SurrondChange { + /** + * delete count & insert text + */ + prepend: [number, string] + /** + * delete count & insert text + */ + append: [number, string] +} + +/** + * Split to single line ranges + */ +export function splitRange(doc: Document, range: Range): Range[] { + let splited: Range[] = [] + for (let i = range.start.line; i <= range.end.line; i++) { + let curr = doc.getline(i) || '' + let sc = i == range.start.line ? range.start.character : 0 + let ec = i == range.end.line ? range.end.character : curr.length + if (sc == ec) continue + splited.push(Range.create(i, sc, i, ec)) + } + return splited +} + +/** + * Get ranges of visual block + */ +export function getVisualRanges(doc: Document, range: Range): Range[] { + let { start, end } = getWellformedRange(range) + let sc = start.character < end.character ? start.character : end.character + let ec = start.character < end.character ? end.character : start.character + let ranges: Range[] = [] + for (let i = start.line; i <= end.line; i++) { + let line = doc.getline(i) + ranges.push(Range.create(i, sc, i, Math.min(line.length, ec))) + } + return ranges +} + +export function isSurrondChange(change: TextChange | SurrondChange): change is SurrondChange { + return Array.isArray(change['prepend']) && Array.isArray(change['append']) +} + +export function isTextChange(change: TextChange | SurrondChange): change is TextChange { + return typeof change['offset'] === 'number' && typeof change['remove'] === 'number' +} + +export function getDelta(change: TextChange | SurrondChange): number { + if (isSurrondChange(change)) { + return change.append[1].length + change.prepend[1].length - change.append[0] - change.prepend[0] + } + return change.insert.length - change.remove +} + +export function getChange(r: TextRange, range: Range, newText: string): TextChange | SurrondChange { + let text = r.text + if (equals(r.range, range)) { + // surrond + let idx = text.indexOf(newText) + if (idx !== -1) { + let prepend: [number, string] = [idx, ''] + let append: [number, string] = [text.length - newText.length - idx, ''] + return { prepend, append } + } + idx = newText.indexOf(text) + if (idx !== -1) { + let prepend: [number, string] = [0, newText.slice(0, idx)] + let append: [number, string] = [0, newText.slice(- (newText.length - text.length - idx))] + return { prepend, append } + } + } + if (equals(r.range.end, range.end)) { + // end change + let remove = range.end.character - range.start.character + return { offset: remove, remove, insert: newText, fromEnd: true } + } + let remove = range.end.character - range.start.character + let offset = range.start.character - r.range.start.character + return { offset, remove, insert: newText } +} + +export function getBeforeCount(textRange: TextRange, ranges: TextRange[], exclude?: TextRange): number { + let n = 0 + for (let idx = 0; idx < ranges.length; idx++) { + const r = ranges[idx] + if (r.position.line < textRange.position.line || r === exclude) continue + if (r.isBefore(textRange)) { + n++ + continue + } + break + } + return n +} diff --git a/sources_non_forked/coc.nvim/src/diagnostic/buffer.ts b/sources_non_forked/coc.nvim/src/diagnostic/buffer.ts new file mode 100644 index 00000000..e0971121 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/diagnostic/buffer.ts @@ -0,0 +1,436 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import { debounce } from 'debounce' +import { Diagnostic, DiagnosticSeverity, Position, TextEdit } from 'vscode-languageserver-protocol' +import events from '../events' +import { SyncItem } from '../model/bufferSync' +import Document from '../model/document' +import { DidChangeTextDocumentParams, HighlightItem, LocationListItem } from '../types' +import { lineInRange, positionInRange } from '../util/position' +import workspace from '../workspace' +import { adjustDiagnostics, DiagnosticConfig, getHighlightGroup, getLocationListItem, getNameFromSeverity, getSeverityType, sortDiagnostics } from './util' +const logger = require('../util/logger')('diagnostic-buffer') +const signGroup = 'CocDiagnostic' +const NAMESPACE = 'diagnostic' +// higher priority first +const hlGroups = ['CocErrorHighlight', 'CocWarningHighlight', 'CocInfoHighlight', 'CocHintHighlight', 'CocDeprecatedHighlight', 'CocUnusedHighlight'] + +interface DiagnosticInfo { + /** + * current bufnr + */ + bufnr: number + lnum: number + winid: number + locationlist: string +} + +interface SignItem { + name: string + lnum: number + priority?: number +} + +const delay = global.__TEST__ ? 10 : 500 +const aleMethod = global.__TEST__ ? 'MockAleResults' : 'ale#other_source#ShowResults' + +/** + * Manage diagnostics of buffer, including: + * + * - highlights + * - variable + * - signs + * - location list + * - virtual text + */ +export class DiagnosticBuffer implements SyncItem { + private diagnosticsMap: Map> = new Map() + private _disposed = false + private _dirty = false + private _changeTs = 0 + public refreshHighlights: Function & { clear(): void } + constructor( + private readonly nvim: Neovim, + public readonly doc: Document, + private config: DiagnosticConfig, + private onRefresh: (diagnostics: ReadonlyArray) => void + ) { + this.refreshHighlights = debounce(this._refresh.bind(this), delay) + } + + public get dirty(): boolean { + return this._dirty + } + + public get bufnr(): number { + return this.doc.bufnr + } + + public get uri(): string { + return this.doc.uri + } + + public onChange(e: DidChangeTextDocumentParams): void { + let changes = e.contentChanges + if (changes.length > 0) { + this._changeTs = Date.now() + let edit = TextEdit.replace(changes[0].range, changes[0].text) + for (let [collection, diagnostics] of this.diagnosticsMap.entries()) { + if (diagnostics.length) { + let arr = adjustDiagnostics(diagnostics, edit) + this.diagnosticsMap.set(collection, arr) + } + } + } + this.refreshHighlights() + } + + public onTextChange(): void { + this._dirty = true + this.refreshHighlights.clear() + } + + private get displayByAle(): boolean { + return this.config.displayByAle + } + + private clearHighlight(collection: string): void { + this.buffer.clearNamespace(NAMESPACE + collection) + } + + private clearSigns(collection: string): void { + this.buffer.unplaceSign({ group: signGroup + collection }) + } + + private get diagnostics(): Diagnostic[] { + let res: Diagnostic[] = [] + for (let diags of this.diagnosticsMap.values()) { + res.push(...diags) + } + return res + } + + private get buffer(): Buffer { + return this.nvim.createBuffer(this.bufnr) + } + + private refreshAle(collection: string, diagnostics: ReadonlyArray): void { + let aleItems = diagnostics.map(o => { + let range = o.range + return { + text: o.message, + code: o.code, + lnum: range.start.line + 1, + col: range.start.character + 1, + end_lnum: range.end.line + 1, + end_col: range.end.character, + type: getSeverityType(o.severity) + } + }) + this.nvim.call(aleMethod, [this.bufnr, 'coc' + collection, aleItems], true) + } + + /** + * Update diagnostics when diagnostics change on collection. + * + * @param {string} collection + * @param {Diagnostic[]} diagnostics + */ + public async update(collection: string, diagnostics: ReadonlyArray): Promise { + let { diagnosticsMap } = this + let curr = diagnosticsMap.get(collection) || [] + if (!this._dirty && diagnostics.length == 0 && curr.length == 0) return + diagnosticsMap.set(collection, diagnostics) + if (this._dirty || Date.now() - this._changeTs < delay) { + this._dirty = true + return + } + let info = await this.getDiagnosticInfo() + // avoid highlights on invalid state or buffer hidden. + if (this._dirty || !info || info.winid == -1) { + this._dirty = true + return + } + let map: Map> = new Map() + map.set(collection, diagnostics) + this.refresh(map, info) + } + + /** + * Reset all diagnostics of current buffer + */ + public async reset(diagnostics: { [collection: string]: Diagnostic[] }, force?: boolean): Promise { + this._changeTs = Date.now() + let { diagnosticsMap } = this + for (let key of diagnosticsMap.keys()) { + // make sure clear collection when it's empty. + if (diagnostics[key] == null) diagnostics[key] = [] + } + for (let [key, value] of Object.entries(diagnostics)) { + this.diagnosticsMap.set(key, value) + } + let info = await this.getDiagnosticInfo(force) + if (!info) { + this._dirty = true + return + } + this.refresh(this.diagnosticsMap, info) + } + + /** + * Get buffer info needed for refresh. + */ + private async getDiagnosticInfo(force?: boolean): Promise { + let { refreshOnInsertMode } = this.config + let { nvim, bufnr } = this + let checkInsert = !refreshOnInsertMode + if (force) { + checkInsert = false + } else { + let disabledByInsert = events.insertMode && !refreshOnInsertMode + if (disabledByInsert) return undefined + } + return await nvim.call('coc#util#diagnostic_info', [bufnr, checkInsert]) + } + + /** + * Refresh changed diagnostics to UI. + */ + private refresh(diagnosticsMap: Map>, info: DiagnosticInfo): void { + let { nvim, displayByAle } = this + this._dirty = false + if (displayByAle) { + nvim.pauseNotification() + for (let [collection, diagnostics] of diagnosticsMap.entries()) { + this.refreshAle(collection, diagnostics) + } + nvim.resumeNotification(true, true) + } else { + let emptyCollections: string[] = [] + nvim.pauseNotification() + for (let [collection, diagnostics] of diagnosticsMap.entries()) { + if (diagnostics.length == 0) emptyCollections.push(collection) + this.addSigns(collection, diagnostics) + this.updateHighlights(collection, diagnostics) + } + this.showVirtualText(info.lnum, info.bufnr) + this.updateLocationList(info.winid, info.locationlist) + this.setDiagnosticInfo() + nvim.resumeNotification(true, true) + // cleanup unnecessary collections + emptyCollections.forEach(name => { + this.diagnosticsMap.delete(name) + }) + this.onRefresh(this.diagnostics) + } + } + + public updateLocationList(winid: number, title: string): void { + if (!this.config.locationlistUpdate || winid == -1 || title !== 'Diagnostics of coc') return + let items = this.toLocationListItems(this.diagnostics) + this.nvim.call('setloclist', [winid, [], 'r', { title: 'Diagnostics of coc', items }], true) + } + + public toLocationListItems(diagnostics: Diagnostic[]): LocationListItem[] { + let { locationlistLevel } = this.config + let items: LocationListItem[] = [] + let lines = this.doc.textDocument.lines + diagnostics.sort(sortDiagnostics) + for (let diagnostic of diagnostics) { + if (locationlistLevel && diagnostic.severity && diagnostic.severity > locationlistLevel) continue + items.push(getLocationListItem(this.bufnr, diagnostic, lines)) + } + return items + } + + public addSigns(collection: string, diagnostics: ReadonlyArray): void { + let { enableSign, signLevel } = this.config + if (!enableSign) return + let group = signGroup + collection + let signs: SignItem[] = [] + // this.buffer.unplaceSign({ group }) + let signsMap: Map = new Map() + for (let diagnostic of diagnostics) { + let { range, severity } = diagnostic + if (!severity || (signLevel && severity > signLevel)) { + continue + } + let line = range.start.line + let exists = signsMap.get(line) || [] + if (exists.includes(severity)) { + continue + } + exists.push(severity) + signsMap.set(line, exists) + let priority = this.config.signPriority + 4 - severity + signs.push({ name: getNameFromSeverity(severity), lnum: line + 1, priority }) + } + this.nvim.call('coc#ui#update_signs', [this.bufnr, group, signs], true) + } + + public setDiagnosticInfo(): void { + let lnums = [0, 0, 0, 0] + let info = { error: 0, warning: 0, information: 0, hint: 0, lnums } + for (let diagnostics of this.diagnosticsMap.values()) { + for (let diagnostic of diagnostics) { + let lnum = diagnostic.range.start.line + 1 + switch (diagnostic.severity) { + case DiagnosticSeverity.Warning: + info.warning = info.warning + 1 + lnums[1] = lnums[1] ? Math.min(lnums[1], lnum) : lnum + break + case DiagnosticSeverity.Information: + info.information = info.information + 1 + lnums[2] = lnums[2] ? Math.min(lnums[2], lnum) : lnum + break + case DiagnosticSeverity.Hint: + info.hint = info.hint + 1 + lnums[3] = lnums[3] ? Math.min(lnums[3], lnum) : lnum + break + default: + lnums[0] = lnums[0] ? Math.min(lnums[0], lnum) : lnum + info.error = info.error + 1 + } + } + } + let buf = this.nvim.createBuffer(this.bufnr) + buf.setVar('coc_diagnostic_info', info, true) + this.nvim.call('coc#util#do_autocmd', ['CocDiagnosticChange'], true) + } + + public showVirtualText(lnum: number, bufnr?: number): void { + let { config } = this + let { virtualText, virtualTextLevel } = config + if (!virtualText) return + let { virtualTextSrcId, virtualTextPrefix, virtualTextCurrentLineOnly } = this.config + let { diagnostics, buffer } = this + if (virtualTextCurrentLineOnly) { + if (bufnr && this.bufnr != bufnr) return + diagnostics = diagnostics.filter(d => { + let { start, end } = d.range + return start.line <= lnum - 1 && end.line >= lnum - 1 + }) + } + diagnostics.sort(sortDiagnostics) + buffer.clearNamespace(virtualTextSrcId) + for (let i = diagnostics.length - 1; i >= 0; i--) { + let diagnostic = diagnostics[i] + if (virtualTextLevel && diagnostic.severity && diagnostic.severity > virtualTextLevel) { + continue + } + let { line } = diagnostic.range.start + let highlight = getNameFromSeverity(diagnostic.severity) + 'VirtualText' + let msg = diagnostic.message.split(/\n/) + .map((l: string) => l.trim()) + .filter((l: string) => l.length > 0) + .slice(0, this.config.virtualTextLines) + .join(this.config.virtualTextLineSeparator) + if (workspace.has('nvim-0.5.1')) { + let opts: any = { + virt_text: [[virtualTextPrefix + msg, highlight]] + } + if (config.virtualTextAlignRight) { + // opts.virt_text_pos = 'right_align' + } else if (typeof config.virtualTextWinCol === 'number') { + opts.virt_text_win_col = config.virtualTextWinCol + } + buffer.setExtMark(virtualTextSrcId, line, 0, opts) + } else { + void buffer.setVirtualText(virtualTextSrcId, line, [[virtualTextPrefix + msg, highlight]], {}) + } + } + } + + public updateHighlights(collection: string, diagnostics: ReadonlyArray): void { + if (!diagnostics.length) { + this.clearHighlight(collection) + } else { + let items = this.getHighlightItems(diagnostics) + let priority = this.config.highlightPriority + this.buffer.updateHighlights(NAMESPACE + collection, items, { priority }) + } + } + + /** + * Refresh all diagnostics + */ + private async _refresh(): Promise { + if (!this._dirty) return + let info = await this.getDiagnosticInfo() + let noHighlights = !info || info.winid == -1 + if (noHighlights || this.diagnosticsMap.size == 0) return + this.refresh(this.diagnosticsMap, info) + } + + public getHighlightItems(diagnostics: ReadonlyArray): HighlightItem[] { + let doc = workspace.getDocument(this.uri) + if (!doc) return [] + let res: HighlightItem[] = [] + for (let diagnostic of diagnostics.slice(0, this.config.highlighLimit)) { + let hlGroup = getHighlightGroup(diagnostic) + doc.addHighlights(res, hlGroup, diagnostic.range) + } + // needed for iteration performance and since diagnostic highlight may cross lines. + res.sort((a, b) => { + if (a.lnum != b.lnum) return a.lnum - b.lnum + if (a.colStart != b.colStart) return a.colStart - b.colStart + return hlGroups.indexOf(b.hlGroup) - hlGroups.indexOf(a.hlGroup) + }) + return res + } + + /** + * Clear all diagnostics from UI. + */ + public clear(): void { + let { nvim } = this + let collections = Array.from(this.diagnosticsMap.keys()) + this.refreshHighlights.clear() + this.diagnosticsMap.clear() + if (this.displayByAle) { + for (let collection of collections) { + this.nvim.call(aleMethod, [this.bufnr, collection, []], true) + } + } else { + nvim.pauseNotification() + this.buffer.deleteVar('coc_diagnostic_info') + for (let collection of collections) { + this.clearHighlight(collection) + this.clearSigns(collection) + } + if (this.config.virtualText) { + this.buffer.clearNamespace(this.config.virtualTextSrcId) + } + nvim.resumeNotification(true, true) + } + } + + /** + * Get diagnostics at cursor position. + */ + public getDiagnosticsAt(pos: Position, checkCurrentLine: boolean): Diagnostic[] { + let diagnostics: Diagnostic[] = [] + for (let diags of this.diagnosticsMap.values()) { + if (checkCurrentLine) { + diagnostics.push(...diags.filter(o => lineInRange(pos.line, o.range))) + } else { + diagnostics.push(...diags.filter(o => positionInRange(pos, o.range) == 0)) + } + } + diagnostics.sort(sortDiagnostics) + return diagnostics + } + + public async isEnabled(): Promise { + if (this._disposed) return false + let buf = this.nvim.createBuffer(this.bufnr) + let res = await buf.getVar('coc_diagnostic_disable') + return res != 1 + } + + public dispose(): void { + this.clear() + this._disposed = true + this.refreshHighlights.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/diagnostic/collection.ts b/sources_non_forked/coc.nvim/src/diagnostic/collection.ts new file mode 100644 index 00000000..665add60 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/diagnostic/collection.ts @@ -0,0 +1,96 @@ +'use strict' +import { Diagnostic, DiagnosticSeverity, DiagnosticTag, Emitter, Event, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import workspace from '../workspace' +const logger = require('../util/logger')('diagnostic-collection') +const knownTags = [DiagnosticTag.Deprecated, DiagnosticTag.Unnecessary] + +export default class DiagnosticCollection { + private diagnosticsMap: Map = new Map() + private _onDidDiagnosticsChange = new Emitter() + public readonly onDidDiagnosticsChange: Event = this._onDidDiagnosticsChange.event + + constructor( + public readonly name: string, + private onDispose?: () => void) { + } + + public set(uri: string, diagnostics: Diagnostic[] | undefined): void + public set(entries: [string, Diagnostic[] | undefined][]): void + public set(entries: [string, Diagnostic[] | undefined][] | string, diagnostics?: Diagnostic[]): void { + let diagnosticsPerFile: Map = new Map() + if (!Array.isArray(entries)) { + let doc = workspace.getDocument(entries) + let uri = doc ? doc.uri : entries + diagnosticsPerFile.set(uri, diagnostics || []) + } else { + for (let item of entries) { + let [uri, diagnostics] = item + let doc = workspace.getDocument(uri) + uri = doc ? doc.uri : uri + if (diagnostics == null) { + // clear previous diagnostics if entry contains null + diagnostics = [] + } else { + diagnostics = (diagnosticsPerFile.get(uri) || []).concat(diagnostics) + } + diagnosticsPerFile.set(uri, diagnostics) + } + } + for (let item of diagnosticsPerFile) { + let [uri, diagnostics] = item + uri = URI.parse(uri).toString() + diagnostics.forEach(o => { + // should be message for the file, but we need range + o.range = o.range || Range.create(0, 0, 0, 0) + o.message = o.message || '' + o.source = o.source || this.name + if (Array.isArray(o.tags) && o.tags.some(t => knownTags.includes(t))) { + o.severity = DiagnosticSeverity.Hint + } + }) + this.diagnosticsMap.set(uri, diagnostics) + this._onDidDiagnosticsChange.fire(uri) + } + } + + public delete(uri: string): void { + this.diagnosticsMap.delete(uri) + this._onDidDiagnosticsChange.fire(uri) + } + + public clear(): void { + let uris = Array.from(this.diagnosticsMap.keys()) + uris = uris.filter(uri => this.diagnosticsMap.get(uri).length > 0) + this.diagnosticsMap.clear() + for (let uri of uris) { + this._onDidDiagnosticsChange.fire(uri) + } + } + + public forEach(callback: (uri: string, diagnostics: Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void { + for (let uri of this.diagnosticsMap.keys()) { + let diagnostics = this.diagnosticsMap.get(uri) + callback.call(thisArg, uri, diagnostics, this) + } + } + + public entries(): IterableIterator<[string, Diagnostic[]]> { + return this.diagnosticsMap.entries() + } + + public get(uri: string): Diagnostic[] { + let arr = this.diagnosticsMap.get(uri) + return arr == null ? [] : arr.slice() + } + + public has(uri: string): boolean { + return this.diagnosticsMap.has(uri) + } + + public dispose(): void { + this.clear() + if (this.onDispose) this.onDispose() + this._onDidDiagnosticsChange.dispose() + } +} diff --git a/sources_non_forked/coc.nvim/src/diagnostic/manager.ts b/sources_non_forked/coc.nvim/src/diagnostic/manager.ts new file mode 100644 index 00000000..430d3ba8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/diagnostic/manager.ts @@ -0,0 +1,681 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { Diagnostic, DiagnosticSeverity, DiagnosticTag, Disposable, Emitter, Event, Location, Position, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import events from '../events' +import BufferSync from '../model/bufferSync' +import FloatFactory from '../model/floatFactory' +import { ConfigurationChangeEvent, Documentation, ErrorItem } from '../types' +import { disposeAll } from '../util' +import { readFileLines } from '../util/fs' +import { comparePosition, rangeIntersect } from '../util/position' +import { byteIndex } from '../util/string' +import window from '../window' +import workspace from '../workspace' +import { DiagnosticBuffer } from './buffer' +import DiagnosticCollection from './collection' +import { DiagnosticConfig, getSeverityName, severityLevel } from './util' +const logger = require('../util/logger')('diagnostic-manager') + +export interface DiagnosticEventParams { + bufnr: number + uri: string + diagnostics: ReadonlyArray +} + +export interface DiagnosticItem { + file: string + lnum: number + end_lnum: number + col: number + end_col: number + source: string + code: string | number + message: string + severity: string + level: number + location: Location +} + +export class DiagnosticManager implements Disposable { + public config: DiagnosticConfig + private enabled = true + private readonly _onDidRefresh = new Emitter() + public readonly onDidRefresh: Event = this._onDidRefresh.event + private buffers: BufferSync + private floatFactory: FloatFactory + private collections: DiagnosticCollection[] = [] + private disposables: Disposable[] = [] + private clearTimers: () => void | undefined + + public init(): void { + this.setConfiguration() + if (workspace.isNvim) { + // setExtMark throws when namespace not created. + this.nvim.createNamespace('coc-diagnostic-virtualText').then(id => { + this.config.virtualTextSrcId = id + }).logError() + } + workspace.onDidChangeConfiguration(this.setConfiguration, this, this.disposables) + + this.floatFactory = new FloatFactory(this.nvim) + this.buffers = workspace.registerBufferSync(doc => { + if (!this.enabled) return undefined + let buf = new DiagnosticBuffer( + this.nvim, doc, this.config, + diagnostics => { + this._onDidRefresh.fire({ diagnostics, uri: buf.uri, bufnr: buf.bufnr }) + if (buf.bufnr === workspace.bufnr && this.config.messageTarget === 'float') { + void this.getCurrentDiagnostics().then(diagnostics => { + return this.showFloat(diagnostics) + }) + } + }) + let diagnostics = this.getDiagnostics(doc.uri) + // ignore empty diagnostics on first time. + if (Object.keys(diagnostics).length > 0) { + void buf.reset(diagnostics) + } + return buf + }) + + workspace.onDidCloseTextDocument(e => { + for (let collection of this.collections) { + collection.delete(e.uri) + } + }, null, this.disposables) + + let messageTimer: NodeJS.Timeout + events.on('CursorMoved', bufnr => { + if (this.config.enableMessage != 'always') return + if (messageTimer) clearTimeout(messageTimer) + messageTimer = setTimeout(async () => { + let buf = this.buffers.getItem(bufnr) + if (!buf || buf.dirty) return + await this.echoMessage(true) + }, this.config.messageDelay) + }, null, this.disposables) + + let fn = debounce(async (bufnr, cursor) => { + if (!this.config.virtualTextCurrentLineOnly) return + if (events.insertMode && !this.config.refreshOnInsertMode) return + let buf = this.buffers.getItem(bufnr) + if (buf) { + let enabled = await buf.isEnabled() + if (enabled) buf.showVirtualText(cursor[0]) + } + }, global.__TEST__ ? 10 : 100) + this.disposables.push(Disposable.create(() => { + fn.clear() + })) + events.on('CursorMoved', fn, null, this.disposables) + events.on('InsertLeave', async () => { + if (this.config.refreshOnInsertMode || !this.autoRefresh) return + for (let buf of this.buffers.items) { + if (buf.dirty) buf.refreshHighlights() + } + }, null, this.disposables) + events.on('BufWinEnter', (bufnr: number) => { + let buf = this.buffers.getItem(bufnr) + if (buf && buf.dirty) buf.refreshHighlights() + }, null, this.disposables) + this.clearTimers = () => { + if (messageTimer) clearTimeout(messageTimer) + messageTimer = undefined + fn.clear() + } + events.on('InsertEnter', this.clearTimers, this, this.disposables) + let errorItems = workspace.configurations.errorItems + this.setConfigurationErrors(errorItems) + workspace.configurations.onError(items => { + this.setConfigurationErrors(items) + }, null, this.disposables) + } + + private defineSigns(): void { + let { nvim } = this + let { enableHighlightLineNumber, enableSign } = this.config + if (!enableSign) return + nvim.pauseNotification() + for (let kind of ['Error', 'Warning', 'Info', 'Hint']) { + let signText = this.config[kind.toLowerCase() + 'Sign'] + let cmd = `sign define Coc${kind} linehl=Coc${kind}Line` + if (signText) cmd += ` texthl=Coc${kind}Sign text=${signText}` + if (enableHighlightLineNumber) cmd += ` numhl=Coc${kind}Sign` + nvim.command(cmd, true) + } + nvim.resumeNotification(false, true) + } + + /** + * Fill location list with diagnostics + */ + public async setLocationlist(bufnr: number): Promise { + if (!this.enabled) throw new Error(`Diagnostic not enabled.`) + let buf = this.buffers.getItem(bufnr) + if (!buf) throw new Error(`buffer ${bufnr} not attached.`) + let diagnostics: Diagnostic[] = [] + for (let diags of Object.values(this.getDiagnostics(buf.uri))) { + diagnostics.push(...diags) + } + let items = buf.toLocationListItems(diagnostics) + let curr = await this.nvim.call('getloclist', [0, { title: 1 }]) as { title?: string } + let action = curr.title && curr.title.indexOf('Diagnostics of coc') != -1 ? 'r' : ' ' + await this.nvim.call('setloclist', [0, [], action, { title: 'Diagnostics of coc', items }]) + } + + public setConfigurationErrors(errorItems?: ErrorItem[]): void { + let collection = this.create('config') + if (errorItems?.length) { + let fsPath = URI.parse(errorItems[0].location.uri).fsPath + void window.showErrorMessage(`Error detected for config file ${fsPath}, please check diagnostics list.`) + let entries: Map = new Map() + for (let item of errorItems) { + let { uri } = item.location + let diagnostics: Diagnostic[] = entries.get(uri) || [] + diagnostics.push(Diagnostic.create(item.location.range, item.message, DiagnosticSeverity.Error)) + entries.set(uri, diagnostics) + } + collection.set(Array.from(entries)) + } else { + collection.clear() + } + } + + /** + * Create collection by name + */ + public create(name: string): DiagnosticCollection { + let collection = this.getCollectionByName(name) + if (collection) return collection + collection = new DiagnosticCollection(name, () => { + let idx = this.collections.findIndex(o => o == collection) + if (idx !== -1) this.collections.splice(idx, 1) + }) + this.collections.push(collection) + collection.onDidDiagnosticsChange(uri => { + let buf = this.buffers.getItem(uri) + if (!this.autoRefresh || !buf) return + void buf.update(name, this.getDiagnosticsByCollection(uri, collection)) + }) + return collection + } + + /** + * Get diagnostics ranges from document + */ + public getSortedRanges(uri: string, severity?: string): Range[] { + let collections = this.getCollections(uri) + let res: Range[] = [] + let level = severity ? severityLevel(severity) : 0 + for (let collection of collections) { + let diagnostics = collection.get(uri) + if (level) { + diagnostics = diagnostics.filter(o => o.severity == level) + } else { + let minLevel = this.config.level + if (minLevel && minLevel < DiagnosticSeverity.Hint) { + diagnostics = diagnostics.filter(o => { + return o.severity && o.severity > minLevel ? false : true + }) + } + } + let ranges = diagnostics.map(o => o.range) + res.push(...ranges) + } + res.sort((a, b) => { + if (a.start.line != b.start.line) { + return a.start.line - b.start.line + } + return a.start.character - b.start.character + }) + return res + } + + /** + * Get readonly diagnostics for a buffer + */ + public getDiagnostics(uri: string): { [collection: string]: Diagnostic[] } { + let res: { [collection: string]: Diagnostic[] } = {} + let collections = this.getCollections(uri) + for (let collection of collections) { + if (!collection) continue + res[collection.name] = this.getDiagnosticsByCollection(uri, collection) + } + return res + } + + /** + * Get filtered diagnostics by collection. + */ + public getDiagnosticsByCollection(uri: string, collection: DiagnosticCollection): Diagnostic[] { + let { level, showUnused, showDeprecated } = this.config + let items = collection.get(uri) || [] + if (items.length) { + items = items.filter(d => { + if (level && d.severity && d.severity > level) { + return false + } + if (!showUnused && d.tags?.includes(DiagnosticTag.Unnecessary)) { + return false + } + if (!showDeprecated && d.tags?.includes(DiagnosticTag.Deprecated)) { + return false + } + return true + }) + items.sort((a, b) => { + return comparePosition(a.range.start, b.range.start) + }) + } + return items + } + + public getDiagnosticsInRange(document: TextDocument, range: Range): Diagnostic[] { + let collections = this.getCollections(document.uri) + let res: Diagnostic[] = [] + for (let collection of collections) { + let items = collection.get(document.uri) + if (!items) continue + for (let item of items) { + if (rangeIntersect(item.range, range)) { + res.push(item) + } + } + } + return res + } + + /** + * Show diagnostics under curosr in preview window + */ + public async preview(): Promise { + let diagnostics = await this.getCurrentDiagnostics() + if (diagnostics.length == 0) { + this.nvim.command('pclose', true) + return + } + let lines: string[] = [] + for (let diagnostic of diagnostics) { + let { source, code, severity, message } = diagnostic + let s = getSeverityName(severity)[0] + lines.push(`[${source}${code ? ' ' + code : ''}] [${s}]`) + lines.push(...message.split(/\r?\n/)) + lines.push('') + } + this.nvim.call('coc#ui#preview_info', [lines, 'txt'], true) + } + + /** + * Jump to previous diagnostic position + */ + public async jumpPrevious(severity?: string): Promise { + let buffer = await this.nvim.buffer + let item = this.buffers.getItem(buffer.id) + if (!item) return + let curpos = await window.getCursorPosition() + let ranges = this.getSortedRanges(item.uri, severity) + let pos: Position + for (let i = ranges.length - 1; i >= 0; i--) { + let end = ranges[i].end + if (comparePosition(end, curpos) < 0) { + pos = ranges[i].start + break + } else if (i == 0) { + let wrapscan = await this.nvim.getOption('wrapscan') + if (wrapscan) pos = ranges[ranges.length - 1].start + } + } + if (pos) { + await window.moveTo(pos) + if (this.config.enableMessage == 'never') return + await this.echoMessage(false) + } + } + + /** + * Jump to next diagnostic position + */ + public async jumpNext(severity?: string): Promise { + let buffer = await this.nvim.buffer + let item = this.buffers.getItem(buffer.id) + if (!item) return + let curpos = await window.getCursorPosition() + let ranges = this.getSortedRanges(item.uri, severity) + let pos: Position + for (let i = 0; i <= ranges.length - 1; i++) { + let start = ranges[i].start + if (comparePosition(start, curpos) > 0) { + pos = ranges[i].start + break + } else if (i == ranges.length - 1) { + let wrapscan = await this.nvim.getOption('wrapscan') + if (wrapscan) pos = ranges[0].start + } + } + if (pos) { + await window.moveTo(pos) + if (this.config.enableMessage == 'never') return + await this.echoMessage(false) + } + } + + /** + * Get all sorted diagnostics + */ + public async getDiagnosticList(): Promise { + let res: DiagnosticItem[] = [] + const { level } = this.config + for (let collection of this.collections) { + for (let [uri, diagnostics] of collection.entries()) { + if (diagnostics.length == 0) continue + let u = URI.parse(uri) + let doc = workspace.getDocument(uri) + let lines = doc && doc.attached ? doc.textDocument.lines : undefined + if (!lines && u.scheme === 'file') { + try { + const max = diagnostics.reduce((p, c) => { + return Math.max(c.range.end.line, p) + }, 0) + lines = await readFileLines(u.fsPath, 0, max) + } catch (e) {} + } + for (let diagnostic of diagnostics) { + if (diagnostic.severity && diagnostic.severity > level) continue + let { start, end } = diagnostic.range + let o: DiagnosticItem = { + file: u.fsPath, + lnum: start.line + 1, + end_lnum: end.line + 1, + col: Array.isArray(lines) ? byteIndex(lines[start.line] ?? '', start.character) + 1 : start.character + 1, + end_col: Array.isArray(lines) ? byteIndex(lines[end.line] ?? '', end.character) + 1 : end.character + 1, + code: diagnostic.code, + source: diagnostic.source || collection.name, + message: diagnostic.message, + severity: getSeverityName(diagnostic.severity), + level: diagnostic.severity || 0, + location: Location.create(uri, diagnostic.range) + } + res.push(o) + } + } + } + res.sort((a, b) => { + if (a.level !== b.level) { + return a.level - b.level + } + if (a.file !== b.file) { + return a.file > b.file ? 1 : -1 + } else { + if (a.lnum != b.lnum) { + return a.lnum - b.lnum + } + return a.col - b.col + } + }) + return res + } + + private getDiagnosticsAt(bufnr: number, cursor: [number, number], atEnd = false, lastline = false): Diagnostic[] { + let buffer = this.buffers.getItem(bufnr) + if (!buffer) return [] + let pos = Position.create(cursor[0], cursor[1]) + let res = buffer.getDiagnosticsAt(pos, this.config.checkCurrentLine) + if (this.config.checkCurrentLine || res.length) return res + // check next character when cursor at end of line. + if (atEnd) { + pos = Position.create(cursor[0], cursor[1] + 1) + res = buffer.getDiagnosticsAt(pos, false) + if (res.length) return res + } + // check next line when cursor at the beginning of last line. + if (lastline && cursor[1] == 0) { + pos = Position.create(cursor[0] + 1, 0) + res = buffer.getDiagnosticsAt(pos, false) + } + return res + } + + public async getCurrentDiagnostics(): Promise { + let [bufnr, cursor, eol, lastline] = await this.nvim.eval(`[bufnr("%"),coc#cursor#position(),col('.')==col('$')-1,line('.')==line('$')]`) as [number, [number, number], number, number] + return this.getDiagnosticsAt(bufnr, cursor, eol == 1, lastline == 1) + } + + /** + * Echo diagnostic message under cursor. + */ + public async echoMessage(truncate = false): Promise { + const config = this.config + if (!this.enabled || config.displayByAle) return + let useFloat = config.messageTarget == 'float' + let diagnostics = await this.getCurrentDiagnostics() + if (config.messageLevel) { + diagnostics = diagnostics.filter(diagnostic => { + return diagnostic.severity && diagnostic.severity <= config.messageLevel + }) + } + if (useFloat) { + await this.showFloat(diagnostics) + } else { + if (truncate && events.insertMode) return + const lines = [] + diagnostics.forEach(diagnostic => { + let { source, code, severity, message } = diagnostic + let s = getSeverityName(severity)[0] + const codeStr = code ? ' ' + code : '' + const str = config.format.replace('%source', source).replace('%code', codeStr).replace('%severity', s).split('%message').join(message) + lines.push(str) + }) + if (lines.length) { + await this.nvim.command('echo ""') + await window.echoLines(lines, truncate) + } + } + } + + private async showFloat(diagnostics: Diagnostic[]): Promise { + if (this.config.messageTarget !== 'float') return + let { config } = this + if (diagnostics.length == 0) { + this.floatFactory.close() + return + } + if (events.insertMode) return + let ft = '' + let docs: Documentation[] = [] + if (Object.keys(config.filetypeMap).length > 0) { + let doc = workspace.getDocument(workspace.bufnr) + let filetype = doc ? doc.filetype : '' + const defaultFiletype = config.filetypeMap['default'] || '' + ft = config.filetypeMap[filetype] || (defaultFiletype == 'bufferType' ? filetype : defaultFiletype) + } + diagnostics.forEach(diagnostic => { + let { source, code, severity, message } = diagnostic + let s = getSeverityName(severity)[0] + const codeStr = code ? ' ' + code : '' + const str = config.format.replace('%source', source).replace('%code', codeStr).replace('%severity', s).split('%message').join(message) + let filetype = 'Error' + if (ft === '') { + switch (severity) { + case DiagnosticSeverity.Hint: + filetype = 'Hint' + break + case DiagnosticSeverity.Warning: + filetype = 'Warning' + break + case DiagnosticSeverity.Information: + filetype = 'Info' + break + } + } else { + filetype = ft + } + docs.push({ filetype, content: str }) + if (diagnostic.codeDescription?.href) { + docs.push({ filetype: 'txt', content: diagnostic.codeDescription.href }) + } + }) + let floatConfig = this.floatFactory.applyFloatConfig({ modes: ['n'], maxWidth: 80 }, this.config.floatConfig) + logger.debug('floatConfig:', floatConfig) + await this.floatFactory.show(docs, floatConfig) + } + + public async jumpRelated(): Promise { + let diagnostics = await this.getCurrentDiagnostics() + let diagnostic = diagnostics.find(o => o.relatedInformation != null) + let locations = diagnostic ? diagnostic.relatedInformation.map(o => o.location) : [] + if (locations.length == 1) { + await workspace.jumpTo(locations[0].uri, locations[0].range.start) + } else if (locations.length > 1) { + await workspace.showLocations(locations) + } else { + void window.showWarningMessage('No related information found.') + } + } + + public reset(): void { + if (this.clearTimers) { + this.clearTimers() + } + this.buffers.reset() + for (let collection of this.collections) { + collection.dispose() + } + this.collections = [] + } + + public dispose(): void { + if (this.clearTimers) { + this.clearTimers() + } + this.buffers.dispose() + for (let collection of this.collections) { + collection.dispose() + } + this.floatFactory?.close() + this.collections = [] + disposeAll(this.disposables) + } + + private get nvim(): Neovim { + return workspace.nvim + } + + private setConfiguration(event?: ConfigurationChangeEvent): void { + if (event && !event.affectsConfiguration('diagnostic')) return + let config = workspace.getConfiguration('diagnostic') + let messageTarget = config.get('messageTarget', 'float') + if (messageTarget == 'float' && !workspace.env.floating && !workspace.env.textprop) { + messageTarget = 'echo' + } + let enableHighlightLineNumber = config.get('enableHighlightLineNumber', true) + if (!workspace.isNvim) enableHighlightLineNumber = false + this.config = Object.assign(this.config || {}, { + floatConfig: config.get('floatConfig', {}), + messageTarget, + enableHighlightLineNumber, + highlighLimit: config.get('highlighLimit', 1000), + highlightPriority: config.get('highlightPriority'), + autoRefresh: config.get('autoRefresh', true), + checkCurrentLine: config.get('checkCurrentLine', false), + enableSign: workspace.env.sign && config.get('enableSign', true), + locationlistUpdate: config.get('locationlistUpdate', true), + enableMessage: config.get('enableMessage', 'always'), + messageDelay: config.get('messageDelay', 200), + virtualText: config.get('virtualText', false) && this.nvim.hasFunction('nvim_buf_set_virtual_text'), + virtualTextAlignRight: workspace.has('nvim-0.5.1') && config.get('virtualTextAlignRight', false), + virtualTextWinCol: workspace.has('nvim-0.5.1') ? config.get('virtualTextWinCol', null) : null, + virtualTextCurrentLineOnly: config.get('virtualTextCurrentLineOnly', true), + virtualTextPrefix: config.get('virtualTextPrefix', " "), + virtualTextLineSeparator: config.get('virtualTextLineSeparator', " \\ "), + virtualTextLines: config.get('virtualTextLines', 3), + displayByAle: config.get('displayByAle', false), + level: severityLevel(config.get('level', 'hint')), + locationlistLevel: severityLevel(config.get('locationlistLevel')), + signLevel: severityLevel(config.get('signLevel')), + virtualTextLevel: severityLevel(config.get('virtualTextLevel')), + messageLevel: severityLevel(config.get('messageLevel')), + signPriority: config.get('signPriority', 10), + errorSign: config.get('errorSign', '>>'), + warningSign: config.get('warningSign', '>>'), + infoSign: config.get('infoSign', '>>'), + hintSign: config.get('hintSign', '>>'), + refreshOnInsertMode: config.get('refreshOnInsertMode', false), + filetypeMap: config.get('filetypeMap', {}), + showUnused: config.get('showUnused', true), + showDeprecated: config.get('showDeprecated', true), + format: config.get('format', '[%source%code] [%severity] %message'), + }) + this.enabled = config.get('enable', true) + this.defineSigns() + } + + public getCollectionByName(name: string): DiagnosticCollection { + return this.collections.find(o => o.name == name) + } + + private getCollections(uri: string): DiagnosticCollection[] { + return this.collections.filter(c => c.has(uri)) + } + + public toggleDiagnostic(enable?: number): void { + let enabled = enable == undefined ? this.enabled : enable == 0 + this.enabled = !enabled + for (let buf of this.buffers.items) { + if (this.enabled) { + void this.refreshBuffer(buf.uri) + } else { + buf.clear() + } + } + } + + public async toggleDiagnosticBuffer(bufnr?: number, enable?: number): Promise { + if (!this.enabled) return + bufnr = bufnr || workspace.bufnr + let buf = this.buffers.getItem(bufnr) + if (buf) { + let isEnabled = enable == undefined ? await buf.isEnabled() : enable == 0 + await this.nvim.call('setbufvar', [bufnr, 'coc_diagnostic_disable', isEnabled ? 1 : 0]) + if (isEnabled) { + buf.clear() + } else { + void this.refreshBuffer(bufnr) + } + } + } + + private get autoRefresh(): boolean { + return this.enabled && this.config.autoRefresh + } + + /** + * Refresh diagnostics by uri or bufnr + */ + public async refreshBuffer(uri: string | number, force?: boolean): Promise { + let buf = this.buffers.getItem(uri) + if (!buf) return false + await buf.reset(this.getDiagnostics(buf.uri), force) + return true + } + + /** + * Force diagnostics refresh. + */ + public refresh(bufnr?: number): void { + let items: Iterable + if (!bufnr) { + items = this.buffers.items + } else { + let item = this.buffers.getItem(bufnr) + items = item ? [item] : [] + } + for (let item of items) { + void this.refreshBuffer(item.uri, true) + } + } +} + +export default new DiagnosticManager() diff --git a/sources_non_forked/coc.nvim/src/diagnostic/util.ts b/sources_non_forked/coc.nvim/src/diagnostic/util.ts new file mode 100644 index 00000000..60e938e3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/diagnostic/util.ts @@ -0,0 +1,176 @@ +'use strict' +import { DiagnosticSeverity, Diagnostic, Range, DiagnosticTag, TextEdit } from 'vscode-languageserver-protocol' +import { FloatConfig, LocationListItem } from '../types' +import { comparePosition, rangeOverlap } from '../util/position' +import { byteIndex } from '../util/string' +import { getPosition } from '../util/textedit' + +export enum DiagnosticHighlight { + Error = 'CocErrorHighlight', + Warning = 'CocWarningHighlight', + Information = 'CocInfoHighlight', + Hint = 'CocHintHighlight', + Deprecated = 'CocDeprecatedHighlight', + Unused = 'CocUnusedHighlight' +} + +export interface DiagnosticConfig { + highlighLimit: number + highlightPriority: number + autoRefresh: boolean + enableSign: boolean + locationlistUpdate: boolean + enableHighlightLineNumber: boolean + checkCurrentLine: boolean + enableMessage: string + displayByAle: boolean + signPriority: number + errorSign: string + warningSign: string + infoSign: string + hintSign: string + level: number + locationlistLevel: number | undefined + signLevel: number | undefined + messageLevel: number | undefined + messageTarget: string + messageDelay: number + refreshOnInsertMode: boolean + virtualText: boolean + virtualTextLevel: number | undefined + virtualTextAlignRight: boolean + virtualTextWinCol: number | null + virtualTextCurrentLineOnly: boolean + virtualTextSrcId?: number + virtualTextPrefix: string + virtualTextLines: number + virtualTextLineSeparator: string + filetypeMap: object + showUnused?: boolean + showDeprecated?: boolean + format?: string + floatConfig: FloatConfig +} + +export function getSeverityName(severity: DiagnosticSeverity): string { + switch (severity) { + case DiagnosticSeverity.Warning: + return 'Warning' + case DiagnosticSeverity.Information: + return 'Information' + case DiagnosticSeverity.Hint: + return 'Hint' + default: + return 'Error' + } +} + +export function getSeverityType(severity: DiagnosticSeverity): string { + switch (severity) { + case DiagnosticSeverity.Warning: + return 'W' + case DiagnosticSeverity.Information: + return 'I' + case DiagnosticSeverity.Hint: + return 'I' + default: + return 'E' + } +} + +export function severityLevel(level: string | null | undefined): number | undefined { + if (level == null) return undefined + switch (level) { + case 'hint': + return DiagnosticSeverity.Hint + case 'information': + return DiagnosticSeverity.Information + case 'warning': + return DiagnosticSeverity.Warning + case 'error': + return DiagnosticSeverity.Error + default: + return DiagnosticSeverity.Hint + } +} + +export function getNameFromSeverity(severity: DiagnosticSeverity): string { + switch (severity) { + case DiagnosticSeverity.Error: + return 'CocError' + case DiagnosticSeverity.Warning: + return 'CocWarning' + case DiagnosticSeverity.Information: + return 'CocInfo' + case DiagnosticSeverity.Hint: + return 'CocHint' + default: + return 'CocError' + } +} + +export function getLocationListItem(bufnr: number, diagnostic: Diagnostic, lines?: ReadonlyArray): LocationListItem { + let { start, end } = diagnostic.range + let owner = diagnostic.source || 'coc.nvim' + let msg = diagnostic.message.split('\n')[0] + let type = getSeverityName(diagnostic.severity).slice(0, 1).toUpperCase() + return { + bufnr, + lnum: start.line + 1, + end_lnum: end.line + 1, + col: Array.isArray(lines) ? byteIndex(lines[start.line] ?? '', start.character) + 1 : start.character + 1, + end_col: Array.isArray(lines) ? byteIndex(lines[end.line] ?? '', end.character) + 1 : end.character + 1, + text: `[${owner}${diagnostic.code ? ' ' + diagnostic.code : ''}] ${msg} [${type}]`, + type + } +} + +/** + * Sort by severity and position + */ +export function sortDiagnostics(a: Diagnostic, b: Diagnostic): number { + if ((a.severity || 1) != (b.severity || 1)) { + return (a.severity || 1) - (b.severity || 1) + } + let d = comparePosition(a.range.start, b.range.start) + if (d != 0) return d + return a.source > b.source ? 1 : -1 +} + +export function getHighlightGroup(diagnostic: Diagnostic): DiagnosticHighlight { + let tags = diagnostic.tags || [] + if (tags.includes(DiagnosticTag.Deprecated)) { + return DiagnosticHighlight.Deprecated + } + if (tags.includes(DiagnosticTag.Unnecessary)) { + return DiagnosticHighlight.Unused + } + switch (diagnostic.severity) { + case DiagnosticSeverity.Warning: + return DiagnosticHighlight.Warning + case DiagnosticSeverity.Information: + return DiagnosticHighlight.Information + case DiagnosticSeverity.Hint: + return DiagnosticHighlight.Hint + default: + return DiagnosticHighlight.Error + } +} + +export function adjustDiagnostics(diagnostics: ReadonlyArray, edit: TextEdit): ReadonlyArray { + let res: Diagnostic[] = [] + let { range } = edit + for (let diag of diagnostics) { + let r = diag.range + if (rangeOverlap(range, r)) continue + if (comparePosition(r.start, range.end) > 0) { + let s = getPosition(r.start, edit) + let e = getPosition(r.end, edit) + if (s.line >= 0 && s.character >= 0 && e.line >= 0 && e.character >= 0) { + diag.range = Range.create(s, e) + } + } + res.push(diag) + } + return res +} diff --git a/sources_non_forked/coc.nvim/src/events.ts b/sources_non_forked/coc.nvim/src/events.ts new file mode 100644 index 00000000..821cb30a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/events.ts @@ -0,0 +1,285 @@ +'use strict' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import { VimCompleteItem, CompleteDoneItem } from './types' +import { disposeAll } from './util' +import { equals } from './util/object' +import { byteSlice } from './util/string' +const logger = require('./util/logger')('events') + +export type Result = void | Promise + +export interface PopupChangeEvent { + readonly completed_item: VimCompleteItem | {} + readonly height: number + readonly width: number + readonly row: number + readonly col: number + readonly size: number + readonly scrollbar: boolean +} + +export interface InsertChange { + readonly lnum: number + readonly col: number + readonly line: string + readonly changedtick: number + pre: string + /** + * Insert character that cause change of this time. + */ + insertChar?: string +} + +export type BufEvents = 'BufHidden' | 'BufEnter' + | 'InsertLeave' | 'TermOpen' | 'InsertEnter' | 'BufCreate' | 'BufUnload' + | 'BufDetach' | 'Enter' | 'LinesChanged' + +export type EmptyEvents = 'FocusGained' | 'FocusLost' | 'InsertSnippet' | 'ready' | 'VimLeavePre' + +export type InsertChangeEvents = 'TextChangedP' | 'TextChangedI' + +export type TaskEvents = 'TaskExit' | 'TaskStderr' | 'TaskStdout' + +export type WindowEvents = 'WinLeave' | 'WinEnter' | 'WinClosed' | 'WinScrolled' + +export type TabEvents = 'TabNew' | 'TabClosed' + +export type AllEvents = BufEvents | EmptyEvents | CursorEvents | TaskEvents | WindowEvents | TabEvents + | InsertChangeEvents | 'CompleteDone' | 'TextChanged' | 'MenuPopupChanged' | 'BufWritePost' | 'BufWritePre' + | 'InsertCharPre' | 'FileType' | 'BufWinEnter' | 'BufWinLeave' | 'VimResized' | 'TermExit' + | 'DirChanged' | 'OptionSet' | 'Command' | 'BufReadCmd' | 'GlobalChange' | 'InputChar' + | 'WinLeave' | 'MenuInput' | 'PromptInsert' | 'FloatBtnClick' | 'InsertSnippet' | 'TextInsert' + | 'PromptKeyPress' + +export type CursorEvents = 'CursorMoved' | 'CursorMovedI' | 'CursorHold' | 'CursorHoldI' + +export type OptionValue = string | number | boolean + +export interface CursorPosition { + readonly bufnr: number + readonly lnum: number + readonly col: number + readonly insert: boolean +} + +export interface LatestInsert { + readonly bufnr: number + readonly character: string + readonly timestamp: number +} + +class Events { + + private handlers: Map Promise)[]> = new Map() + private _cursor: CursorPosition + private _bufnr: number + // bufnr & character + private _recentInserts: [number, string][] = [] + private _lastChange = 0 + private _insertMode = false + private _pumAlignTop = false + private _pumVisible = false + public completing = false + + public get cursor(): CursorPosition { + return this._cursor + } + + public get bufnr(): number { + return this._bufnr + } + + public get pumvisible(): boolean { + return this._pumVisible + } + + public get pumAlignTop(): boolean { + return this._pumAlignTop + } + + public get insertMode(): boolean { + return this._insertMode + } + + public get lastChangeTs(): number { + return this._lastChange + } + + /** + * Resolved when first event fired or timeout + */ + public race(events: AllEvents[], token?: number | CancellationToken): Promise<{ name: AllEvents, args: unknown[] } | undefined> { + let disposables: Disposable[] = [] + return new Promise(resolve => { + if (typeof token === 'number') { + let timer = setTimeout(() => { + disposeAll(disposables) + resolve(undefined) + }, token) + disposables.push(Disposable.create(() => { + clearTimeout(timer) + })) + } else if (CancellationToken.is(token)) { + token.onCancellationRequested(() => { + disposeAll(disposables) + resolve(undefined) + }, null, disposables) + } + events.forEach(ev => { + this.on(ev, (...args) => { + disposeAll(disposables) + resolve({ name: ev, args }) + }, null, disposables) + }) + }) + } + + public async fire(event: string, args: any[]): Promise { + let cbs = this.handlers.get(event) + if (event == 'InsertEnter') { + this._insertMode = true + } else if (event == 'InsertLeave') { + this._insertMode = false + this._pumVisible = false + this._recentInserts = [] + } else if (event == 'CursorHoldI' || event == 'CursorMovedI') { + this._bufnr = args[0] + if (!this._insertMode) { + this._insertMode = true + void this.fire('InsertEnter', [args[0]]) + } + } else if (event == 'CursorHold' || event == 'CursorMoved') { + this._bufnr = args[0] + if (this._insertMode) { + this._insertMode = false + void this.fire('InsertLeave', [args[0]]) + } + } else if (event == 'MenuPopupChanged') { + this._pumVisible = true + this._pumAlignTop = args[1] > args[0].row + } else if (event == 'CompleteDone') { + this._pumVisible = false + } else if (event == 'InsertCharPre') { + this._recentInserts.push([args[1], args[0]]) + } else if (event == 'TextChanged') { + this._lastChange = Date.now() + } else if (event == 'BufEnter') { + this._bufnr = args[0] + } else if (event == 'TextChangedI' || event == 'TextChangedP') { + let arr = this._recentInserts.filter(o => o[0] == args[0]) + this._bufnr = args[0] + this._recentInserts = [] + this._pumVisible = event == 'TextChangedP' + this._lastChange = Date.now() + let info: InsertChange = args[1] + let pre = byteSlice(info.line ?? '', 0, info.col - 1) + info.pre = pre + // fix cursor since vim not send CursorMovedI event + this._cursor = Object.freeze({ + bufnr: args[0], + lnum: info.lnum, + col: info.col, + insert: true + }) + if (arr.length && pre.length) { + let character = pre.slice(-1) + if (arr.findIndex(o => o[1] == character) !== -1) { + info.insertChar = character + // make it fires after TextChangedI & TextChangedP + process.nextTick(() => { + void this.fire('TextInsert', [...args, character]) + }) + } + } + } + if (event == 'CursorMoved' || event == 'CursorMovedI') { + args.push(this._recentInserts.length > 0) + let cursor = { + bufnr: args[0], + lnum: args[1][0], + col: args[1][1], + insert: event == 'CursorMovedI' + } + // Avoid CursorMoved event when it's not moved at all + if (this._cursor && equals(this._cursor, cursor)) return + this._cursor = Object.freeze(cursor) + } + if (cbs) { + try { + args.forEach(val => { + if (typeof val === 'object') Object.freeze(val) + }) + // need slice since the array might changed when execute fn + await Promise.all(cbs.slice().map(fn => fn(args))) + } catch (e) { + if (e instanceof Error && e.message?.includes('transport disconnected')) return + logger.error(`Error on event: ${event}`, e instanceof Error ? e.stack : e) + } + } + } + + public on(event: BufEvents, handler: (bufnr: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: CursorEvents, handler: (bufnr: number, cursor: [number, number]) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: InsertChangeEvents, handler: (bufnr: number, info: InsertChange) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: WindowEvents, handler: (winid: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: TabEvents, handler: (tabnr: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'TextInsert', handler: (bufnr: number, info: InsertChange, character: string) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'FloatBtnClick', handler: (bufnr: number, index: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'PromptKeyPress', handler: (bufnr: number, key: string) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'BufWritePre', handler: (bufnr: number, bufname: string, changedtick: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'TextChanged' | 'BufWritePost', handler: (bufnr: number, changedtick: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'TaskExit', handler: (id: string, code: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'TaskStderr' | 'TaskStdout', handler: (id: string, lines: string[]) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'BufReadCmd', handler: (scheme: string, fullpath: string) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'VimResized', handler: (columns: number, lines: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'Command', handler: (name: string) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'MenuPopupChanged', handler: (event: PopupChangeEvent, cursorline: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'CompleteDone', handler: (item: CompleteDoneItem) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'InsertCharPre', handler: (character: string, bufnr: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'FileType', handler: (filetype: string, bufnr: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'BufWinEnter' | 'BufWinLeave', handler: (bufnr: number, winid: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'TermExit', handler: (bufnr: number, status: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'DirChanged', handler: (cwd: string) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'OptionSet' | 'GlobalChange', handler: (option: string, oldVal: OptionValue, newVal: OptionValue) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'InputChar', handler: (session: string, character: string, mode: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: 'PromptInsert', handler: (value: string, bufnr: number) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: EmptyEvents, handler: () => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: AllEvents | AllEvents[], handler: (...args: unknown[]) => Result, thisArg?: any, disposables?: Disposable[]): Disposable + public on(event: AllEvents[] | AllEvents, handler: (...args: any[]) => Result, thisArg?: any, disposables?: Disposable[]): Disposable { + if (Array.isArray(event)) { + let arr = disposables || [] + for (let ev of event) { + this.on(ev as any, handler, thisArg, arr) + } + return Disposable.create(() => { + disposeAll(arr) + }) + } else { + let arr = this.handlers.get(event) || [] + let wrappedhandler = args => new Promise((resolve, reject) => { + try { + Promise.resolve(handler.apply(thisArg ?? null, args)).then(() => { + resolve(undefined) + }, e => { + reject(e) + }) + } catch (e) { + reject(e) + } + }) + arr.push(wrappedhandler) + this.handlers.set(event, arr) + let disposable = Disposable.create(() => { + let idx = arr.indexOf(wrappedhandler) + if (idx !== -1) { + arr.splice(idx, 1) + } + }) + if (Array.isArray(disposables)) { + disposables.push(disposable) + } + return disposable + } + } +} +export default new Events() diff --git a/sources_non_forked/coc.nvim/src/extensions.ts b/sources_non_forked/coc.nvim/src/extensions.ts new file mode 100644 index 00000000..eb7ef225 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/extensions.ts @@ -0,0 +1,1110 @@ +'use strict' +import { debounce } from 'debounce' +import fs from 'fs-extra' +import isuri from 'isuri' +import { parse, ParseError } from 'jsonc-parser' +import path from 'path' +import semver from 'semver' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import which from 'which' +import commandManager from './commands' +import Watchman from './core/watchman' +import events from './events' +import DB from './model/db' +import FloatFactory from './model/floatFactory' +import InstallBuffer from './model/installBuffer' +import { createInstallerFactory } from './model/installer' +import Memos from './model/memos' +import { OutputChannel } from './types' +import { concurrent, disposeAll, wait, watchFile } from './util' +import { distinct, splitArray } from './util/array' +import './util/extensions' +import { createExtension, ExtensionExport } from './util/factory' +import { checkFolder, readFile, statAsync } from './util/fs' +import { objectLiteral } from './util/is' +import window from './window' +import workspace from './workspace' + +const createLogger = require('./util/logger') +const logger = createLogger('extensions') + +export type API = { [index: string]: any } | void | null | undefined + +export type ExtensionState = 'disabled' | 'loaded' | 'activated' | 'unknown' + +export enum ExtensionType { + Global, + Local, + SingleFile, + Internal +} + +export interface PropertyScheme { + type: string + default: any + description: string + enum?: string[] + items?: any + [key: string]: any +} + +export interface Extension { + readonly id: string + readonly extensionPath: string + readonly isActive: boolean + readonly packageJSON: any + readonly exports: T + activate(): Promise +} + +export interface ExtensionItem { + readonly id: string + readonly type: ExtensionType + extension: Extension + deactivate: () => void | Promise + filepath?: string + directory?: string + readonly isLocal: boolean +} + +export interface ExtensionJson { + name: string + main?: string + engines: { + [key: string]: string + } + version?: string + [key: string]: any +} + +export interface ExtensionInfo { + id: string + version: string + description: string + root: string + exotic: boolean + uri?: string + state: ExtensionState + isLocal: boolean + packageJSON: Readonly +} + +// global local file native +export class Extensions { + private extensions: Map = new Map() + private disabled: Set = new Set() + private db: DB + private memos: Memos + private root: string + private _onDidLoadExtension = new Emitter>() + private _onDidActiveExtension = new Emitter>() + private _onDidUnloadExtension = new Emitter() + private _additionalSchemes: { [key: string]: PropertyScheme } = {} + private activated = false + private installBuffer: InstallBuffer + private disposables: Disposable[] = [] + private _outputChannel: OutputChannel | undefined + public ready = true + public readonly onDidLoadExtension: Event> = this._onDidLoadExtension.event + public readonly onDidActiveExtension: Event> = this._onDidActiveExtension.event + public readonly onDidUnloadExtension: Event = this._onDidUnloadExtension.event + + constructor() { + let folder = global.__TEST__ ? path.join(__dirname, '__tests__') : process.env.COC_DATA_HOME + let root = this.root = path.join(folder, 'extensions') + let checked = this.checkRoot(root) + if (checked) { + let filepath = path.join(root, 'db.json') + this.db = new DB(filepath) + } + } + + public checkRoot(root: string): boolean { + try { + if (!fs.existsSync(root)) { + fs.mkdirpSync(root) + } + let stat = fs.statSync(root) + if (stat.isFile()) { + logger.info(`Trying to delete ${root}`) + fs.unlinkSync(root) + fs.mkdirpSync(root) + } else if (!stat.isDirectory()) { + console.error(`Data home ${root} it not a valid directory`) + return false + } + let jsonFile = path.join(root, 'package.json') + if (!fs.existsSync(jsonFile)) { + fs.writeFileSync(jsonFile, '{"dependencies":{}}', 'utf8') + } + } catch (e) { + console.error(`Unexpected error when check data home: ${e}`) + return false + } + return true + } + + private get outputChannel(): OutputChannel { + if (this._outputChannel) return this._outputChannel + this._outputChannel = window.createOutputChannel('extensions') + return this._outputChannel + } + + public async init(): Promise { + let extensionObj = this.db.fetch('extension') || {} + let keys = Object.keys(extensionObj) + for (let key of keys) { + if (extensionObj[key].disabled == true) { + this.disabled.add(key) + } + } + if (process.env.COC_NO_PLUGINS) return + let stats = await this.globalExtensionStats() + let localStats = await this.localExtensionStats(stats.map(o => o.id)) + stats = stats.concat(localStats) + this.memos = new Memos(path.resolve(this.root, '../memos.json')) + stats.map(stat => { + let extensionType = stat.isLocal ? ExtensionType.Local : ExtensionType.Global + try { + this.createExtension(stat.root, stat.packageJSON, extensionType) + } catch (e) { + logger.error(`Error on create ${stat.root}:`, e) + } + }) + await this.loadFileExtensions() + commandManager.register({ + id: 'extensions.forceUpdateAll', + execute: async () => { + let arr = await this.cleanExtensions() + logger.info(`Force update extensions: ${arr}`) + await this.installExtensions(arr) + } + }, false, 'remove all global extensions and install them') + workspace.onDidRuntimePathChange(async paths => { + for (let p of paths) { + if (p && this.checkDirectory(p) === true) { + await this.loadExtension(p) + } + } + }, null, this.disposables) + } + + public getExtensionsInfo(): { name: string, directory: string, filepath?: string }[] { + let res: { name: string, directory: string, filepath?: string }[] = [] + for (let [key, entry] of this.extensions.entries()) { + let { directory, filepath } = entry + if (!directory) directory = filepath + entry.type + if (directory) res.push({ + name: key, + filepath, + directory: directory.endsWith(path.sep) ? directory : directory + path.sep + }) + } + return res + } + + public activateExtensions(): void { + this.activated = true + for (let item of this.extensions.values()) { + let { id, packageJSON } = item.extension + this.setupActiveEvents(id, packageJSON).logError() + } + // make sure workspace.env exists + let floatFactory = new FloatFactory(workspace.nvim) + events.on('CursorMoved', debounce(async bufnr => { + if (this.installBuffer && bufnr == this.installBuffer.bufnr) { + let lnum = await workspace.nvim.call('line', ['.']) + let msgs = this.installBuffer.getMessages(lnum - 1) + let docs = msgs && msgs.length ? [{ content: msgs.join('\n'), filetype: 'txt' }] : [] + await floatFactory.show(docs, { modes: ['n'] }) + } + }, 500)) + if (global.__TEST__) return + // check extensions need watch & install + this.checkExtensions() + let config = workspace.getConfiguration('coc.preferences') + let interval = config.get('extensionUpdateCheck', 'never') + let silent = config.get('silentAutoupdate', true) + if (interval != 'never') { + let now = new Date() + let day = new Date(now.getFullYear(), now.getMonth(), now.getDate() - (interval == 'daily' ? 0 : 7)) + let ts = this.db.fetch('lastUpdate') + if (ts && Number(ts) > day.getTime()) return + this.outputChannel.appendLine('Start auto update...') + this.updateExtensions(false, silent).logError() + } + } + + public async updateExtensions(sync?: boolean, silent = false): Promise { + if (!this.npm) return + let lockedList = await this.getLockedList() + let stats = await this.globalExtensionStats() + stats = stats.filter(o => ![...lockedList, ...this.disabled].includes(o.id)) + this.db.push('lastUpdate', Date.now()) + if (silent) { + window.showMessage('Updating extensions, checkout output:///extensions for details.', 'more') + } + let installBuffer = this.installBuffer = new InstallBuffer(true, sync, silent ? this.outputChannel : undefined) + installBuffer.setExtensions(stats.map(o => o.id)) + await installBuffer.show(workspace.nvim) + let createInstaller = createInstallerFactory(this.npm, this.modulesFolder) + let fn = (stat: ExtensionInfo): Promise => { + let { id } = stat + installBuffer.startProgress([id]) + let url = stat.exotic ? stat.uri : null + // msg => installBuffer.addMessage(id, msg) + let installer = createInstaller(id) + installer.on('message', (msg, isProgress) => { + installBuffer.addMessage(id, msg, isProgress) + }) + return installer.update(url).then(directory => { + installBuffer.finishProgress(id, true) + if (directory) { + this.loadExtension(directory).logError() + } + }, err => { + installBuffer.addMessage(id, err.message) + installBuffer.finishProgress(id, false) + }) + } + await concurrent(stats, fn, silent ? 1 : 3) + } + + private checkExtensions(): void { + let { globalExtensions } = workspace.env + if (globalExtensions && globalExtensions.length) { + let names = this.filterGlobalExtensions(globalExtensions) + void this.installExtensions(names) + } + } + + public get installer() { + return createInstallerFactory(this.npm, this.modulesFolder) + } + + /** + * Install extensions, can be called without initialize. + */ + public async installExtensions(list: string[] = []): Promise { + let { npm } = this + if (!npm || !list.length) return + list = distinct(list) + let installBuffer = this.installBuffer = new InstallBuffer() + installBuffer.setExtensions(list) + await installBuffer.show(workspace.nvim) + let createInstaller = createInstallerFactory(this.npm, this.modulesFolder) + let fn = (key: string): Promise => { + installBuffer.startProgress([key]) + let installer = createInstaller(key) + installer.on('message', (msg, isProgress) => { + installBuffer.addMessage(key, msg, isProgress) + }) + return installer.install().then(name => { + installBuffer.finishProgress(key, true) + let directory = path.join(this.modulesFolder, name) + this.loadExtension(directory).logError() + let ms = key.match(/(.+)@([^/]+)$/) + if (ms != null) void this.lockExtension(name, true) + }, err => { + installBuffer.addMessage(key, err.message) + installBuffer.finishProgress(key, false) + logger.error(`Error on install ${key}`, err) + }) + } + await concurrent(list, fn) + } + + /** + * Get list of extensions in package.json that not installed + */ + public getMissingExtensions(): string[] { + let json = this.loadJson() || { dependencies: {} } + let ids: string[] = [] + for (let key of Object.keys(json.dependencies)) { + let folder = path.join(this.modulesFolder, key) + if (!fs.existsSync(folder)) { + let val = json.dependencies[key] + if (val.startsWith('http')) { + ids.push(val) + } else { + ids.push(key) + } + } + } + return ids + } + + public get npm(): string { + let npm = workspace.getConfiguration('npm').get('binPath', 'npm') + npm = workspace.expand(npm) + for (let exe of [npm, 'yarnpkg', 'yarn', 'npm']) { + try { + let res = which.sync(exe) + return res + } catch (e) { + continue + } + } + window.showMessage(`Can't find npm or yarn in your $PATH`, 'error') + return null + } + + /** + * Get all loaded extensions. + */ + public get all(): Extension[] { + return Array.from(this.extensions.values()).map(o => o.extension).filter(o => !this.isDisabled(o.id)) + } + + public getExtension(id: string): ExtensionItem { + return this.extensions.get(id) + } + + public getExtensionState(id: string): ExtensionState { + let disabled = this.isDisabled(id) + if (disabled) return 'disabled' + let item = this.extensions.get(id) + if (!item) return 'unknown' + let { extension } = item + return extension.isActive ? 'activated' : 'loaded' + } + + public async getExtensionStates(): Promise { + let localStats = await this.localExtensionStats([]) + let globalStats = await this.globalExtensionStats() + return localStats.concat(globalStats.filter(o => localStats.find(s => s.id == o.id) == null)) + } + + public async getLockedList(): Promise { + let obj = await this.db.fetch('extension') + obj = obj || {} + return Object.keys(obj).filter(id => obj[id].locked === true) + } + + public async lockExtension(id: string, lock?: boolean): Promise { + let key = `extension.${id}.locked` + let locked = await this.db.fetch(key) + lock = lock === undefined ? !locked : lock + if (lock) { + this.db.push(key, true) + } else { + this.db.delete(key) + } + } + + public async toggleExtension(id: string): Promise { + let state = this.getExtensionState(id) + if (state == null) return + if (state == 'activated') { + await this.deactivate(id) + } + let key = `extension.${id}.disabled` + this.db.push(key, state == 'disabled' ? false : true) + if (state != 'disabled') { + this.disabled.add(id) + await this.unloadExtension(id) + } else { + this.disabled.delete(id) + let folder = path.join(this.modulesFolder, id) + if (fs.existsSync(folder)) { + await this.loadExtension(folder) + } + } + await wait(200) + } + + public async reloadExtension(id: string): Promise { + let item = this.extensions.get(id) + if (!item) { + window.showMessage(`Extension ${id} not registered`, 'error') + return + } + if (item.type == ExtensionType.Internal) { + window.showMessage(`Can't reload internal extension "${item.id}"`, 'warning') + return + } + if (item.type == ExtensionType.SingleFile) { + await this.loadExtensionFile(item.filepath) + } else if (item.directory) { + await this.loadExtension(item.directory) + } else { + window.showMessage(`Can't reload extension ${item.id}`, 'warning') + } + } + + /** + * Unload & remove all global extensions, return removed extensions. + */ + public async cleanExtensions(): Promise { + let dir = this.modulesFolder + if (!fs.existsSync(dir)) return [] + let ids = this.globalExtensions + let res: string[] = [] + for (let id of ids) { + let directory = path.join(dir, id) + let stat = await fs.lstat(directory) + if (!stat || (stat && stat.isSymbolicLink())) continue + await this.unloadExtension(id) + await fs.remove(directory) + res.push(id) + } + return res + } + + public async uninstallExtension(ids: string[]): Promise { + try { + if (!ids.length) return + let [globals, filtered] = splitArray(ids, id => this.globalExtensions.includes(id)) + if (filtered.length) { + window.showMessage(`Extensions ${filtered} not global extensions, can't uninstall!`, 'warning') + } + let json = this.loadJson() || { dependencies: {} } + for (let id of globals) { + await this.unloadExtension(id) + delete json.dependencies[id] + // remove directory + let folder = path.join(this.modulesFolder, id) + if (fs.existsSync(folder)) { + await fs.remove(folder) + } + } + // update package.json + const sortedObj = { dependencies: {} } + Object.keys(json.dependencies).sort().forEach(k => { + sortedObj.dependencies[k] = json.dependencies[k] + }) + let jsonFile = path.join(this.root, 'package.json') + fs.writeFileSync(jsonFile, JSON.stringify(sortedObj, null, 2), { encoding: 'utf8' }) + window.showMessage(`Removed: ${globals.join(' ')}`) + } catch (e) { + window.showMessage(`Uninstall failed: ${e}`, 'error') + } + } + + public isDisabled(id: string): boolean { + return this.disabled.has(id) + } + + public has(id: string): boolean { + return this.extensions.has(id) + } + + public isActivated(id: string): boolean { + let item = this.extensions.get(id) + if (item && item.extension.isActive) { + return true + } + return false + } + + /** + * Load extension from folder, folder should contains coc extension. + */ + public async loadExtension(folder: string | string[]): Promise { + if (Array.isArray(folder)) { + for (let f of folder) { + await this.loadExtension(f) + } + return true + } + try { + let parentFolder = path.dirname(folder) + let isLocal = path.normalize(parentFolder) != path.normalize(this.modulesFolder) + let jsonFile = path.join(folder, 'package.json') + let packageJSON = JSON.parse(fs.readFileSync(jsonFile, 'utf8')) + let { name } = packageJSON + if (this.isDisabled(name)) return false + // unload if loaded + await this.unloadExtension(name) + this.createExtension(folder, Object.freeze(packageJSON), isLocal ? ExtensionType.Local : ExtensionType.Global) + return true + } catch (e) { + window.showMessage(`Error on load extension from "${folder}": ${e}`, 'error') + logger.error(`Error on load extension from ${folder}`, e) + return false + } + } + + private async loadFileExtensions(): Promise { + if (!process.env.COC_VIMCONFIG) return + let folder = path.join(process.env.COC_VIMCONFIG, 'coc-extensions') + if (!fs.existsSync(folder)) return + let files = await fs.readdir(folder) + files = files.filter(f => f.endsWith('.js')) + for (let file of files) { + await this.loadExtensionFile(path.join(folder, file)) + } + } + + public loadedExtensions(): string[] { + return Array.from(this.extensions.keys()) + } + + public async watchExtension(id: string): Promise { + let item = this.extensions.get(id) + if (!item) { + window.showMessage(`extension ${id} not found`, 'error') + return + } + if (id.startsWith('single-')) { + window.showMessage(`watching ${item.filepath}`) + this.disposables.push(watchFile(item.filepath, async () => { + await this.loadExtensionFile(item.filepath) + window.showMessage(`reloaded ${id}`) + })) + } else { + let watchmanPath = workspace.getWatchmanPath() + if (!watchmanPath) { + window.showMessage('watchman not found', 'error') + return + } + let client = await Watchman.createClient(watchmanPath, item.directory) + if (!client) { + window.showMessage(`Can't create watchman client, check output:///watchman`) + return + } + window.showMessage(`watching ${item.directory}`) + this.disposables.push(client) + client.subscribe('**/*.js', async () => { + await this.reloadExtension(id) + window.showMessage(`reloaded ${id}`) + }).then(disposable => { + this.disposables.push(disposable) + }, _e => { + // ignore + }) + } + } + + /** + * Load single javascript file as extension. + */ + public async loadExtensionFile(filepath: string): Promise { + let filename = path.basename(filepath) + let basename = path.basename(filepath, '.js') + let name = 'single-' + basename + if (this.isDisabled(name)) return + let root = path.dirname(filepath) + let packageJSON = { + name, main: filename, engines: { coc: '^0.0.79' } + } + let confpath = path.join(root, basename + '.json') + let stat = await statAsync(confpath) + if (stat && stat.isFile()) { + let content = await readFile(confpath, 'utf8') + let obj = JSON.parse(content) + if (obj) { + let attrs = ['activationEvents', 'contributes'] + for (const attr of attrs) { + if (obj[attr]) { + packageJSON[attr] = obj[attr] + } + } + } + } + await this.unloadExtension(name) + this.createExtension(root, packageJSON, ExtensionType.SingleFile) + } + + /** + * Activate extension, throw error if disabled or doesn't exist. + * Returns true if extension successfully activated. + */ + public async activate(id): Promise { + if (this.isDisabled(id)) { + throw new Error(`Extension ${id} is disabled!`) + } + let item = this.extensions.get(id) + if (!item) { + throw new Error(`Extension ${id} not registered!`) + } + let { extension } = item + if (extension.isActive) return true + await Promise.resolve(extension.activate()) + if (extension.isActive) { + this._onDidActiveExtension.fire(extension) + return true + } + return false + } + + public async deactivate(id): Promise { + let item = this.extensions.get(id) + if (!item) return false + await Promise.resolve(item.deactivate()) + return true + } + + public async call(id: string, method: string, args: any[]): Promise { + let item = this.extensions.get(id) + if (!item) throw new Error(`extension ${id} not registered`) + let { extension } = item + if (!extension.isActive) { + await this.activate(id) + } + let { exports } = extension + if (!exports || !exports.hasOwnProperty(method)) { + throw new Error(`method ${method} not found on extension ${id}`) + } + return await Promise.resolve(exports[method].apply(null, args)) + } + + public getExtensionApi(id: string): API | null { + let item = this.extensions.get(id) + if (!item) return null + let { extension } = item + return extension.isActive ? extension.exports : null + } + + public registerExtension(extension: Extension, deactivate?: () => void): void { + let { id, packageJSON } = extension + this.extensions.set(id, { id, type: ExtensionType.Internal, extension, deactivate, isLocal: true }) + let { contributes } = packageJSON + if (contributes) { + let { configuration } = contributes + if (configuration && configuration.properties) { + let { properties } = configuration + let props = {} + for (let key of Object.keys(properties)) { + let val = properties[key].default + if (val != null) props[key] = val + } + workspace.configurations.extendsDefaults(props) + } + } + this._onDidLoadExtension.fire(extension) + this.setupActiveEvents(id, packageJSON).logError() + } + + public get globalExtensions(): string[] { + let json = this.loadJson() + if (!json || !json.dependencies) return [] + return Object.keys(json.dependencies) + } + + private async globalExtensionStats(): Promise { + let json = this.loadJson() + if (!json || !json.dependencies) return [] + let { modulesFolder } = this + let res: ExtensionInfo[] = await Promise.all(Object.keys(json.dependencies).map(key => new Promise(async resolve => { + try { + let val = json.dependencies[key] + let root = path.join(modulesFolder, key) + let res = this.checkDirectory(root) + if (res instanceof Error) { + window.showMessage(`Unable to load global extension at ${root}: ${res.message}`, 'error') + logger.error(`Error on load ${root}`, res) + return resolve(null) + } + let content = await readFile(path.join(root, 'package.json'), 'utf8') + root = await fs.realpath(root) + let obj = JSON.parse(content) + let version = obj ? obj.version || '' : '' + let description = obj ? obj.description || '' : '' + let uri = isuri.isValid(val) ? val : '' + resolve({ + id: key, + isLocal: false, + version, + description, + exotic: /^https?:/.test(val), + uri: uri.replace(/\.git(#master)?$/, ''), + root, + state: this.getExtensionState(key), + packageJSON: Object.freeze(obj) + }) + } catch (e) { + logger.error(e) + resolve(null) + } + }))) + return res.filter(info => info != null) + } + + private async localExtensionStats(excludes: string[]): Promise { + let runtimepath = await workspace.nvim.eval('join(globpath(&runtimepath, "", 0, 1), ",")') as string + let paths = runtimepath.split(',') + let res: ExtensionInfo[] = await Promise.all(paths.map(root => new Promise(async resolve => { + try { + let res = this.checkDirectory(root) + if (res !== true) return resolve(null) + let jsonFile = path.join(root, 'package.json') + let content = await readFile(jsonFile, 'utf8') + let obj = JSON.parse(content) + let exist = this.extensions.get(obj.name) + if (exist && !exist.isLocal) { + logger.info(`Extension "${obj.name}" in runtimepath already loaded.`) + return resolve(null) + } + if (excludes.includes(obj.name)) { + logger.info(`Skipped load vim plugin from "${root}", "${obj.name}" already global extension.`) + return resolve(null) + } + let version = obj ? obj.version || '' : '' + let description = obj ? obj.description || '' : '' + resolve({ + id: obj.name, + isLocal: true, + version, + description, + exotic: false, + root, + state: this.getExtensionState(obj.name), + packageJSON: Object.freeze(obj) + }) + } catch (e) { + logger.error(e) + resolve(null) + } + }))) + return res.filter(info => info != null) + } + + private loadJson(): any { + let { root } = this + let jsonFile = path.join(root, 'package.json') + if (!fs.existsSync(jsonFile)) return null + let errors: ParseError[] = [] + let content = fs.readFileSync(jsonFile, 'utf8') + let data = parse(content, errors, { allowTrailingComma: true }) + if (errors && errors.length > 0) { + window.showMessage(`Error on parse ${jsonFile}`, 'error') + workspace.nvim.call('coc#util#open_file', ['edit', jsonFile], true) + } + return data + } + + public get schemes(): { [key: string]: PropertyScheme } { + return this._additionalSchemes + } + + public addSchemeProperty(key: string, def: PropertyScheme): void { + this._additionalSchemes[key] = def + workspace.configurations.extendsDefaults({ [key]: def.default }) + } + + private async setupActiveEvents(id: string, packageJSON: any): Promise { + let { activationEvents } = packageJSON + if (!this.canActivate(id)) return + if (!activationEvents || Array.isArray(activationEvents) && activationEvents.includes('*')) { + await this.activate(id).catch(e => { + window.showMessage(`Error on activate extension ${id}: ${e.message}`) + this.outputChannel.appendLine(`Error on activate extension ${id}.\n${e.message}\n ${e.stack}`) + }) + return + } + let disposables: Disposable[] = [] + let called = false + let active = (): Promise => { + if (called) return + called = true + disposeAll(disposables) + return new Promise(resolve => { + if (!this.canActivate(id)) { + this.outputChannel.appendLine(`Extension ${id} is disabled or not loaded.`) + return resolve() + } + this.activate(id).then(() => { + resolve() + }, e => { + window.showMessage(`Error on activate extension ${id}: ${e.message}`) + this.outputChannel.appendLine(`Error on activate extension ${id}:${e.message}\n ${e.stack}`) + resolve() + }) + }) + } + + for (let eventName of activationEvents as string[]) { + let parts = eventName.split(':') + let ev = parts[0] + if (ev == 'onLanguage') { + if (workspace.languageIds.has(parts[1]) + || workspace.filetypes.has(parts[1])) { + await active() + return + } + workspace.onDidOpenTextDocument(document => { + let doc = workspace.getDocument(document.bufnr) + if (document.languageId == parts[1] || doc.filetype == parts[1]) { + void active() + } + }, null, disposables) + } else if (ev == 'onCommand') { + commandManager.onCommandList.push(parts[1]) + events.on('Command', async command => { + if (command == parts[1]) { + await active() + await wait(500) + } + }, null, disposables) + } else if (ev == 'workspaceContains') { + let check = async () => { + let folders = workspace.workspaceFolders.map(o => URI.parse(o.uri).fsPath) + for (let folder of folders) { + for (let pattern of parts[1].split(/\s+/)) { + let exists = await checkFolder(folder, pattern) + if (exists) { + await active() + return true + } + } + } + return false + } + workspace.onDidChangeWorkspaceFolders(check, null, disposables) + let checked = await check() + if (checked) return + } else if (ev == 'onFileSystem') { + for (let doc of workspace.documents) { + let u = URI.parse(doc.uri) + if (u.scheme == parts[1]) { + await active() + return + } + } + workspace.onDidOpenTextDocument(document => { + let u = URI.parse(document.uri) + if (u.scheme == parts[1]) { + void active() + } + }, null, disposables) + } else { + window.showMessage(`Unsupported event ${eventName} of ${id}`, 'error') + } + } + } + + private createExtension(root: string, packageJSON: any, type: ExtensionType): void { + let id = packageJSON.name + let isActive = false + let result: Promise | undefined + let filename = path.join(root, packageJSON.main || 'index.js') + let ext: ExtensionExport + let subscriptions: Disposable[] = [] + let exports: any + let extension: any = { + activate: (): Promise => { + if (result) return result + let context = { + subscriptions, + extensionPath: root, + globalState: this.memos.createMemento(`${id}|global`), + workspaceState: this.memos.createMemento(`${id}|${workspace.rootPath}`), + asAbsolutePath: relativePath => path.join(root, relativePath), + storagePath: path.join(this.root, `${id}-data`), + logger: createLogger(id) + } + if (!ext) { + try { + let isEmpty = !(packageJSON.engines || {}).hasOwnProperty('coc') + ext = createExtension(id, filename, isEmpty) + } catch (e) { + logger.error(`Error on createExtension ${id} from ${filename}`, e) + return + } + } + result = new Promise((resolve, reject) => { + try { + Promise.resolve(ext.activate(context)).then(res => { + isActive = true + exports = res + resolve(res) + }, e => { + logger.error(`Error on active extension ${id}: ${e.message}`, e) + reject(e) + }) + } catch (e) { + logger.error(`Error on active extension ${id}: ${e}`, e instanceof Error ? e.stack : e) + reject(e) + } + }) + return result + } + } + Object.defineProperties(extension, { + id: { + get: () => id, + enumerable: true + }, + packageJSON: { + get: () => packageJSON, + enumerable: true + }, + extensionPath: { + get: () => root, + enumerable: true + }, + isActive: { + get: () => isActive, + enumerable: true + }, + exports: { + get: () => { + if (!isActive) throw new Error(`Invalid access to exports, extension "${id}" not activated`) + return exports + }, + enumerable: true + } + }) + + this.extensions.set(id, { + id, + type, + isLocal: type == ExtensionType.Local, + extension, + directory: root, + filepath: filename, + deactivate: () => { + if (!isActive) return + result = undefined + exports = undefined + isActive = false + disposeAll(subscriptions) + subscriptions.splice(0, subscriptions.length) + subscriptions = [] + if (ext && ext.deactivate) { + try { + return Promise.resolve(ext.deactivate()).catch(e => { + logger.error(`Error on ${id} deactivate: `, e) + }) + } catch (e) { + logger.error(`Error on ${id} deactivate: `, e) + } + } + } + }) + let { contributes } = packageJSON + if (contributes) { + let { configuration, rootPatterns, commands } = contributes + if (configuration && configuration.properties) { + let { properties } = configuration + let props = {} + for (let key of Object.keys(properties)) { + let val = properties[key].default + if (val != null) props[key] = val + } + workspace.configurations.extendsDefaults(props) + } + if (rootPatterns && rootPatterns.length) { + for (let item of rootPatterns) { + workspace.workspaceFolderControl.addRootPattern(item.filetype, item.patterns) + } + } + if (commands && commands.length) { + for (let cmd of commands) { + commandManager.titles.set(cmd.command, cmd.title) + } + } + } + this._onDidLoadExtension.fire(extension) + if (this.activated) { + this.setupActiveEvents(id, packageJSON).logError() + } + } + + /** + * Filter out global extensions that needs install + */ + public filterGlobalExtensions(names: string[]): string[] { + let map: Map = new Map() + names.forEach(def => { + let name = this.getExtensionName(def) + if (name) map.set(name, def) + }) + let json = this.loadJson() + let urls: string[] = [] + let exists: string[] = [] + if (json && json.dependencies) { + for (let key of Object.keys(json.dependencies)) { + let val = json.dependencies[key] + if (typeof val !== 'string') continue + if (fs.existsSync(path.join(this.modulesFolder, key, 'package.json'))) { + exists.push(key) + if (/^https?:/.test(val)) { + urls.push(val) + } + } + } + } + for (let name of map.keys()) { + if (this.disabled.has(name) || this.extensions.has(name)) { + map.delete(name) + continue + } + if ((/^https?:/.test(name) && urls.some(url => url.startsWith(name))) + || exists.includes(name)) { + map.delete(name) + } + } + return Array.from(map.values()) + } + + /** + * Name of extension + */ + private getExtensionName(def: string): string { + if (/^https?:/.test(def)) return def + if (!def.includes('@')) return def + return def.replace(/@[\d.]+$/, '') + } + + private get modulesFolder(): string { + return path.join(this.root, global.__TEST__ ? '' : 'node_modules') + } + + private canActivate(id: string): boolean { + return !this.disabled.has(id) && this.extensions.has(id) + } + + /** + * Deactivate & unregist extension + */ + private async unloadExtension(id: string): Promise { + let item = this.extensions.get(id) + if (item) { + await this.deactivate(id) + this.extensions.delete(id) + this._onDidUnloadExtension.fire(id) + } + } + + /** + * Check if folder contains extension, return Error + */ + private checkDirectory(folder: string): boolean | Error { + try { + let jsonFile = path.join(folder, 'package.json') + if (!fs.existsSync(jsonFile)) throw new Error('package.json not found') + let packageJSON = JSON.parse(fs.readFileSync(jsonFile, 'utf8')) + let { name, engines, main } = packageJSON + if (!name || !engines) throw new Error(`can't find name & engines in package.json`) + if (!engines || !objectLiteral(engines)) { + throw new Error(`invalid engines in ${jsonFile}`) + } + if (main && !fs.existsSync(path.join(folder, main))) { + throw new Error(`main file ${main} not found, you may need to build the project.`) + } + let keys = Object.keys(engines) + if (!keys.includes('coc') && !keys.includes('vscode')) { + throw new Error(`Engines in package.json doesn't have coc or vscode`) + } + if (keys.includes('coc')) { + let required = engines['coc'].replace(/^\^/, '>=') + if (!semver.satisfies(workspace.version, required)) { + throw new Error(`Please update coc.nvim, ${packageJSON.name} requires coc.nvim ${engines['coc']}`) + } + } + return true + } catch (e) { + return e as Error + } + } + + public dispose(): void { + disposeAll(this.disposables) + } +} + +export default new Extensions() diff --git a/sources_non_forked/coc.nvim/src/handler/callHierarchy.ts b/sources_non_forked/coc.nvim/src/handler/callHierarchy.ts new file mode 100644 index 00000000..a3afa63a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/callHierarchy.ts @@ -0,0 +1,258 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CancellationToken, CancellationTokenSource, Disposable, Emitter, Position, Range, SymbolTag } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import commands from '../commands' +import events from '../events' +import languages from '../languages' +import { TreeDataProvider, TreeItem, TreeItemCollapsibleState } from '../tree/index' +import BasicTreeView from '../tree/TreeView' +import { ConfigurationChangeEvent, HandlerDelegate } from '../types' +import { disposeAll } from '../util' +import { omit } from '../util/lodash' +import workspace from '../workspace' +const logger = require('../util/logger')('Handler-callHierarchy') + +interface CallHierarchyDataItem extends CallHierarchyItem { + ranges?: Range[] + sourceUri?: string + children?: CallHierarchyItem[] +} + +interface CallHierarchyConfig { + splitCommand: string + openCommand: string + enableTooltip: boolean +} + +interface CallHierarchyProvider extends TreeDataProvider { + kind: 'incoming' | 'outgoing' + dispose: () => void +} + +function isCallHierarchyItem(item: any): item is CallHierarchyItem { + if (item && item.name && item.kind && Range.is(item.range) && item.uri) return true + return false +} + +export default class CallHierarchyHandler { + private config: CallHierarchyConfig + private disposables: Disposable[] = [] + public static commandId = 'callHierarchy.reveal' + public static rangesHighlight = 'CocSelectedRange' + private highlightWinids: Set = new Set() + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.loadConfiguration() + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + this.disposables.push(commands.registerCommand(CallHierarchyHandler.commandId, async (winid: number, item: CallHierarchyDataItem, openCommand?: string) => { + let { nvim } = this + await nvim.call('win_gotoid', [winid]) + await workspace.jumpTo(item.uri, item.selectionRange.start, openCommand) + let win = await nvim.window + win.clearMatchGroup(CallHierarchyHandler.rangesHighlight) + win.highlightRanges(CallHierarchyHandler.rangesHighlight, [item.selectionRange], 10, true) + if (!item.ranges?.length) return + if (item.sourceUri) { + let doc = workspace.getDocument(item.sourceUri) + if (!doc) return + let winid = await nvim.call('coc#compat#buf_win_id', [doc.bufnr]) + if (winid == -1) return + if (winid != win.id) { + win = nvim.createWindow(winid) + win.clearMatchGroup(CallHierarchyHandler.rangesHighlight) + } + } + win.highlightRanges(CallHierarchyHandler.rangesHighlight, item.ranges, 100, true) + this.highlightWinids.add(win.id) + }, null, true)) + events.on('BufWinEnter', (_, winid) => { + if (this.highlightWinids.has(winid)) { + this.highlightWinids.delete(winid) + let win = nvim.createWindow(winid) + win.clearMatchGroup(CallHierarchyHandler.rangesHighlight) + } + }, null, this.disposables) + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('callHierarchy')) { + let c = workspace.getConfiguration('callHierarchy') + this.config = { + splitCommand: c.get('splitCommand'), + openCommand: c.get('openCommand'), + enableTooltip: c.get('enableTooltip') + } + } + } + + private createProvider(doc: TextDocument, winid: number, position: Position, kind: 'incoming' | 'outgoing'): CallHierarchyProvider { + let _onDidChangeTreeData = new Emitter() + let source: CancellationTokenSource | undefined + let rootItems: CallHierarchyDataItem[] | undefined + const cancel = () => { + if (source) { + source.cancel() + source.dispose() + source = null + } + } + const findParent = (curr: CallHierarchyDataItem, element: CallHierarchyDataItem): CallHierarchyDataItem | undefined => { + let children = curr.children + if (!Array.isArray(children)) return undefined + let find = children.find(o => o == element) + if (find) return curr + for (let item of children) { + let res = findParent(item, element) + if (res) return res + } + } + let provider: CallHierarchyProvider = { + kind, + onDidChangeTreeData: _onDidChangeTreeData.event, + getTreeItem: element => { + let item = new TreeItem(element.name, element.children ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed) + if (this.config.enableTooltip) { + item.tooltip = path.relative(workspace.cwd, URI.parse(element.uri).fsPath) + } + item.description = element.detail + item.deprecated = element.tags?.includes(SymbolTag.Deprecated) + item.icon = this.handler.getIcon(element.kind) + item.command = { + command: CallHierarchyHandler.commandId, + title: 'open location', + arguments: [winid, element, this.config.openCommand] + } + return item + }, + getChildren: async element => { + cancel() + source = new CancellationTokenSource() + let { token } = source + if (!element) { + if (!rootItems) { + rootItems = await this.prepare(doc, position, token) as CallHierarchyDataItem[] + if (!rootItems?.length) return + } + for (let o of rootItems) { + let children = await this.getChildren(doc, o, provider.kind, token) + if (token.isCancellationRequested) break + if (Array.isArray(children)) o.children = children + } + return rootItems + } + if (element.children) return element.children + let items = await this.getChildren(doc, element, provider.kind, token) + source = null + if (token.isCancellationRequested) return [] + element.children = items + return items + }, + resolveActions: () => { + return [{ + title: 'Open in new tab', + handler: async element => { + await commands.executeCommand(CallHierarchyHandler.commandId, winid, element, 'tabe') + } + }, { + title: 'Show Incoming Calls', + handler: element => { + rootItems = [omit(element, ['children', 'ranges', 'sourceUri'])] + provider.kind = 'incoming' + _onDidChangeTreeData.fire(undefined) + } + }, { + title: 'Show Outgoing Calls', + handler: element => { + rootItems = [omit(element, ['children', 'ranges', 'sourceUri'])] + provider.kind = 'outgoing' + _onDidChangeTreeData.fire(undefined) + } + }, { + title: 'Dismiss', + handler: async element => { + let parentElement: CallHierarchyDataItem | undefined + for (let curr of rootItems) { + parentElement = findParent(curr, element) + if (parentElement) break + } + if (!parentElement) return + let idx = parentElement.children.findIndex(o => o === element) + parentElement.children.splice(idx, 1) + _onDidChangeTreeData.fire(parentElement) + } + }] + }, + dispose: () => { + cancel() + _onDidChangeTreeData.dispose() + rootItems = undefined + _onDidChangeTreeData = undefined + } + } + return provider + } + + private async getChildren(doc: TextDocument, item: CallHierarchyItem, kind: 'incoming' | 'outgoing', token: CancellationToken): Promise { + let items: CallHierarchyDataItem[] = [] + if (kind == 'incoming') { + let res = await languages.provideIncomingCalls(doc, item, token) + if (res) items = res.map(o => Object.assign(o.from, { ranges: o.fromRanges })) + } else { + let res = await languages.provideOutgoingCalls(doc, item, token) + if (res) items = res.map(o => Object.assign(o.to, { ranges: o.fromRanges, sourceUri: item.uri })) + } + return items + } + + private async prepare(doc: TextDocument, position: Position, token: CancellationToken): Promise { + this.handler.checkProvier('callHierarchy', doc) + const res = await languages.prepareCallHierarchy(doc, position, token) + return isCallHierarchyItem(res) ? [res] : res + } + + private async getCallHierarchyItems(item: CallHierarchyItem | undefined, kind: 'outgoing'): Promise + private async getCallHierarchyItems(item: CallHierarchyItem | undefined, kind: 'incoming'): Promise + private async getCallHierarchyItems(item: CallHierarchyItem | undefined, kind: 'incoming' | 'outgoing'): Promise { + const { doc, position } = await this.handler.getCurrentState() + const source = new CancellationTokenSource() + if (!item) { + await doc.synchronize() + let res = await this.prepare(doc.textDocument, position, source.token) + item = res ? res[0] : undefined + if (!res) return undefined + } + let method = kind == 'incoming' ? 'provideIncomingCalls' : 'provideOutgoingCalls' + return await languages[method](doc.textDocument, item, source.token) + } + + public async getIncoming(item?: CallHierarchyItem): Promise { + return await this.getCallHierarchyItems(item, 'incoming') + } + + public async getOutgoing(item?: CallHierarchyItem): Promise { + return await this.getCallHierarchyItems(item, 'outgoing') + } + + public async showCallHierarchyTree(kind: 'incoming' | 'outgoing'): Promise { + const { doc, position, winid } = await this.handler.getCurrentState() + await doc.synchronize() + let provider = this.createProvider(doc.textDocument, winid, position, kind) + let treeView = new BasicTreeView('calls', { treeDataProvider: provider }) + treeView.title = `${kind.toUpperCase()} CALLS` + provider.onDidChangeTreeData(e => { + if (!e) treeView.title = `${provider.kind.toUpperCase()} CALLS` + }) + treeView.onDidChangeVisibility(e => { + if (!e.visible) provider.dispose() + }) + this.disposables.push(treeView) + await treeView.show(this.config.splitCommand) + } + + public dispose(): void { + this.highlightWinids.clear() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/codeActions.ts b/sources_non_forked/coc.nvim/src/handler/codeActions.ts new file mode 100644 index 00000000..db8b13df --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/codeActions.ts @@ -0,0 +1,149 @@ +'use strict' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import { CodeActionContext, CodeActionKind, Range } from 'vscode-languageserver-protocol' +import commandManager from '../commands' +import diagnosticManager from '../diagnostic/manager' +import languages from '../languages' +import Document from '../model/document' +import { ExtendedCodeAction, HandlerDelegate } from '../types' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-codeActions') + +/** + * Handle codeActions related methods. + */ +export default class CodeActions { + constructor( + private nvim: Neovim, + private handler: HandlerDelegate + ) { + handler.addDisposable(commandManager.registerCommand('editor.action.organizeImport', async (bufnr?: number) => { + await this.organizeImport(bufnr) + })) + commandManager.titles.set('editor.action.organizeImport', 'run organize import code action.') + } + + public async codeActionRange(start: number, end: number, only?: string): Promise { + let { doc } = await this.handler.getCurrentState() + await doc.synchronize() + let line = doc.getline(end - 1) + let range = Range.create(start - 1, 0, end - 1, line.length) + let codeActions = await this.getCodeActions(doc, range, only ? [only] : null) + codeActions = codeActions.filter(o => !o.disabled) + if (!codeActions || codeActions.length == 0) { + window.showMessage(`No${only ? ' ' + only : ''} code action available`, 'warning') + return + } + let idx = await window.showMenuPicker(codeActions.map(o => o.title), 'Choose action') + let action = codeActions[idx] + if (action) await this.applyCodeAction(action) + } + + public async organizeImport(bufnr?: number): Promise { + let { doc } = await this.handler.getCurrentState() + if (bufnr && doc.bufnr != bufnr) return + await doc.synchronize() + let actions = await this.getCodeActions(doc, undefined, [CodeActionKind.SourceOrganizeImports]) + if (actions && actions.length) { + await this.applyCodeAction(actions[0]) + return + } + throw new Error('Organize import action not found.') + } + + public async getCodeActions(doc: Document, range?: Range, only?: CodeActionKind[]): Promise { + range = range || Range.create(0, 0, doc.lineCount, 0) + let diagnostics = diagnosticManager.getDiagnosticsInRange(doc.textDocument, range) + let context: CodeActionContext = { diagnostics } + if (only && Array.isArray(only)) context.only = only + let codeActions = await this.handler.withRequestToken('code action', token => { + return languages.getCodeActions(doc.textDocument, range, context, token) + }) + if (!codeActions || codeActions.length == 0) return [] + codeActions.sort((a, b) => { + if (a.isPreferred && !b.isPreferred) return -1 + if (b.isPreferred && !a.isPreferred) return 1 + if (a.disabled && !b.disabled) return 1 + if (b.disabled && !a.disabled) return -1 + return 0 + }) + return codeActions + } + + private get floatActions(): boolean { + if (!workspace.floatSupported) return false + let config = workspace.getConfiguration('coc.preferences') + return config.get('floatActions', true) + } + + public async doCodeAction(mode: string | null, only?: CodeActionKind[] | string): Promise { + let { doc } = await this.handler.getCurrentState() + let range: Range + if (mode) range = await window.getSelectedRange(mode) + await doc.synchronize() + let codeActions = await this.getCodeActions(doc, range, Array.isArray(only) ? only : null) + if (typeof only == 'string') { + codeActions = codeActions.filter(o => o.title == only || (o.command && o.command.title == only)) + } else if (Array.isArray(only)) { + codeActions = codeActions.filter(o => only.some(k => o.kind && o.kind.startsWith(k))) + } + if (!codeActions || codeActions.length == 0) { + window.showMessage(`No${only ? ' ' + only : ''} code action available`, 'warning') + return + } + if (only && codeActions.length == 1 && !codeActions[0].disabled) { + await this.applyCodeAction(codeActions[0]) + return + } + if (!this.floatActions) codeActions = codeActions.filter(o => !o.disabled) + let idx = this.floatActions + ? await window.showMenuPicker( + codeActions.map(o => { + return { text: o.title, disabled: o.disabled } + }), + 'Choose action' + ) + : await window.showQuickpick(codeActions.map(o => o.title)) + let action = codeActions[idx] + if (action) await this.applyCodeAction(action) + } + + /** + * Get current codeActions + */ + public async getCurrentCodeActions(mode?: string, only?: CodeActionKind[]): Promise { + let { doc } = await this.handler.getCurrentState() + let range: Range + if (mode) range = await window.getSelectedRange(mode) + let codeActions = await this.getCodeActions(doc, range, only) + return codeActions.filter(o => !o.disabled) + } + + /** + * Invoke preferred quickfix at current position + */ + public async doQuickfix(): Promise { + let actions = await this.getCurrentCodeActions('line', [CodeActionKind.QuickFix]) + if (!actions || actions.length == 0) { + throw new Error('No quickfix action available') + } + await this.applyCodeAction(actions[0]) + this.nvim.command(`silent! call repeat#set("\\(coc-fix-current)", -1)`, true) + } + + public async applyCodeAction(action: ExtendedCodeAction): Promise { + if (action.disabled) { + throw new Error(`Action "${action.title}" is disabled: ${action.disabled.reason}`) + } + if (!action.providerId) { + throw new Error('providerId not found with codeAction') + } + let resolved = await this.handler.withRequestToken('resolve codeAction', token => { + return languages.resolveCodeAction(action, token) + }) + let { edit, command } = resolved + if (edit) await workspace.applyEdit(edit) + if (command) await commandManager.execute(command) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/codelens/buffer.ts b/sources_non_forked/coc.nvim/src/handler/codelens/buffer.ts new file mode 100644 index 00000000..cd8ce615 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/codelens/buffer.ts @@ -0,0 +1,233 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationTokenSource, CodeLens, Command } from 'vscode-languageserver-protocol' +import { SyncItem } from '../../model/bufferSync' +import commandManager from '../../commands' +import languages from '../../languages' +import Document from '../../model/document' +import window from '../../window' +import workspace from '../../workspace' +import { DidChangeTextDocumentParams } from '../../types' +const logger = require('../../util/logger')('codelens-buffer') + +export interface CodeLensInfo { + codeLenses: CodeLens[] + version: number +} + +export interface CodeLensConfig { + position: 'top' | 'eol' | 'right_align' + enabled: boolean + separator: string + subseparator: string + srcId?: number +} + +/** + * CodeLens buffer + */ +export default class CodeLensBuffer implements SyncItem { + private codeLenses: CodeLensInfo + private tokenSource: CancellationTokenSource + private resolveTokenSource: CancellationTokenSource + public resolveCodeLens: (() => void) & { clear(): void } + constructor( + private nvim: Neovim, + public readonly document: Document, + private config: CodeLensConfig + ) { + this.resolveCodeLens = debounce(() => { + void this._resolveCodeLenses() + }, global.__TEST__ ? 20 : 200) + void this.fetchCodeLenses() + } + + private get bufnr(): number { + return this.document.bufnr + } + + public onChange(e: DidChangeTextDocumentParams): void { + if (e.contentChanges.length === 0 && this.codeLenses != null) { + void this._resolveCodeLenses() + } else { + this.cancel() + void this.fetchCodeLenses() + } + } + + public get currentCodeLens(): CodeLens[] | undefined { + return this.codeLenses?.codeLenses + } + + private get enabled(): boolean { + if (!this.document?.attached) return false + return this.config.enabled && languages.hasProvider('codeLens', this.document.textDocument) + } + + public async forceFetch(): Promise { + if (!this.enabled) return + await this.document.synchronize() + this.cancel() + await this.fetchCodeLenses() + } + + private async fetchCodeLenses(): Promise { + if (!this.enabled) return + this.cancel() + let noFetch = this.codeLenses?.version == this.document.version + if (!noFetch) { + let { textDocument } = this.document + let version = textDocument.version + let tokenSource = this.tokenSource = new CancellationTokenSource() + let token = tokenSource.token + let codeLenses = await languages.getCodeLens(textDocument, token) + codeLenses = Array.isArray(codeLenses) ? codeLenses.filter(o => o != null) : [] + this.tokenSource = undefined + if (token.isCancellationRequested || codeLenses.length == 0) return + this.codeLenses = { version, codeLenses } + } + await this._resolveCodeLenses() + } + + /** + * Resolve visible codeLens + */ + private async _resolveCodeLenses(): Promise { + if (!this.enabled || !this.codeLenses || this.isChanged) return + if (!workspace.has('nvim-0.4.0')) return + let { codeLenses } = this.codeLenses + let [bufnr, start, end] = await this.nvim.eval(`[bufnr('%'),line('w0'),line('w$')]`) as [number, number, number] + // only resolve current buffer + if (this.isChanged || bufnr != this.bufnr) return + if (this.resolveTokenSource) this.resolveTokenSource.cancel() + codeLenses = codeLenses.filter(o => { + let lnum = o.range.start.line + 1 + return lnum >= start && lnum <= end + }) + if (codeLenses.length) { + let tokenSource = this.resolveTokenSource = new CancellationTokenSource() + let token = tokenSource.token + await Promise.all(codeLenses.map(codeLens => languages.resolveCodeLens(codeLens, token))) + this.resolveTokenSource = undefined + if (token.isCancellationRequested || this.isChanged) return + } + this.nvim.pauseNotification() + this.clear(start - 1, end) + this.setVirtualText(codeLenses) + this.nvim.resumeNotification(false, true) + } + + private get isChanged(): boolean { + if (!this.codeLenses || this.document.dirty) return true + let { version } = this.codeLenses + return this.document.textDocument.version !== version + } + + /** + * Attach resolved codeLens + */ + private setVirtualText(codeLenses: CodeLens[]): void { + let { document } = this + if (!document || !codeLenses.length) return + let list: Map = new Map() + let { position } = this.config + for (let codeLens of codeLenses) { + let { range, command } = codeLens + if (!command) continue + let { line } = range.start + if (list.has(line)) { + list.get(line).push(codeLens) + } else { + list.set(line, [codeLens]) + } + } + for (let lnum of list.keys()) { + let codeLenses = list.get(lnum) + let commands = codeLenses.map(codeLens => codeLens.command) + commands = commands.filter(c => c && c.title) + let chunks: [string, string][] = [] + let n_commands = commands.length + for (let i = 0; i < n_commands; i++) { + let c = commands[i] + chunks.push([c.title.replace(/(\r\n|\r|\n|\s)+/g, " "), 'CocCodeLens'] as [string, string]) + if (i != n_commands - 1) { + chunks.push([this.config.subseparator, 'CocCodeLens'] as [string, string]) + } + } + if (this.config.separator) { + chunks.unshift([`${this.config.separator} `, 'CocCodeLens']) + } + let { srcId } = this.config + if (workspace.has('nvim-0.6.0')) { + let buf = this.document.buffer + let line = document.getline(lnum) + if (position == 'top') { + let indent = line.match(/^\s*/)[0] + if (indent.length > 0) chunks.unshift([indent, 'Normal']) + buf.setExtMark(srcId, lnum, 0, { + virt_lines: [chunks], + virt_lines_above: true + }) + } else { + buf.setExtMark(srcId, lnum, 0, { + hl_mode: 'combine', + virt_text: chunks, + virt_text_pos: position + }) + } + } else { + this.nvim.call('nvim_buf_set_virtual_text', [this.bufnr, srcId, lnum, chunks, {}], true) + } + } + } + + public clear(start = 0, end = -1): void { + let { srcId } = this.config + if (!srcId) return + let buf = this.nvim.createBuffer(this.bufnr) + buf.clearNamespace(srcId, start, end) + } + + public async doAction(line: number): Promise { + let commands = getCommands(line, this.codeLenses?.codeLenses) + if (commands.length == 1) { + await commandManager.execute(commands[0]) + } else if (commands.length > 1) { + let res = await window.showMenuPicker(commands.map(c => c.title)) + if (res != -1) await commandManager.execute(commands[res]) + } + } + + private cancel(): void { + this.resolveCodeLens.clear() + if (this.resolveTokenSource) { + this.resolveTokenSource.cancel() + this.resolveTokenSource.dispose() + this.resolveTokenSource = null + } + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public dispose(): void { + this.cancel() + this.codeLenses = undefined + } +} + +export function getCommands(line: number, codeLenses: CodeLens[] | undefined): Command[] { + if (!codeLenses?.length) return [] + let commands: Command[] = [] + for (let codeLens of codeLenses) { + let { range, command } = codeLens + if (!command) continue + if (line == range.start.line) { + commands.push(command) + } + } + return commands +} diff --git a/sources_non_forked/coc.nvim/src/handler/codelens/index.ts b/sources_non_forked/coc.nvim/src/handler/codelens/index.ts new file mode 100644 index 00000000..57ca6c45 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/codelens/index.ts @@ -0,0 +1,75 @@ +'use strict' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import events from '../../events' +import BufferSync from '../../model/bufferSync' +import { ConfigurationChangeEvent } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import CodeLensBuffer, { CodeLensConfig } from './buffer' +const logger = require('../../util/logger')('codelens') + +/** + * Show codeLens of document, works on neovim only. + */ +export default class CodeLensManager { + private config: CodeLensConfig + private disposables: Disposable[] = [] + public buffers: BufferSync + constructor(private nvim: Neovim) { + this.setConfiguration() + this.nvim.createNamespace('coc-codelens').then(id => { + this.config.srcId = id + }).logError() + workspace.onDidChangeConfiguration(this.setConfiguration, this, this.disposables) + this.buffers = workspace.registerBufferSync(doc => { + if (doc.buftype != '') return undefined + return new CodeLensBuffer(nvim, doc, this.config) + }) + this.disposables.push(this.buffers) + this.listen() + } + + private listen(): void { + events.on('CursorMoved', bufnr => { + let buf = this.buffers.getItem(bufnr) + if (buf) buf.resolveCodeLens() + }, null, this.disposables) + // Refresh on CursorHold + events.on('CursorHold', async bufnr => { + let buf = this.buffers.getItem(bufnr) + if (buf) await buf.forceFetch() + }, this, this.disposables) + } + + /** + * Check provider for buf that not fetched + */ + public async checkProvider(): Promise { + for (let buf of this.buffers.items) { + await buf.forceFetch() + } + } + + private setConfiguration(e?: ConfigurationChangeEvent): void { + if (e && !e.affectsConfiguration('codeLens')) return + let config = workspace.getConfiguration('codeLens') + let enable: boolean = this.nvim.hasFunction('nvim_buf_set_virtual_text') && config.get('enable', false) + this.config = Object.assign(this.config || {}, { + enabled: enable, + position: config.get<'top' | 'eol'>('position', 'top'), + separator: config.get('separator', '‣'), + subseparator: config.get('subseparator', ' ') + }) + } + + public async doAction(): Promise { + let [bufnr, line] = await this.nvim.eval(`[bufnr("%"),line(".")-1]`) as [number, number] + let buf = this.buffers.getItem(bufnr) + await buf?.doAction(line) + } + + public dispose(): void { + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/colors/colorBuffer.ts b/sources_non_forked/coc.nvim/src/handler/colors/colorBuffer.ts new file mode 100644 index 00000000..b93af062 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/colors/colorBuffer.ts @@ -0,0 +1,129 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationTokenSource, Color, ColorInformation, Position, Range } from 'vscode-languageserver-protocol' +import languages from '../../languages' +import { SyncItem } from '../../model/bufferSync' +import { HighlightItem } from '../../types' +import { isDark, toHexString } from '../../util/color' +import { comparePosition, positionInRange } from '../../util/position' +import window from '../../window' +import workspace from '../../workspace' +const logger = require('../../util/logger')('colors-buffer') +const NAMESPACE = 'color' + +export interface ColorRanges { + color: Color + ranges: Range[] +} + +export interface ColorConfig { + filetypes: string[] + highlightPriority: number +} + +export default class ColorBuffer implements SyncItem { + private _colors: ColorInformation[] = [] + private tokenSource: CancellationTokenSource + public highlight: Function & { clear(): void } + // last highlight version + constructor( + private nvim: Neovim, + private bufnr: number, + private config: ColorConfig, + private usedColors: Set) { + this.highlight = debounce(() => { + this.doHighlight().logError() + }, global.hasOwnProperty('__TEST__') ? 10 : 300) + this.highlight() + } + + public get enabled(): boolean { + let { filetypes } = this.config + let doc = workspace.getDocument(this.bufnr) + if (!doc) return false + if (filetypes.includes('*')) return true + if (!languages.hasProvider('documentColor', doc.textDocument)) return false + return filetypes.includes(doc.filetype) + } + + public onChange(): void { + this.cancel() + this.highlight() + } + + public get buffer(): Buffer { + return this.nvim.createBuffer(this.bufnr) + } + + public get colors(): ColorInformation[] { + return this._colors + } + + public hasColor(): boolean { + return this._colors.length > 0 + } + + public async doHighlight(): Promise { + if (!this.enabled) return + let { nvim } = this + let doc = workspace.getDocument(this.bufnr) + this.tokenSource = new CancellationTokenSource() + let { token } = this.tokenSource + let colors: ColorInformation[] + colors = await languages.provideDocumentColors(doc.textDocument, token) + if (token.isCancellationRequested) return + colors = colors || [] + colors.sort((a, b) => comparePosition(a.range.start, b.range.start)) + this._colors = colors + let items: HighlightItem[] = [] + colors.forEach(o => { + let hlGroup = getHighlightGroup(o.color) + doc.addHighlights(items, hlGroup, o.range, { combine: false }) + }) + let diff = await window.diffHighlights(this.bufnr, NAMESPACE, items) + if (token.isCancellationRequested || !diff) return + nvim.pauseNotification() + this.defineColors(colors) + nvim.resumeNotification(false, true) + await window.applyDiffHighlights(this.bufnr, NAMESPACE, this.config.highlightPriority, diff, true) + } + + private defineColors(colors: ColorInformation[]): void { + for (let color of colors) { + let hex = toHexString(color.color) + if (!this.usedColors.has(hex)) { + this.nvim.command(`hi BG${hex} guibg=#${hex} guifg=#${isDark(color.color) ? 'ffffff' : '000000'}`, true) + this.usedColors.add(hex) + } + } + } + + public hasColorAtPosition(position: Position): boolean { + return this.colors.some(o => positionInRange(position, o.range) == 0) + } + + public clearHighlight(): void { + this.highlight.clear() + this._colors = [] + this.buffer.clearNamespace('color') + } + + public cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public dispose(): void { + this._colors = [] + this.highlight.clear() + this.cancel() + } +} + +function getHighlightGroup(color: Color): string { + return `BG${toHexString(color)}` +} diff --git a/sources_non_forked/coc.nvim/src/handler/colors/index.ts b/sources_non_forked/coc.nvim/src/handler/colors/index.ts new file mode 100644 index 00000000..63899116 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/colors/index.ts @@ -0,0 +1,144 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, ColorInformation, Disposable, Position } from 'vscode-languageserver-protocol' +import commandManager from '../../commands' +import extensions from '../../extensions' +import languages from '../../languages' +import BufferSync from '../../model/bufferSync' +import { ConfigurationChangeEvent, HandlerDelegate } from '../../types' +import { disposeAll } from '../../util' +import { toHexString } from '../../util/color' +import window from '../../window' +import workspace from '../../workspace' +import ColorBuffer, { ColorConfig } from './colorBuffer' +const logger = require('../../util/logger')('colors-index') + +export default class Colors { + private config: ColorConfig + private disposables: Disposable[] = [] + private highlighters: BufferSync + + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.setConfiguration() + let usedColors: Set = new Set() + this.highlighters = workspace.registerBufferSync(doc => { + return new ColorBuffer(this.nvim, doc.bufnr, this.config, usedColors) + }) + extensions.onDidActiveExtension(() => { + this.highlightAll() + }, null, this.disposables) + workspace.onDidChangeConfiguration(this.setConfiguration, this, this.disposables) + this.disposables.push(commandManager.registerCommand('editor.action.pickColor', () => { + return this.pickColor() + })) + commandManager.titles.set('editor.action.pickColor', 'pick color from system color picker when possible.') + this.disposables.push(commandManager.registerCommand('editor.action.colorPresentation', () => { + return this.pickPresentation() + })) + commandManager.titles.set('editor.action.colorPresentation', 'change color presentation.') + } + + private setConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('colors')) { + let c = workspace.getConfiguration('colors') + this.config = Object.assign(this.config || {}, { + filetypes: c.get('filetypes', []), + highlightPriority: c.get('highlightPriority', 1000) + }) + } + } + + public async pickPresentation(): Promise { + let { doc } = await this.handler.getCurrentState() + this.handler.checkProvier('documentColor', doc.textDocument) + let info = await this.getColorInformation(doc.bufnr) + if (!info) return window.showMessage('Color not found at current position', 'warning') + let tokenSource = new CancellationTokenSource() + let presentations = await languages.provideColorPresentations(info, doc.textDocument, tokenSource.token) + if (!presentations?.length) return + let res = await window.showMenuPicker(presentations.map(o => o.label), 'choose color:') + if (res == -1) return + let presentation = presentations[res] + let { textEdit, additionalTextEdits, label } = presentation + if (!textEdit) textEdit = { range: info.range, newText: label } + await doc.applyEdits([textEdit]) + if (additionalTextEdits) { + await doc.applyEdits(additionalTextEdits) + } + } + + public async pickColor(): Promise { + let { doc } = await this.handler.getCurrentState() + this.handler.checkProvier('documentColor', doc.textDocument) + let info = await this.getColorInformation(doc.bufnr) + if (!info) return window.showMessage('Color not found at current position', 'warning') + let { color } = info + let colorArr = [(color.red * 255).toFixed(0), (color.green * 255).toFixed(0), (color.blue * 255).toFixed(0)] + let res = await this.nvim.call('coc#color#pick_color', [colorArr]) + if (!res) return + let hex = toHexString({ + red: (res[0] / 65535), + green: (res[1] / 65535), + blue: (res[2] / 65535), + alpha: 1 + }) + await doc.applyEdits([{ + range: info.range, + newText: `#${hex}` + }]) + } + + public isEnabled(bufnr: number): boolean { + let highlighter = this.highlighters.getItem(bufnr) + return highlighter != null && highlighter.enabled === true + } + + public clearHighlight(bufnr: number): void { + let highlighter = this.highlighters.getItem(bufnr) + if (highlighter) highlighter.clearHighlight() + } + + public hasColor(bufnr: number): boolean { + let highlighter = this.highlighters.getItem(bufnr) + if (!highlighter) return false + return highlighter.hasColor() + } + + public hasColorAtPosition(bufnr: number, position: Position): boolean { + let highlighter = this.highlighters.getItem(bufnr) + if (!highlighter) return false + return highlighter.hasColorAtPosition(position) + } + + public highlightAll(): void { + for (let buf of this.highlighters.items) { + buf.highlight() + } + } + + public async doHighlight(bufnr: number): Promise { + let highlighter = this.highlighters.getItem(bufnr) + if (highlighter) await highlighter.doHighlight() + } + + public async getColorInformation(bufnr: number): Promise { + let highlighter = this.highlighters.getItem(bufnr) + if (!highlighter) return null + let position = await window.getCursorPosition() + for (let info of highlighter.colors) { + let { range } = info + let { start, end } = range + if (position.line == start.line + && position.character >= start.character + && position.character <= end.character) { + return info + } + } + return null + } + + public dispose(): void { + this.highlighters.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/commands.ts b/sources_non_forked/coc.nvim/src/handler/commands.ts new file mode 100644 index 00000000..0fd9c99f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/commands.ts @@ -0,0 +1,54 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import commandManager from '../commands' +import listManager from '../list/manager' +import { Env } from '../types' +const logger = require('../util/logger')('handler-commands') + +interface CommandItem { + id: string + title: string +} + +export default class Commands { + constructor(private nvim: Neovim, private env: Readonly) { + for (let item of env.vimCommands) { + this.addVimCommand(item) + } + } + + public addVimCommand(cmd: { id: string; cmd: string; title?: string }): void { + let id = `vim.${cmd.id}` + commandManager.registerCommand(id, () => { + this.nvim.command(cmd.cmd, true) + this.nvim.redrawVim() + }) + if (cmd.title) commandManager.titles.set(id, cmd.title) + } + + public getCommandList(): string[] { + return commandManager.commandList.map(o => o.id) + } + + public async repeat(): Promise { + await commandManager.repeatCommand() + } + + public async runCommand(id?: string, ...args: any[]): Promise { + if (id) return await commandManager.fireCommand(id, ...args) + await listManager.start(['commands']) + } + + public getCommands(): CommandItem[] { + let list = commandManager.commandList + let res: CommandItem[] = [] + let { titles } = commandManager + for (let item of list) { + res.push({ + id: item.id, + title: titles.get(item.id) || '' + }) + } + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/fold.ts b/sources_non_forked/coc.nvim/src/handler/fold.ts new file mode 100644 index 00000000..8248f144 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/fold.ts @@ -0,0 +1,35 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import languages from '../languages' +import { HandlerDelegate } from '../types' + +export default class FoldHandler { + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + } + + public async fold(kind?: string | 'comment' | 'region'): Promise { + let { doc, winid } = await this.handler.getCurrentState() + this.handler.checkProvier('foldingRange', doc.textDocument) + await doc.synchronize() + let win = this.nvim.createWindow(winid) + let foldlevel = await this.nvim.eval('&foldlevel') as number + let ranges = await this.handler.withRequestToken('foldingrange', token => { + return languages.provideFoldingRanges(doc.textDocument, {}, token) + }, true) + if (!ranges || !ranges.length) return false + if (kind) ranges = ranges.filter(o => o.kind == kind) + ranges.sort((a, b) => b.startLine - a.startLine) + this.nvim.pauseNotification() + win.setOption('foldmethod', 'manual', true) + this.nvim.command('normal! zE', true) + for (let range of ranges) { + let { startLine, endLine } = range + let cmd = `${startLine + 1}, ${endLine + 1}fold` + this.nvim.command(cmd, true) + } + win.setOption('foldenable', true, true) + win.setOption('foldlevel', foldlevel, true) + await this.nvim.resumeNotification(true) + return true + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/format.ts b/sources_non_forked/coc.nvim/src/handler/format.ts new file mode 100644 index 00000000..ad0cc4e6 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/format.ts @@ -0,0 +1,212 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import commandManager from '../commands' +import events from '../events' +import languages from '../languages' +import Document from '../model/document' +import snippetManager from '../snippets/manager' +import { ConfigurationChangeEvent, HandlerDelegate } from '../types' +import { isWord } from '../util/string' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-format') + +const pairs: Map = new Map([ + ['<', '>'], + ['>', '<'], + ['{', '}'], + ['[', ']'], + ['(', ')'], +]) + +interface FormatPreferences { + formatOnType: boolean + formatOnTypeFiletypes: string[] + formatOnSaveFiletypes: string[] + bracketEnterImprove: boolean +} + +export default class FormatHandler { + private preferences: FormatPreferences + constructor( + private nvim: Neovim, + private handler: HandlerDelegate + ) { + this.loadPreferences() + handler.addDisposable(workspace.onDidChangeConfiguration(this.loadPreferences, this)) + handler.addDisposable(workspace.onWillSaveTextDocument(event => { + let { languageId } = event.document + let filetypes = this.preferences.formatOnSaveFiletypes + if (filetypes.includes(languageId) || filetypes.includes('*')) { + let willSaveWaitUntil = async (): Promise => { + if (!languages.hasFormatProvider(event.document)) { + logger.warn(`Format provider not found for ${event.document.uri}`) + return undefined + } + let options = await workspace.getFormatOptions(event.document.uri) + let tokenSource = new CancellationTokenSource() + let timer: NodeJS.Timer + const tp = new Promise(c => { + timer = setTimeout(() => { + logger.warn(`Format on save ${event.document.uri} timeout after 0.5s`) + tokenSource.cancel() + c(undefined) + }, 500) + }) + const provideEdits = languages.provideDocumentFormattingEdits(event.document, options, tokenSource.token) + let textEdits = await Promise.race([tp, provideEdits]) + clearTimeout(timer) + return Array.isArray(textEdits) ? textEdits : undefined + } + event.waitUntil(willSaveWaitUntil()) + } + })) + let enterTs: number + let enterBufnr: number + handler.addDisposable(events.on('Enter', async bufnr => { + enterTs = Date.now() + enterBufnr = bufnr + })) + handler.addDisposable(events.on('CursorMovedI', async bufnr => { + if (bufnr == enterBufnr && Date.now() - enterTs < 100) { + enterBufnr = undefined + await this.handleEnter(bufnr) + } + })) + handler.addDisposable(events.on('TextInsert', async (bufnr: number, info, character: string) => { + if (!events.pumvisible) await this.tryFormatOnType(character, bufnr) + })) + handler.addDisposable(commandManager.registerCommand('editor.action.formatDocument', async (uri?: string | number) => { + const doc = uri ? workspace.getDocument(uri) : (await this.handler.getCurrentState()).doc + await this.documentFormat(doc) + })) + commandManager.titles.set('editor.action.formatDocument', 'Format Document') + } + + private loadPreferences(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('coc.preferences')) { + let config = workspace.getConfiguration('coc.preferences') + this.preferences = { + formatOnType: config.get('formatOnType', false), + formatOnSaveFiletypes: config.get('formatOnSaveFiletypes', []), + formatOnTypeFiletypes: config.get('formatOnTypeFiletypes', []), + bracketEnterImprove: config.get('bracketEnterImprove', true), + } + } + } + + private async tryFormatOnType(ch: string, bufnr: number, newLine = false): Promise { + if (!ch || isWord(ch) || !this.preferences.formatOnType) return + if (snippetManager.getSession(bufnr) != null) return + let doc = workspace.getDocument(bufnr) + if (!doc || !doc.attached || doc.isCommandLine) return + const filetypes = this.preferences.formatOnTypeFiletypes + if (filetypes.length && !filetypes.includes(doc.filetype) && !filetypes.includes('*')) { + // Only check formatOnTypeFiletypes when set, avoid breaking change + return + } + if (!languages.hasProvider('formatOnType', doc.textDocument)) { + logger.warn(`Format on type provider not found for buffer: ${doc.uri}`) + return + } + if (!languages.canFormatOnType(ch, doc.textDocument)) return + let position: Position + let edits = await this.handler.withRequestToken('Format on type', async token => { + position = await window.getCursorPosition() + let origLine = doc.getline(position.line - 1) + // not format for empty line. + if (newLine && /^\s*$/.test(origLine)) return + await doc.synchronize() + return await languages.provideDocumentOnTypeEdits(ch, doc.textDocument, position, token) + }) + if (!edits || !edits.length) return + await doc.applyEdits(edits, false, true) + } + + public async formatCurrentBuffer(): Promise { + let { doc } = await this.handler.getCurrentState() + return await this.documentFormat(doc) + } + + public async formatCurrentRange(mode: string): Promise { + let { doc } = await this.handler.getCurrentState() + return await this.documentRangeFormat(doc, mode) + } + + public async documentFormat(doc: Document): Promise { + await doc.synchronize() + if (!languages.hasFormatProvider(doc.textDocument)) { + throw new Error(`Format provider not found for buffer: ${doc.bufnr}`) + } + let options = await workspace.getFormatOptions(doc.uri) + let textEdits = await this.handler.withRequestToken('format', token => { + return languages.provideDocumentFormattingEdits(doc.textDocument, options, token) + }) + if (textEdits && textEdits.length > 0) { + await doc.applyEdits(textEdits, false, true) + return true + } + return false + } + + private async handleEnter(bufnr: number): Promise { + let { nvim } = this + let { bracketEnterImprove } = this.preferences + await this.tryFormatOnType('\n', bufnr) + if (bracketEnterImprove) { + let line = (await nvim.call('line', '.') as number) - 1 + let doc = workspace.getDocument(bufnr) + if (!doc) return + await doc.patchChange() + let pre = doc.getline(line - 1) + let curr = doc.getline(line) + let prevChar = pre[pre.length - 1] + if (prevChar && pairs.has(prevChar)) { + let nextChar = curr.trim()[0] + if (nextChar && pairs.get(prevChar) == nextChar) { + let edits: TextEdit[] = [] + let opts = await workspace.getFormatOptions(doc.uri) + let space = opts.insertSpaces ? ' '.repeat(opts.tabSize) : '\t' + let currIndent = curr.match(/^\s*/)[0] + let pos: Position = Position.create(line - 1, pre.length) + // make sure indent of current line + if (doc.filetype == 'vim') { + let newText = '\n' + currIndent + space + edits.push({ range: Range.create(line, currIndent.length, line, currIndent.length), newText: ' \\ ' }) + newText = newText + '\\ ' + edits.push({ range: Range.create(pos, pos), newText }) + await doc.applyEdits(edits) + await window.moveTo(Position.create(line, newText.length - 1)) + } else { + await nvim.eval(`feedkeys("\\O", 'in')`) + } + } + } + } + } + + public async documentRangeFormat(doc: Document, mode?: string): Promise { + this.handler.checkProvier('formatRange', doc.textDocument) + await doc.synchronize() + let range: Range + if (mode) { + range = await window.getSelectedRange(mode) + if (!range) return -1 + } else { + let [lnum, count, mode] = await this.nvim.eval("[v:lnum,v:count,mode()]") as [number, number, string] + // we can't handle + if (count == 0 || mode == 'i' || mode == 'R') return -1 + range = Range.create(lnum - 1, 0, lnum - 1 + count, 0) + } + let options = await workspace.getFormatOptions(doc.uri) + let textEdits = await this.handler.withRequestToken('Format range', token => { + return languages.provideDocumentRangeFormattingEdits(doc.textDocument, range, options, token) + }) + if (textEdits && textEdits.length > 0) { + await doc.applyEdits(textEdits, false, true) + return 0 + } + return -1 + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/highlights.ts b/sources_non_forked/coc.nvim/src/handler/highlights.ts new file mode 100644 index 00000000..6d8b14e1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/highlights.ts @@ -0,0 +1,132 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, DocumentHighlight, DocumentHighlightKind, Position, Range } from 'vscode-languageserver-protocol' +import events from '../events' +import languages from '../languages' +import Document from '../model/document' +import { ConfigurationChangeEvent, HandlerDelegate } from '../types' +import { disposeAll } from '../util' +import workspace from '../workspace' +const logger = require('../util/logger')('documentHighlight') + +interface HighlightConfig { + priority: number + timeout: number +} + +/** + * Highlight same symbols on current window. + * Highlights are added to window by matchaddpos. + */ +export default class Highlights { + private config: HighlightConfig + private disposables: Disposable[] = [] + private tokenSource: CancellationTokenSource + private highlights: Map = new Map() + private timer: NodeJS.Timer + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + events.on(['CursorMoved', 'CursorMovedI'], () => { + this.cancel() + this.clearHighlights() + }, null, this.disposables) + this.getConfiguration() + workspace.onDidChangeConfiguration(this.getConfiguration, this, this.disposables) + } + + private getConfiguration(e?: ConfigurationChangeEvent): void { + let config = workspace.getConfiguration('documentHighlight') + if (!e || e.affectsConfiguration('documentHighlight')) { + this.config = Object.assign(this.config || {}, { + priority: config.get('priority', -1), + timeout: config.get('timeout', 300) + }) + } + } + + public isEnabled(bufnr: number, cursors: number): boolean { + let doc = workspace.getDocument(bufnr) + if (!doc || !doc.attached || cursors) return false + if (!languages.hasProvider('documentHighlight', doc.textDocument)) return false + return true + } + + public clearHighlights(): void { + if (this.highlights.size == 0) return + for (let winid of this.highlights.keys()) { + let win = this.nvim.createWindow(winid) + win.clearMatchGroup('^CocHighlight') + } + this.highlights.clear() + } + + public async highlight(): Promise { + let { nvim } = this + this.cancel() + let [bufnr, winid, pos, cursors] = await nvim.eval(`[bufnr("%"),win_getid(),coc#cursor#position(),get(b:,'coc_cursors_activated',0)]`) as [number, number, [number, number], number] + if (!this.isEnabled(bufnr, cursors)) return + let doc = workspace.getDocument(bufnr) + let highlights = await this.getHighlights(doc, Position.create(pos[0], pos[1])) + if (!highlights) return + let groups: { [index: string]: Range[] } = {} + for (let hl of highlights) { + if (!hl.range) continue + let hlGroup = hl.kind == DocumentHighlightKind.Text + ? 'CocHighlightText' + : hl.kind == DocumentHighlightKind.Read ? 'CocHighlightRead' : 'CocHighlightWrite' + groups[hlGroup] = groups[hlGroup] || [] + groups[hlGroup].push(hl.range) + } + let win = nvim.createWindow(winid) + nvim.pauseNotification() + win.clearMatchGroup('^CocHighlight') + for (let hlGroup of Object.keys(groups)) { + win.highlightRanges(hlGroup, groups[hlGroup], this.config.priority, true) + } + nvim.resumeNotification(true, true) + this.highlights.set(winid, highlights) + } + + public async getSymbolsRanges(): Promise { + let { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('documentHighlight', doc.textDocument) + let highlights = await this.getHighlights(doc, position) + if (!highlights) return null + return highlights.map(o => o.range) + } + + public hasHighlights(winid: number): boolean { + return this.highlights.get(winid) != null + } + + public async getHighlights(doc: Document, position: Position): Promise { + let line = doc.getline(position.line) + let ch = line[position.character] + if (!ch || !doc.isWord(ch)) return null + await doc.synchronize() + this.cancel() + let source = this.tokenSource = new CancellationTokenSource() + let timer = this.timer = setTimeout(() => { + if (source.token.isCancellationRequested) return + source.cancel() + }, this.config.timeout) + let highlights = await languages.getDocumentHighLight(doc.textDocument, position, source.token) + clearTimeout(timer) + if (source.token.isCancellationRequested) return null + return highlights + } + + private cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public dispose(): void { + if (this.timer) clearTimeout(this.timer) + this.cancel() + this.highlights.clear() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/hover.ts b/sources_non_forked/coc.nvim/src/handler/hover.ts new file mode 100644 index 00000000..9679be11 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/hover.ts @@ -0,0 +1,245 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import { CancellationTokenSource, Disposable, Hover, MarkedString, MarkupContent, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import languages from '../languages' +import { Documentation } from '../types' +import FloatFactory from '../model/floatFactory' +import { TextDocumentContentProvider } from '../provider' +import { ConfigurationChangeEvent, FloatConfig, HandlerDelegate } from '../types' +import { disposeAll, isMarkdown } from '../util' +import { readFileLines } from '../util/fs' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-hover') + +export type HoverTarget = 'float' | 'preview' | 'echo' + +interface HoverConfig { + target: HoverTarget + floatConfig: FloatConfig + previewMaxHeight: number + autoHide: boolean +} + +export default class HoverHandler { + private hoverFactory: FloatFactory + private disposables: Disposable[] = [] + private documentLines: string[] = [] + private config: HoverConfig + private timer: NodeJS.Timeout + private hasProvider = false + private excludeImages = true + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.loadConfiguration() + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + this.hoverFactory = new FloatFactory(nvim) + this.disposables.push(this.hoverFactory) + } + + private registerProvider(): void { + if (this.hasProvider) return + this.hasProvider = true + let { nvim } = this + let provider: TextDocumentContentProvider = { + onDidChange: null, + provideTextDocumentContent: async () => { + nvim.pauseNotification() + nvim.command('setlocal conceallevel=2 nospell nofoldenable wrap', true) + nvim.command('setlocal bufhidden=wipe nobuflisted', true) + nvim.command('setfiletype markdown', true) + nvim.command(`if winnr('j') != winnr('k') | exe "normal! z${Math.min(this.documentLines.length, this.config.previewMaxHeight)}\\ | endif"`, true) + await nvim.resumeNotification() + return this.documentLines.join('\n') + } + } + this.disposables.push(workspace.registerTextDocumentContentProvider('coc', provider)) + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('hover')) { + let config = workspace.getConfiguration('hover') + let target = config.get('target', 'float') + this.config = { + floatConfig: config.get('floatConfig', {}), + autoHide: config.get('autoHide', true), + target: target == 'float' && !workspace.floatSupported ? 'preview' : target, + previewMaxHeight: config.get('previewMaxHeight', 12) + } + if (this.config.target == 'preview') { + this.registerProvider() + } + let preferences = workspace.getConfiguration('coc.preferences') + this.excludeImages = preferences.get('excludeImageLinksInMarkdownDocument', true) + } + } + + public async onHover(hoverTarget?: HoverTarget): Promise { + let { doc, position, winid } = await this.handler.getCurrentState() + if (hoverTarget == 'preview') this.registerProvider() + this.handler.checkProvier('hover', doc.textDocument) + await doc.synchronize() + let hovers = await this.handler.withRequestToken('hover', token => { + return languages.getHover(doc.textDocument, position, token) + }, true) + if (hovers == null || !hovers.length) return false + let hover = hovers.find(o => Range.is(o.range)) + if (hover?.range) { + let win = this.nvim.createWindow(winid) + win.highlightRanges('CocHoverRange', [hover.range], 99, true) + this.timer = setTimeout(() => { + win.clearMatchGroup('CocHoverRange') + this.nvim.redrawVim() + }, 500) + } + await this.previewHover(hovers, hoverTarget) + return true + } + + public async definitionHover(hoverTarget: HoverTarget): Promise { + const { doc, position, winid } = await this.handler.getCurrentState() + if (hoverTarget == 'preview') this.registerProvider() + this.handler.checkProvier('hover', doc.textDocument) + await doc.synchronize() + const hovers: (Hover | Documentation)[] = await this.handler.withRequestToken('hover', token => { + return languages.getHover(doc.textDocument, position, token) + }, true) + if (!hovers?.length) return false + const defs = await this.handler.withRequestToken('definitionHover', token => { + return languages.getDefinitionLinks(doc.textDocument, position, token) + }, false) + if (defs?.length) { + for (const def of defs) { + if (!def.targetRange) continue + const { start, end } = def.targetRange + const endLine = end.line - start.line >= 100 ? start.line + 100 : (end.character == 0 ? end.line - 1 : end.line) + let lines = await readLines(def.targetUri, start.line, endLine) + if (lines.length) { + let indent = lines[0].match(/^\s*/)[0] + if (indent) lines = lines.map(l => l.startsWith(indent) ? l.substring(indent.length) : l) + hovers.push({ content: lines.join('\n'), filetype: doc.filetype }) + } + } + } + let hover = hovers.find(o => Hover.is(o) && Range.is(o.range)) as Hover + if (hover?.range) { + let win = this.nvim.createWindow(winid) + win.highlightRanges('CocHoverRange', [hover.range], 99, true) + this.timer = setTimeout(() => { + win.clearMatchGroup('CocHoverRange') + this.nvim.redrawVim() + }, 500) + } + await this.previewHover(hovers, hoverTarget) + return true + } + + private async previewHover(hovers: (Hover | Documentation)[], target?: string): Promise { + let docs: Documentation[] = [] + target = target || this.config.target + let isPreview = target === 'preview' + for (let hover of hovers) { + if (isDocumentation(hover)) { + docs.push(hover) + continue + } + let { contents } = hover + if (Array.isArray(contents)) { + for (let item of contents) { + if (typeof item === 'string') { + addDocument(docs, item, 'markdown', isPreview) + } else { + addDocument(docs, item.value, item.language, isPreview) + } + } + } else if (MarkedString.is(contents)) { + if (typeof contents == 'string') { + addDocument(docs, contents, 'markdown', isPreview) + } else { + addDocument(docs, contents.value, contents.language, isPreview) + } + } else if (MarkupContent.is(contents)) { + addDocument(docs, contents.value, isMarkdown(contents) ? 'markdown' : 'txt', isPreview) + } + } + if (target == 'float') { + let config = this.hoverFactory.applyFloatConfig({ + modes: ['n'], + autoHide: this.config.autoHide, + excludeImages: this.excludeImages, + maxWidth: 80, + }, this.config.floatConfig) + await this.hoverFactory.show(docs, config) + return + } + let lines = docs.reduce((p, c) => { + let arr = c.content.split(/\r?\n/) + if (p.length > 0) p.push('') + p.push(...arr) + return p + }, []) + if (target == 'echo') { + const msg = lines.join('\n').trim() + await this.nvim.call('coc#ui#echo_hover', [msg]) + } else { + this.documentLines = lines + await this.nvim.command(`noswapfile pedit coc://document`) + } + } + + /** + * Get hover text array + */ + public async getHover(): Promise { + let result: string[] = [] + let { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('hover', doc.textDocument) + await doc.synchronize() + let tokenSource = new CancellationTokenSource() + let hovers = await languages.getHover(doc.textDocument, position, tokenSource.token) + if (Array.isArray(hovers)) { + for (let h of hovers) { + let { contents } = h + if (Array.isArray(contents)) { + contents.forEach(c => { + result.push(typeof c === 'string' ? c : c.value) + }) + } else if (MarkupContent.is(contents)) { + result.push(contents.value) + } else { + result.push(typeof contents === 'string' ? contents : contents.value) + } + } + } + result = result.filter(s => s != null && s.length > 0) + return result + } + + public dispose(): void { + if (this.timer) clearTimeout(this.timer) + disposeAll(this.disposables) + } +} + +function addDocument(docs: Documentation[], text: string, filetype: string, isPreview = false): void { + let content = text.trim() + if (!content.length) + return + if (isPreview && filetype !== 'markdown') { + content = '``` ' + filetype + '\n' + content + '\n```' + } + docs.push({ content, filetype }) +} + +function isDocumentation(obj: any): obj is Documentation { + if (!obj) return false + return typeof obj.filetype === 'string' && typeof obj.content === 'string' +} + +async function readLines(uri: string, start: number, end: number): Promise { + let doc = workspace.getDocument(uri) + if (doc) return doc.getLines(start, end + 1) + let fsPath = URI.parse(uri).fsPath + if (!fs.existsSync(fsPath)) return [] + return await readFileLines(fsPath, start, end) +} diff --git a/sources_non_forked/coc.nvim/src/handler/index.ts b/sources_non_forked/coc.nvim/src/handler/index.ts new file mode 100644 index 00000000..c76d478e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/index.ts @@ -0,0 +1,218 @@ +'use strict' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import { CancellationToken, CancellationTokenSource, CodeActionKind, Disposable, Position, Range, SymbolKind } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import events from '../events' +import languages from '../languages' +import Document from '../model/document' +import { StatusBarItem } from '../model/status' +import { ExtendedCodeAction, ProviderName } from '../types' +import { disposeAll } from '../util' +import window from '../window' +import workspace from '../workspace' +import CodeActions from './codeActions' +import CodeLens from './codelens/index' +import Colors from './colors/index' +import Commands from './commands' +import Fold from './fold' +import Format from './format' +import Highlights from './highlights' +import HoverHandler from './hover' +import Links from './links' +import Locations from './locations' +import Refactor from './refactor/index' +import Rename from './rename' +import WorkspaceHandler from './workspace' +import SelectionRange from './selectionRange' +import CallHierarchy from './callHierarchy' +import SemanticTokens from './semanticTokens/index' +import Signature from './signature' +import Symbols from './symbols/index' +import { HandlerDelegate } from '../types' +import { getSymbolKind } from '../util/convert' +import LinkedEditingHandler from './linkedEditing' +import InlayHintHandler from './inlayHint/index' +const logger = require('../util/logger')('Handler') + +export interface CurrentState { + doc: Document + winid: number + position: Position + // :h mode() + mode: string +} + +export default class Handler implements HandlerDelegate { + public readonly documentHighlighter: Highlights + public readonly colors: Colors + public readonly signature: Signature + public readonly locations: Locations + public readonly symbols: Symbols + public readonly refactor: Refactor + public readonly codeActions: CodeActions + public readonly format: Format + public readonly hover: HoverHandler + public readonly codeLens: CodeLens + public readonly commands: Commands + public readonly links: Links + public readonly rename: Rename + public readonly fold: Fold + public readonly selectionRange: SelectionRange + public readonly callHierarchy: CallHierarchy + public readonly semanticHighlighter: SemanticTokens + public readonly workspace: WorkspaceHandler + public readonly linkedEditingHandler: LinkedEditingHandler + public readonly inlayHintHandler: InlayHintHandler + private labels: { [key: string]: string } + private requestStatusItem: StatusBarItem + private requestTokenSource: CancellationTokenSource | undefined + private requestTimer: NodeJS.Timer + private disposables: Disposable[] = [] + + constructor(private nvim: Neovim) { + this.requestStatusItem = window.createStatusBarItem(0, { progress: true }) + events.on(['CursorMoved', 'CursorMovedI', 'InsertEnter', 'InsertSnippet', 'InsertLeave'], () => { + if (this.requestTokenSource) { + this.requestTokenSource.cancel() + this.requestTokenSource = null + } + }, null, this.disposables) + this.labels = workspace.getConfiguration('suggest').get('completionItemKindLabels', {}) + this.fold = new Fold(nvim, this) + this.links = new Links(nvim, this) + this.codeLens = new CodeLens(nvim) + this.colors = new Colors(nvim, this) + this.format = new Format(nvim, this) + this.symbols = new Symbols(nvim, this) + this.refactor = new Refactor(nvim, this) + this.hover = new HoverHandler(nvim, this) + this.locations = new Locations(nvim, this) + this.signature = new Signature(nvim, this) + this.rename = new Rename(nvim, this) + this.workspace = new WorkspaceHandler(nvim, this) + this.codeActions = new CodeActions(nvim, this) + this.commands = new Commands(nvim, workspace.env) + this.callHierarchy = new CallHierarchy(nvim, this) + this.documentHighlighter = new Highlights(nvim, this) + this.semanticHighlighter = new SemanticTokens(nvim, this) + this.selectionRange = new SelectionRange(nvim, this) + this.linkedEditingHandler = new LinkedEditingHandler(nvim, this) + this.inlayHintHandler = new InlayHintHandler(nvim, this) + this.disposables.push({ + dispose: () => { + this.callHierarchy.dispose() + this.codeLens.dispose() + this.links.dispose() + this.refactor.dispose() + this.signature.dispose() + this.symbols.dispose() + this.hover.dispose() + this.locations.dispose() + this.colors.dispose() + this.documentHighlighter.dispose() + this.semanticHighlighter.dispose() + } + }) + void this.refactor.init() + } + + public async getCurrentState(): Promise { + let { nvim } = this + let [bufnr, [line, character], winid, mode] = await nvim.eval("[bufnr('%'),coc#cursor#position(),win_getid(),mode()]") as [number, [number, number], number, string] + let doc = workspace.getAttachedDocument(bufnr) + return { + doc, + mode, + position: Position.create(line, character), + winid + } + } + + public addDisposable(disposable: Disposable): void { + this.disposables.push(disposable) + } + + /** + * Throw error when provider doesn't exist. + */ + public checkProvier(id: ProviderName, document: TextDocument): void { + if (!languages.hasProvider(id, document)) { + throw new Error(`${id} provider not found for current buffer, your language server doesn't support it.`) + } + } + + public async withRequestToken(name: string, fn: (token: CancellationToken) => Thenable, checkEmpty?: boolean): Promise { + if (this.requestTokenSource) { + this.requestTokenSource.cancel() + this.requestTokenSource.dispose() + } + if (this.requestTimer) { + clearTimeout(this.requestTimer) + } + let statusItem = this.requestStatusItem + this.requestTokenSource = new CancellationTokenSource() + let { token } = this.requestTokenSource + token.onCancellationRequested(() => { + statusItem.text = `${name} request canceled` + statusItem.isProgress = false + this.requestTimer = setTimeout(() => { + statusItem.hide() + }, 500) + }) + statusItem.isProgress = true + statusItem.text = `requesting ${name}` + statusItem.show() + let res: T + try { + res = await Promise.resolve(fn(token)) + } catch (e) { + this.nvim.echoError(e) + } + if (this.requestTokenSource) { + this.requestTokenSource.dispose() + this.requestTokenSource = undefined + } + if (token.isCancellationRequested) return null + statusItem.hide() + if (checkEmpty && (!res || (Array.isArray(res) && res.length == 0))) { + window.showMessage(`${name} not found`, 'warning') + return null + } + return res + } + + public getIcon(kind: SymbolKind): { text: string, hlGroup: string } { + let { labels } = this + let kindText = getSymbolKind(kind) + let defaultIcon = typeof labels['default'] === 'string' ? labels['default'] : kindText[0].toLowerCase() + let text = kindText == 'Unknown' ? '' : labels[kindText[0].toLowerCase() + kindText.slice(1)] + if (!text || typeof text !== 'string') text = defaultIcon + return { + text, + hlGroup: kindText == 'Unknown' ? 'CocSymbolDefault' : `CocSymbol${kindText}` + } + } + + public async getCodeActions(doc: Document, range?: Range, only?: CodeActionKind[]): Promise { + let codeActions = await this.codeActions.getCodeActions(doc, range, only) + return codeActions.filter(o => !o.disabled) + } + + public async applyCodeAction(action: ExtendedCodeAction): Promise { + await this.codeActions.applyCodeAction(action) + } + + public async hasProvider(id: string): Promise { + let bufnr = await this.nvim.call('bufnr', '%') + let doc = workspace.getDocument(bufnr) + if (!doc) return false + return languages.hasProvider(id as ProviderName, doc.textDocument) + } + + public dispose(): void { + if (this.requestTimer) { + clearTimeout(this.requestTimer) + } + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/inlayHint/buffer.ts b/sources_non_forked/coc.nvim/src/handler/inlayHint/buffer.ts new file mode 100644 index 00000000..c6cb425f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/inlayHint/buffer.ts @@ -0,0 +1,114 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationTokenSource, Emitter, Event, Range } from 'vscode-languageserver-protocol' +import languages from '../../languages' +import { SyncItem } from '../../model/bufferSync' +import Document from '../../model/document' +import Regions from '../../model/regions' +import { getLabel, InlayHintWithProvider } from '../../provider/inlayHintManager' +import { positionInRange } from '../../util/position' + +export interface InlayHintConfig { + srcId?: number +} + +const debounceInterval = global.hasOwnProperty('__TEST__') ? 10 : 100 +const highlightGroup = 'CocInlayHint' + +export default class InlayHintBuffer implements SyncItem { + private tokenSource: CancellationTokenSource + private regions = new Regions() + // Saved for resolve and TextEdits in the future. + private currentHints: InlayHintWithProvider[] = [] + private readonly _onDidRefresh = new Emitter() + public readonly onDidRefresh: Event = this._onDidRefresh.event + public render: Function & { clear(): void } + constructor( + private readonly nvim: Neovim, + public readonly doc: Document, + private readonly config: InlayHintConfig + ) { + this.render = debounce(() => { + void this.renderRange() + }, debounceInterval) + this.render() + } + + public get current(): ReadonlyArray { + return this.currentHints + } + + public clearCache(): void { + this.currentHints = [] + this.regions.clear() + this.render.clear() + } + + public onChange(): void { + this.clearCache() + this.cancel() + this.render() + } + + public cancel(): void { + this.render.clear() + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource = null + } + } + + public async renderRange(): Promise { + this.cancel() + if (!languages.hasProvider('inlayHint', this.doc.textDocument)) return + this.tokenSource = new CancellationTokenSource() + let token = this.tokenSource.token + let res = await this.nvim.call('coc#window#visible_range', [this.doc.bufnr]) as [number, number] + if (res == null || this.doc.dirty || token.isCancellationRequested) return + if (this.regions.has(res[0], res[1])) return + let range = Range.create(res[0] - 1, 0, res[1], 0) + let inlayHints = await languages.provideInlayHints(this.doc.textDocument, range, token) + if (inlayHints == null || token.isCancellationRequested) return + this.regions.add(res[0], res[1]) + this.currentHints = this.currentHints.filter(o => positionInRange(o.position, range) !== 0) + this.currentHints.push(...inlayHints) + this.setVirtualText(range, inlayHints) + } + + private setVirtualText(range: Range, inlayHints: InlayHintWithProvider[]): void { + let { nvim, doc } = this + let srcId = this.config.srcId + let buffer = doc.buffer + const chunksMap = {} + for (const item of inlayHints) { + const chunks: [[string, string]] = [[getLabel(item), highlightGroup]] + if (chunksMap[item.position.line] === undefined) { + chunksMap[item.position.line] = chunks + } else { + chunksMap[item.position.line].push([' ', 'Normal']) + chunksMap[item.position.line].push(chunks[0]) + } + } + nvim.pauseNotification() + buffer.clearNamespace(srcId, range.start.line, range.end.line + 1) + for (let key of Object.keys(chunksMap)) { + buffer.setExtMark(srcId, Number(key), 0, { + virt_text: chunksMap[key], + virt_text_pos: 'eol', + hl_mode: 'combine' + }) + } + nvim.resumeNotification(false, true) + this._onDidRefresh.fire() + } + + public clearVirtualText(): void { + let srcId = this.config.srcId + this.doc.buffer.clearNamespace(srcId) + } + + public dispose(): void { + this.cancel() + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/inlayHint/index.ts b/sources_non_forked/coc.nvim/src/handler/inlayHint/index.ts new file mode 100644 index 00000000..fcc75417 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/inlayHint/index.ts @@ -0,0 +1,51 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import events from '../../events' +import languages from '../../languages' +import BufferSync from '../../model/bufferSync' +import { HandlerDelegate } from '../../types' +import workspace from '../../workspace' +import InlayHintBuffer, { InlayHintConfig } from './buffer' + +export default class InlayHintHandler { + private config: InlayHintConfig = {} + private buffers: BufferSync | undefined + constructor(nvim: Neovim, handler: HandlerDelegate) { + void nvim.createNamespace('coc-inlayHint').then(id => { + this.config.srcId = id + }) + this.buffers = workspace.registerBufferSync(doc => { + if (!workspace.has('nvim-0.5.0')) return undefined + return new InlayHintBuffer(nvim, doc, this.config) + }) + handler.addDisposable(this.buffers) + handler.addDisposable(languages.onDidInlayHintRefresh(async e => { + for (let item of this.buffers.items) { + if (workspace.match(e, item.doc.textDocument)) { + item.clearCache() + if (languages.hasProvider('inlayHint', item.doc.textDocument)) { + await item.renderRange() + } else { + item.clearVirtualText() + } + } + } + })) + handler.addDisposable(events.on('CursorMoved', bufnr => { + this.refresh(bufnr) + })) + handler.addDisposable(events.on('WinScrolled', async winid => { + let bufnr = await nvim.call('winbufnr', [winid]) + if (bufnr != -1) this.refresh(bufnr) + })) + } + + public getItem(bufnr: number): InlayHintBuffer { + return this.buffers.getItem(bufnr) + } + + public refresh(bufnr: number): void { + let buf = this.buffers.getItem(bufnr) + if (buf) buf.render() + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/linkedEditing.ts b/sources_non_forked/coc.nvim/src/handler/linkedEditing.ts new file mode 100644 index 00000000..08f3d1dc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/linkedEditing.ts @@ -0,0 +1,160 @@ +'use strict' +import { Neovim, Window } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationTokenSource, Position, TextEdit } from 'vscode-languageserver-protocol' +import TextRange from '../cursors/textRange' +import { getBeforeCount, getChange, getDelta } from '../cursors/util' +import events from '../events' +import languages from '../languages' +import Document from '../model/document' +import { DidChangeTextDocumentParams, HandlerDelegate } from '../types' +import { emptyRange, positionInRange, rangeAdjacent, rangeInRange, rangeIntersect } from '../util/position' +import { characterIndex } from '../util/string' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-linkedEditing') + +export default class LinkedEditingHandler { + private changing = false + private window: Window | undefined + private bufnr: number | undefined + private ranges: TextRange[] | undefined + private wordPattern: string | undefined + private tokenSource: CancellationTokenSource | undefined + public checkPosition: ((bufnr: number, cursor: [number, number]) => void) & { clear(): void } + constructor(private nvim: Neovim, handler: HandlerDelegate) { + this.checkPosition = debounce(this._checkPosition, global.__TEST__ ? 10 : 100) + handler.addDisposable(events.on('CursorMoved', (bufnr, cursor) => { + this.cancel() + this.checkPosition(bufnr, cursor) + })) + handler.addDisposable(events.on('CursorMovedI', (bufnr, cursor) => { + this.cancel() + this.checkPosition(bufnr, cursor) + })) + handler.addDisposable(window.onDidChangeActiveTextEditor(() => { + this.cancel() + this.cancelEdit() + })) + handler.addDisposable(events.on('InsertCharPre', (character, bufnr) => { + if (bufnr !== this.bufnr) return + let doc = workspace.getDocument(bufnr) + if (!this.wordPattern) { + if (!doc.isWord(character)) this.cancelEdit() + } else { + let r = new RegExp(this.wordPattern) + if (!r.test(character)) this.cancelEdit() + } + })) + handler.addDisposable(workspace.onDidChangeTextDocument(async e => { + await this.onChange(e) + })) + } + + private cancelEdit(): void { + this.window?.clearMatchGroup('^CocLinkedEditing') + this.ranges = undefined + this.window = undefined + this.bufnr = undefined + } + + public async onChange(e: DidChangeTextDocumentParams): Promise { + if (e.bufnr !== this.bufnr || this.changing || !this.ranges) return + if (e.contentChanges.length === 0) { + this.doHighlights() + return + } + let change = e.contentChanges[0] + let { text, range } = change + let affected = this.ranges.filter(r => { + if (!rangeIntersect(range, r.range)) return false + if (rangeAdjacent(range, r.range)) { + if (text.includes('\n') || !emptyRange(range)) return false + } + return true + }) + if (affected.length == 1 && rangeInRange(range, affected[0].range)) { + if (text.includes('\n')) { + this.cancelEdit() + return + } + logger.debug('affected single range') + // change textRange + await this.applySingleEdit(affected[0], { range, newText: text }) + } else { + this.cancelEdit() + } + } + + private async applySingleEdit(textRange: TextRange, edit: TextEdit): Promise { + // single range change, calculate & apply changes for all ranges + let { bufnr, ranges } = this + let doc = workspace.getDocument(bufnr) + let after = ranges.filter(r => r !== textRange && r.position.line == textRange.position.line) + after.forEach(r => r.adjustFromEdit(edit)) + let change = getChange(textRange, edit.range, edit.newText) + let delta = getDelta(change) + ranges.forEach(r => r.applyChange(change)) + let edits = ranges.filter(r => r !== textRange).map(o => o.textEdit) + // logger.debug('edits:', JSON.stringify(edits, null, 2)) + this.changing = true + await doc.applyEdits(edits, true, true) + this.changing = false + if (delta != 0) { + for (let r of ranges) { + let n = getBeforeCount(r, this.ranges, textRange) + r.move(n * delta) + } + } + this.doHighlights() + } + + private doHighlights(): void { + let { window, ranges } = this + if (window && ranges) { + this.nvim.pauseNotification() + window.clearMatchGroup('^CocLinkedEditing') + window.highlightRanges('CocLinkedEditing', ranges.map(o => o.range), 99, true) + this.nvim.resumeNotification(true, true) + } + } + + private _checkPosition(bufnr: number, cursor: [number, number]): void { + if (events.pumvisible || !workspace.isAttached(bufnr)) return + let doc = workspace.getDocument(bufnr) + let config = workspace.getConfiguration('coc.preferences', doc.uri) + let enabled = config.get('enableLinkedEditing', false) + if (!enabled || !languages.hasProvider('linkedEditing', doc.textDocument)) return + let character = characterIndex(doc.getline(cursor[0] - 1), cursor[1] - 1) + let position = Position.create(cursor[0] - 1, character) + if (this.ranges) { + if (this.ranges.some(r => positionInRange(position, r.range) == 0)) { + return + } + this.cancelEdit() + } + void this.enable(doc, position) + } + + public async enable(doc: Document, position: Position): Promise { + let textDocument = doc.textDocument + let tokenSource = this.tokenSource = new CancellationTokenSource() + let token = tokenSource.token + let window = await this.nvim.window + let linkedRanges = await languages.provideLinkedEdits(textDocument, position, token) + if (token.isCancellationRequested || !linkedRanges || linkedRanges.ranges.length == 0) return + let ranges = linkedRanges.ranges.map(o => new TextRange(o.start.line, o.start.character, textDocument.getText(o))) + this.wordPattern = linkedRanges.wordPattern + this.bufnr = doc.bufnr + this.window = window + this.ranges = ranges + this.doHighlights() + } + + private cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource = null + } + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/links.ts b/sources_non_forked/coc.nvim/src/handler/links.ts new file mode 100644 index 00000000..4b1a5ef0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/links.ts @@ -0,0 +1,122 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, DocumentLink, Range } from 'vscode-languageserver-protocol' +import events from '../events' +import languages from '../languages' +import FloatFactory from '../model/floatFactory' +import { ConfigurationChangeEvent, Documentation, HandlerDelegate } from '../types' +import { disposeAll } from '../util' +import { positionInRange } from '../util/position' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-links') + +const regex = /CocAction(Async)?\(["']openLink["']\)/ +export default class Links implements Disposable { + private floatFactory: FloatFactory | undefined + private disposables: Disposable[] = [] + private _tooltip: boolean + private tokenSource: CancellationTokenSource + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.setConfiguration() + workspace.onDidChangeConfiguration(this.setConfiguration, this, this.disposables) + this.floatFactory = new FloatFactory(nvim) + events.on('CursorHold', async () => { + if (!this._tooltip) return + if (!nvim.hasFunction('nvim_get_keymap')) return + await this.showTooltip() + }, null, this.disposables) + events.on(['CursorMoved', 'InsertEnter'], () => { + this.cancel() + }, null, this.disposables) + } + + private setConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('links')) { + let config = workspace.getConfiguration('links') + this._tooltip = config.get('tooltip', false) + } + } + + public async showTooltip(): Promise { + let { nvim, floatFactory } = this + let obj = await nvim.getKeymap('n') as any[] + let find = obj.find(o => regex.test(o.rhs)) + let key = find ? find.lhs : undefined + let link = await this.getCurrentLink() + if (!link || !link.target) return + let text = '' + if (link.tooltip) text = link.tooltip + ' ' + if (key) text += `Press "${key}" to open link` + if (!text.length) return + let doc: Documentation = { content: text, filetype: 'txt' } + await floatFactory.show([doc], { autoHide: true }) + } + + public async getLinks(): Promise { + try { + let { doc } = await this.handler.getCurrentState() + if (!languages.hasProvider('documentLink', doc.textDocument)) return [] + let tokenSource = this.tokenSource = new CancellationTokenSource() + let links = await languages.getDocumentLinks(doc.textDocument, tokenSource.token) + return tokenSource.token.isCancellationRequested ? [] : links + } catch (_) { + return [] + } + } + + public async openLink(link: DocumentLink): Promise { + if (!link.target) throw new Error(`Failed to resolve link target`) + await workspace.openResource(link.target) + } + + public async getCurrentLink(): Promise { + let links = await this.getLinks() + let pos = await window.getCursorPosition() + if (links && links.length) { + for (let link of links) { + if (positionInRange(pos, link.range) == 0) { + if (!link.target) { + let tokenSource = this.tokenSource = this.tokenSource || new CancellationTokenSource() + link = await languages.resolveDocumentLink(link, this.tokenSource.token) + if (!link.target || tokenSource.token.isCancellationRequested) continue + } + return link + } + } + } + let line = await this.nvim.call('getline', ['.']) + let regex = /\w+?:\/\/[^)\]'" ]+/g + let arr + let link: DocumentLink | undefined + while ((arr = regex.exec(line)) !== null) { + let start = arr.index + if (start <= pos.character && start + arr[0].length >= pos.character) { + link = DocumentLink.create(Range.create(pos.line, start, pos.line, start + arr[0].length), arr[0]) + break + } + } + return link + } + + public async openCurrentLink(): Promise { + let link = await this.getCurrentLink() + if (link) { + await this.openLink(link) + return true + } + return false + } + + private cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource = null + } + } + + public dispose(): void { + this.floatFactory?.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/locations.ts b/sources_non_forked/coc.nvim/src/handler/locations.ts new file mode 100644 index 00000000..86853699 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/locations.ts @@ -0,0 +1,178 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, CancellationTokenSource, Definition, Location, LocationLink, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import languages from '../languages' +import services from '../services' +import { HandlerDelegate, ProviderName } from '../types' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-hover') + +export interface TagDefinition { + name: string + cmd: string + filename: string +} + +export type RequestFunc = (doc: TextDocument, position: Position, token: CancellationToken) => Thenable + +export default class LocationsHandler { + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + } + + private async request(method: ProviderName, fn: RequestFunc): Promise { + let { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier(method, doc.textDocument) + await doc.synchronize() + return await this.handler.withRequestToken(method, token => { + return fn(doc.textDocument, position, token) + }, true) + } + + public async definitions(): Promise { + const { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('definition', doc.textDocument) + await doc.synchronize() + const tokenSource = new CancellationTokenSource() + return languages.getDefinition(doc.textDocument, position, tokenSource.token) + } + + public async declarations(): Promise { + const { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('declaration', doc.textDocument) + await doc.synchronize() + const tokenSource = new CancellationTokenSource() + return languages.getDeclaration(doc.textDocument, position, tokenSource.token) + } + + public async typeDefinitions(): Promise { + const { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('typeDefinition', doc.textDocument) + await doc.synchronize() + const tokenSource = new CancellationTokenSource() + return languages.getTypeDefinition(doc.textDocument, position, tokenSource.token) + } + + public async implementations(): Promise { + const { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('implementation', doc.textDocument) + await doc.synchronize() + const tokenSource = new CancellationTokenSource() + return languages.getImplementation(doc.textDocument, position, tokenSource.token) + } + + public async references(excludeDeclaration?: boolean): Promise { + const { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('reference', doc.textDocument) + await doc.synchronize() + const tokenSource = new CancellationTokenSource() + return languages.getReferences(doc.textDocument, { includeDeclaration: !excludeDeclaration }, position, tokenSource.token) + } + + public async gotoDefinition(openCommand?: string | false): Promise { + let definition = await this.request('definition', (doc, position, token) => { + return languages.getDefinition(doc, position, token) + }) + await this.handleLocations(definition, openCommand) + return definition ? definition.length > 0 : false + } + + public async gotoDeclaration(openCommand?: string | false): Promise { + let definition = await this.request('declaration', (doc, position, token) => { + return languages.getDeclaration(doc, position, token) + }) + await this.handleLocations(definition, openCommand) + return definition ? (Array.isArray(definition) ? definition.length > 0 : true) : false + } + + public async gotoTypeDefinition(openCommand?: string | false): Promise { + let definition = await this.request('typeDefinition', (doc, position, token) => { + return languages.getTypeDefinition(doc, position, token) + }) + await this.handleLocations(definition, openCommand) + return definition ? definition.length > 0 : false + } + + public async gotoImplementation(openCommand?: string | false): Promise { + let definition = await this.request('implementation', (doc, position, token) => { + return languages.getImplementation(doc, position, token) + }) + await this.handleLocations(definition, openCommand) + return definition ? definition.length > 0 : false + } + + public async gotoReferences(openCommand?: string | false, includeDeclaration = true): Promise { + let definition = await this.request('reference', (doc, position, token) => { + return languages.getReferences(doc, { includeDeclaration }, position, token) + }) + await this.handleLocations(definition, openCommand) + return definition ? definition.length > 0 : false + } + + public async getTagList(): Promise { + let { doc, position } = await this.handler.getCurrentState() + let word = await this.nvim.call('expand', '') + if (!word) return null + if (!languages.hasProvider('definition', doc.textDocument)) return null + let tokenSource = new CancellationTokenSource() + let definitions = await languages.getDefinition(doc.textDocument, position, tokenSource.token) + if (!definitions || !definitions.length) return null + return definitions.map(location => { + let parsedURI = URI.parse(location.uri) + const filename = parsedURI.scheme == 'file' ? parsedURI.fsPath : parsedURI.toString() + return { + name: word, + cmd: `keepjumps ${location.range.start.line + 1} | normal ${location.range.start.character + 1}|`, + filename, + } + }) + } + + /** + * Send custom request for locations to services. + */ + public async findLocations(id: string, method: string, params: any, openCommand?: string | false): Promise { + let { doc, position } = await this.handler.getCurrentState() + params = params || {} + Object.assign(params, { + textDocument: { uri: doc.uri }, + position + }) + let res: any = await services.sendRequest(id, method, params) + res = res || [] + let locations: Location[] = [] + if (Array.isArray(res)) { + locations = res as Location[] + } else if (res.hasOwnProperty('location') && res.hasOwnProperty('children')) { + let getLocation = (item: any): void => { + locations.push(item.location as Location) + if (item.children && item.children.length) { + for (let loc of item.children) { + getLocation(loc) + } + } + } + getLocation(res) + } + await this.handleLocations(locations, openCommand) + return locations ? locations.length > 0 : false + } + + public async handleLocations(definition: Definition | LocationLink[], openCommand?: string | false): Promise { + if (!definition) return + let locations: Location[] = Array.isArray(definition) ? definition as Location[] : [definition] + locations = locations.map(o => LocationLink.is(o) ? Location.create(o.targetUri, o.targetRange) : o) + let len = locations.length + if (len == 0) return + if (len == 1 && openCommand !== false) { + let { uri, range } = locations[0] + await workspace.jumpTo(uri, range.start, openCommand) + } else { + await workspace.showLocations(locations) + } + } + + public dispose(): void { + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/refactor/buffer.ts b/sources_non_forked/coc.nvim/src/handler/refactor/buffer.ts new file mode 100644 index 00000000..764bbc0f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/refactor/buffer.ts @@ -0,0 +1,672 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import fastDiff from 'fast-diff' +import path from 'path' +import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import Document from '../../model/document' +import Highlighter from '../../model/highligher' +import { BufferSyncItem, DidChangeTextDocumentParams, Optional, TextDocumentContentChange } from '../../types' +import { disposeAll } from '../../util' +import { isParentFolder, readFileLines, sameFile } from '../../util/fs' +import { omit } from '../../util/lodash' +import { Mutex } from '../../util/mutex' +import { equals } from '../../util/object' +import { adjustRangePosition, emptyRange } from '../../util/position' +import { byteLength } from '../../util/string' +import { getChangedLineCount, lineCountChange } from '../../util/textedit' +import window from '../../window' +import workspace from '../../workspace' +import Changes, { LineInfo } from './changes' +const logger = require('../../util/logger')('handler-refactorBuffer') + +export const SEPARATOR = '\u3000' + +export interface LineChange { + // zero indexed + lnum: number + delta: number +} + +export interface FileRangeInfo { + // line number of filepath + lnum: number + filepath: string + lines: string[] +} + +export interface FileChange extends FileRangeInfo { + // start line 0 indexed + start: number + // end line 0 indexed, excluded + end: number +} + +export interface FileRange { + // start lnum in refactor buffer, 1 indexed + lnum: number + // start line 0 indexed + start: number + lines: string[] + // range relatived to new range + highlights?: Range[] +} + +export type FileRangeDef = Optional & { end?: number } + +export interface FileItem { + filepath: string + ranges: FileRange[] +} + +export interface FileItemDef { + filepath: string + ranges: FileRangeDef[] +} + +export interface RefactorConfig { + openCommand: string + beforeContext: number + afterContext: number + saveToFile: boolean + showMenu: string +} + +export interface RefactorBufferOpts { + cwd: string + winid: number + fromWinid: number +} + +export default class RefactorBuffer implements BufferSyncItem { + private _disposed = false + private _fileItems: FileItem[] = [] + private mutex = new Mutex() + private disposables: Disposable[] = [] + private matchIds: Set = new Set() + private changes: Changes + private changing = false + constructor( + public readonly bufnr: number, + private srcId: number, + private nvim: Neovim, + public readonly config: RefactorConfig, + private opts: RefactorBufferOpts + ) { + this.changes = new Changes() + this.disposables.push(workspace.registerLocalKeymap('n', '', this.splitOpen.bind(this), true)) + if (config.showMenu) { + this.disposables.push(workspace.registerLocalKeymap('n', config.showMenu, this.showMenu.bind(this), true)) + } + workspace.onDidChangeTextDocument(this.onDocumentChange, this, this.disposables) + } + + public async showMenu(): Promise { + let res = await window.showMenuPicker(['Tab open', 'Remove block']) + if (res == -1) return + let fileRange = await this.searchCurrentRange() + if (!fileRange) return + if (res == 0) { + let before = await this.nvim.eval(`strpart(getline('.'), 0 ,col('.') - 1)`) as string + let character = before.length + let bufname = this.getAbsolutePath(fileRange.filepath) + this.nvim.call('coc#util#jump', ['tabe', bufname, [fileRange.line, character]], true) + } + if (res == 1) { + let range = this.getDeleteRange(fileRange) + await this.document.applyEdits([TextEdit.del(range)]) + } + } + + public get fileItems(): FileItem[] { + return this._fileItems + } + + public getFileItem(uri: string): FileItem | undefined { + let filepath = URI.parse(uri).fsPath + return this._fileItems.find(o => sameFile(o.filepath, filepath)) + } + + public getFileRange(lnum: number): FileRange & { filepath: string } { + for (let item of this._fileItems) { + for (let r of item.ranges) { + if (r.lnum == lnum) { + return Object.assign(omit(r, ['highlights']), { filepath: item.filepath }) + } + } + } + throw new Error(`File range not found at lnum: ${lnum}`) + } + + public onChange(e: DidChangeTextDocumentParams): void { + if (this.changing) return + if (e.contentChanges.length === 0) { + this.highlightLineNr() + this.nvim.redrawVim() + return + } + let { nvim } = this + e = fixChangeParams(e) + let change = e.contentChanges[0] + let { original } = e + if (change.range.end.line > 2) { + nvim.call('setbufvar', [e.bufnr, '&modified', 1], true) + } + let { range, text } = change + let lineChange = lineCountChange(TextEdit.replace(range, text)) + if (lineChange == 0) return + let edits: TextEdit[] = [TextEdit.replace(range, text)] + let addRanges: LineInfo[] = [] + // Check removed ranges + if (!emptyRange(range) && !text.includes('\u3000')) { + let sl = range.start.line + let lnums: number[] = [] + let lines = original.split(/\r?\n/) + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (line.length > 1 && line.includes('\u3000')) { + lnums.push(sl + i + 1) + } + } + if (lnums.length) { + let infos: LineInfo[] = lnums.map(lnum => { + return this.getFileRange(lnum) + }) + for (let item of this._fileItems) { + item.ranges = item.ranges.filter(o => !lnums.includes(o.lnum)) + } + this.changes.add(infos) + } + } else if (emptyRange(range) && text.includes('\u3000')) { + // check undo + let lines = text.split(/\r?\n/) + let lnums: number[] = [] + let sl = range.start.line + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (line.length > 1 && line.includes('\u3000')) { + lnums.push(sl + i + 1) + } + } + if (lnums.length) { + let res = this.changes.checkInsert(lnums) + if (res) addRanges = res + } + } else if (text.includes('\u3000')) { + // check multiple ranges change + edits = this.diffChanges(original, text) + edits.forEach(e => { + e.range = adjustRangePosition(e.range, range.start) + }) + } + this.adjustLnums(edits) + nvim.pauseNotification() + this.highlightLineNr() + nvim.resumeNotification(true, true) + if (addRanges.length) { + addRanges.forEach(info => { + let item = this._fileItems.find(o => o.filepath == info.filepath) + item.ranges.push(info) + }) + } + } + + private diffChanges(original: string, text: string): TextEdit[] { + let edits: TextEdit[] = [] + let diffs = fastDiff(original, text) + let offset = 0 + let orig = TextDocument.create('file:///1', '', 0, original) + for (let i = 0; i < diffs.length; i++) { + let diff = diffs[i] + let pos = orig.positionAt(offset) + if (diff[0] == fastDiff.EQUAL) { + offset = offset + diff[1].length + } else if (diff[0] == fastDiff.DELETE) { + let end = orig.positionAt(offset + diff[1].length) + if (diffs[i + 1] && diffs[i + 1][0] == fastDiff.INSERT) { + let text = diffs[i + 1][1] + edits.push(TextEdit.replace(Range.create(pos, end), text)) + i = i + 1 + } else { + edits.push(TextEdit.replace(Range.create(pos, end), '')) + } + offset = offset + diff[1].length + } else if (diff[0] == fastDiff.INSERT) { + edits.push(TextEdit.insert(pos, diff[1])) + } + } + return edits + } + + /** + * Handle changes of other buffers. + */ + private async onDocumentChange(e: DidChangeTextDocumentParams): Promise { + if (this.changing || e.contentChanges.length === 0) return + let { uri } = e.textDocument + let fileItem = this.getFileItem(uri) + // not affected + if (!fileItem) return + let { range, text } = e.contentChanges[0] + let lineChange = lineCountChange(TextEdit.replace(range, text)) + let edits: TextEdit[] = [] + let deleteIndexes: number[] = [] + // 4 cases: ignore, change lineNr, reload, remove + for (let i = 0; i < fileItem.ranges.length; i++) { + let r = fileItem.ranges[i] + // change after range + if (range.start.line >= r.start + r.lines.length) continue + // change before range + if (range.end.line < r.start) { + r.start = r.start + lineChange + continue + } + let textDocument = workspace.getDocument(uri).textDocument + let end = r.start + r.lines.length + lineChange + let newLines = textDocument.lines.slice(r.start, end) + if (!newLines.length) { + deleteIndexes.push(i) + let replaceRange = this.getDeleteRange(r) + edits.push(TextEdit.replace(replaceRange, '')) + } else { + r.lines = newLines + let replaceRange = this.getReplaceRange(r) + edits.push(TextEdit.replace(replaceRange, newLines.join('\n'))) + } + } + if (deleteIndexes.length) { + fileItem.ranges = fileItem.ranges.filter((_, i) => !deleteIndexes.includes(i)) + } + // clean fileItem with empty ranges + this._fileItems = this._fileItems.filter(o => o.ranges && o.ranges.length > 0) + if (edits.length) { + this.adjustLnums(edits) + this.changing = true + await this.document.applyEdits(edits) + this.changing = false + } + this.nvim.pauseNotification() + this.highlightLineNr() + this.buffer.setOption('modified', false, true) + await this.nvim.resumeNotification(true) + } + + private adjustLnums(edits: TextEdit[]): void { + for (let item of this._fileItems) { + for (let fileRange of item.ranges) { + let line = fileRange.lnum - 1 + fileRange.lnum += getChangedLineCount(Position.create(line, 0), edits) + } + } + } + + /** + * Current changed file ranges + */ + public async getFileChanges(): Promise { + let changes: FileRangeInfo[] = [] + let lines = await this.buffer.lines + lines.push(SEPARATOR) + // current lines + let arr: string[] = [] + let fsPath: string + let lnum: number + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (line.startsWith(SEPARATOR)) { + if (fsPath) { + changes.push({ + filepath: fsPath, + lines: arr.slice(), + lnum + }) + fsPath = undefined + arr = [] + } + if (line.length > 1) { + let ms = line.match(/^\u3000(.*)/) + if (ms) { + fsPath = this.getAbsolutePath(ms[1].replace(/\s+$/, '')) + lnum = i + 1 + arr = [] + } + } + } else { + arr.push(line) + } + } + return changes + } + + /** + * Open line under cursor in split window + */ + public async splitOpen(): Promise { + let { nvim } = this + let win = nvim.createWindow(this.opts.fromWinid) + let valid = await win.valid + let before = await nvim.eval(`strpart(getline('.'), 0 ,col('.') - 1)`) as string + let character = before.length + let fileRange = await this.searchCurrentRange() + if (fileRange) { + let bufname = this.getAbsolutePath(fileRange.filepath) + nvim.pauseNotification() + if (valid) { + nvim.call('win_gotoid', [this.opts.fromWinid], true) + this.nvim.call('coc#util#jump', ['edit', bufname, [fileRange.line, character]], true) + } else { + this.nvim.call('coc#util#jump', ['belowright vs', bufname, [fileRange.line, character]], true) + } + nvim.command('normal! zz', true) + await nvim.resumeNotification(true) + if (!valid) { + this.opts.fromWinid = await nvim.call('win_getid') + } + } + } + + public async searchCurrentRange(): Promise { + let { nvim } = this + let lines = await nvim.eval('getline(1,line("."))') as string[] + let len = lines.length + for (let i = 0; i < len; i++) { + let line = lines[len - i - 1] + let ms = line.match(/^\u3000(.+)/) + if (ms) { + let r = this.getFileRange(len - i) + return Object.assign({ line: r.start + (i == 0 ? 1 : i) - 1 }, r) + } + } + return undefined + } + + /** + * Add FileItem to refactor buffer. + */ + public async addFileItems(items: FileItemDef[]): Promise { + if (this._disposed) return + let { cwd } = this.opts + let { document } = this + const release = await this.mutex.acquire() + try { + await document.synchronize() + let count = document.lineCount + let highligher = new Highlighter() + let hlRanges: Range[] = [] + for (let item of items) { + let ranges: FileRange[] = [] + for (let range of item.ranges) { + highligher.addLine(SEPARATOR) + highligher.addLine(SEPARATOR) + let lnum = count + highligher.length + highligher.addText(`${isParentFolder(cwd, item.filepath) ? path.relative(cwd, item.filepath) : item.filepath}`) + // white spaces for conceal texts + let n = String(range.start + 1).length + String(range.end).length + 4 + if (!this.srcId) highligher.addText(' '.repeat(n)) + let base = 0 - highligher.length - count + if (range.highlights) { + hlRanges.push(...range.highlights.map(r => adjustRange(r, base))) + } + let { lines, start, end, highlights } = range + if (!lines) { + lines = await this.getLines(item.filepath, start, end) + } + ranges.push({ lines, lnum, start, highlights }) + highligher.addLines(lines) + } + if (ranges.length) { + let newItem: FileItem = { filepath: item.filepath, ranges } + let fileItem = this._fileItems.find(o => o.filepath == item.filepath) + if (fileItem) { + fileItem.ranges.push(...newItem.ranges) + } else { + this._fileItems.push(newItem) + } + } + } + let { nvim, buffer } = this + this.changing = true + nvim.pauseNotification() + highligher.render(buffer, count) + this.highlightLineNr() + buffer.setOption('modified', false, true) + buffer.setOption('undolevels', 1000, true) + if (count == 2 && hlRanges.length) { + let pos = hlRanges[0].start + nvim.call('coc#cursor#move_to', [pos.line, pos.character], true) + } + await nvim.resumeNotification(true) + await document.patchChange() + this.changing = false + await window.cursors.addRanges(hlRanges) + } catch (e) { + this.changing = false + logger.error(`Error on add file item:`, e) + } + release() + } + + public findRange(filepath: string, lnum: number): FileRange { + let item = this.fileItems.find(o => sameFile(this.getAbsolutePath(o.filepath), filepath)) + let range = item.ranges.find(o => o.lnum == lnum) + if (!range) throw new Error(`File range not found at lnum: ${lnum}`) + return range + } + + /** + * Save changes to buffers/files, return false when no change made. + */ + public async save(): Promise { + let { nvim } = this + let doc = this.document + let { buffer } = doc + await doc.patchChange() + let changes = await this.getFileChanges() + if (!changes) return + changes.sort((a, b) => a.lnum - b.lnum) + // filter changes that not change + let fileChanges: FileChange[] = [] + for (let i = 0; i < changes.length; i++) { + let change = changes[i] + let range = this.findRange(change.filepath, change.lnum) + if (equals(range.lines, change.lines)) continue + fileChanges.push(Object.assign({ start: range.start, end: range.start + range.lines.length }, change)) + range.lines = change.lines + } + if (fileChanges.length == 0) { + await window.showInformationMessage('No change.') + await buffer.setOption('modified', false) + return false + } + let changeMap: { [uri: string]: TextEdit[] } = {} + for (let change of fileChanges) { + let uri = URI.file(change.filepath).toString() + let edits = changeMap[uri] || [] + edits.push({ + range: Range.create(change.start, 0, change.end, 0), + newText: change.lines.join('\n') + '\n' + }) + changeMap[uri] = edits + } + this.changing = true + await workspace.applyEdit({ changes: changeMap }) + this.changing = false + for (let item of this.fileItems) { + let uri = URI.file(this.getAbsolutePath(item.filepath)).toString() + let edits = changeMap[uri] + if (edits && edits.length > 0) { + item.ranges.forEach(r => { + r.start += getChangedLineCount(Position.create(r.start, 0), edits) + }) + } + } + nvim.pauseNotification() + buffer.setOption('modified', false, true) + if (this.config.saveToFile) { + nvim.command('silent noa wa', true) + } + this.highlightLineNr() + await nvim.resumeNotification() + return true + } + + private async getLines(fsPath: string, start: number, end: number): Promise { + let uri = URI.file(fsPath).toString() + let doc = workspace.getDocument(uri) + if (doc) return doc.getLines(start, end) + return await readFileLines(fsPath, start, end - 1) + } + + private getAbsolutePath(filepath: string): string { + if (path.isAbsolute(filepath)) return filepath + return path.join(this.opts.cwd, filepath) + } + + /** + * Use conceal/virtual text to add lineNr + */ + private highlightLineNr(): void { + let { fileItems, nvim, srcId, bufnr } = this + let { winid, cwd } = this.opts + let info = {} + if (srcId) { + nvim.call('nvim_buf_clear_namespace', [bufnr, srcId, 0, -1], true) + for (let item of fileItems) { + for (let range of item.ranges) { + let end = range.start + range.lines.length + let text = `${range.start + 1}:${end}` + info[range.lnum] = [range.start + 1, end] + nvim.call('nvim_buf_set_virtual_text', [bufnr, srcId, range.lnum - 1, [[text, 'LineNr']], {}], true) + } + } + } else { + if (this.matchIds.size) { + nvim.call('coc#highlight#clear_matches', [winid, Array.from(this.matchIds)], true) + this.matchIds.clear() + } + let id = 2000 + for (let item of fileItems) { + let filename = `${cwd ? path.relative(cwd, item.filepath) : item.filepath}` + let col = byteLength(filename) + 1 + for (let range of item.ranges) { + let end = range.start + range.lines.length + let text = `:${range.start + 1}:${end}` + for (let i = 0; i < text.length; i++) { + let ch = text[i] + this.matchIds.add(id) + info[range.lnum] = [range.start + 1, end] + nvim.call('matchaddpos', ['Conceal', [[range.lnum, col + i]], 99, id, { conceal: ch, window: winid }], true) + id++ + } + } + } + } + this.buffer.setVar('line_infos', info, true) + } + + public getDeleteRange(r: FileRange): Range { + let { document } = this + let start = r.lnum - 1 + let end: Position + let total = document.lineCount + for (let i = start; i < total; i++) { + if (i + 1 == total) { + end = Position.create(total, 0) + break + } + let line = document.getline(i) + if (line === SEPARATOR) { + end = Position.create(i + 1, 0) + break + } + if (i != start && line.startsWith(SEPARATOR)) { + end = Position.create(i, 0) + break + } + } + return Range.create(Position.create(start, 0), end) + } + + public getReplaceRange(r: FileRange): Range { + let { document } = this + let start = r.lnum + let end: Position + let total = document.lineCount + for (let i = start; i < total; i++) { + let line = document.getline(i) + if (i + 1 == total) { + end = Position.create(i, line.length) + break + } + let next = document.getline(i + 1) + if (next.startsWith('\u3000')) { + end = Position.create(i, line.length) + break + } + } + return Range.create(Position.create(start, 0), end) + } + + public get valid(): Promise { + return this.buffer.valid + } + + public get buffer(): Buffer { + return this.nvim.createBuffer(this.bufnr) + } + + public get document(): Document | null { + return workspace.getDocument(this.bufnr) + } + + public dispose(): void { + this._disposed = true + disposeAll(this.disposables) + } +} + +function adjustRange(range: Range, offset: number): Range { + let { start, end } = range + return Range.create(start.line - offset, start.character, end.line - offset, end.character) +} + +export function fixChangeParams(e: DidChangeTextDocumentParams): DidChangeTextDocumentParams { + let { contentChanges, bufnr, textDocument, original, originalLines } = e + let { range, text } = contentChanges[0] + let changes: TextDocumentContentChange[] = [{ range, text }] + if (!original) { + if (emptyRange(range) && range.start.character != 0) { + let lines = text.split(/\r?\n/) + let last = lines[lines.length - 1] + let before = originalLines[range.start.line].slice(0, range.start.character) + if (last.startsWith(SEPARATOR) && before == last) { + changes[0].text = before + lines.slice(0, -1).join('\n') + '\n' + let { start, end } = range + changes[0].range = Range.create(start.line, 0, end.line, 0) + } + } + } else { + let lines = original.split(/\r?\n/) + let last = lines[lines.length - 1] + if (last.startsWith(SEPARATOR)) { + let before = originalLines[range.start.line].slice(0, range.start.character) + if (before == last) { + original = before + lines.slice(0, -1).join('\n') + '\n' + let { start, end } = range + changes[0].range = Range.create(start.line, 0, end.line, 0) + } + } + let prev = originalLines[range.start.line - 1] + let nest = lines.length > 1 ? lines[lines.length - 2] : '' + if (last == '' && + nest.startsWith(SEPARATOR) && + prev == nest && + range.start.character == 0 && range.end.character == 0) { + original = prev + '\n' + lines.slice(0, -2).join('\n') + '\n' + let { start, end } = range + changes[0].range = Range.create(start.line - 1, 0, end.line - 1, 0) + } + } + return { contentChanges: changes, bufnr, textDocument, original, originalLines } +} diff --git a/sources_non_forked/coc.nvim/src/handler/refactor/changes.ts b/sources_non_forked/coc.nvim/src/handler/refactor/changes.ts new file mode 100644 index 00000000..c7bb1f5e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/refactor/changes.ts @@ -0,0 +1,33 @@ +'use strict' +import { equals } from '../../util/object' + +export interface LineInfo { + filepath: string + // start lnum in refactor buffer, 1 indexed + lnum: number + start: number + lines: string[] +} + +export type DeleteChange = Map + +export default class Changes { + private stack: DeleteChange[] = [] + + public add(infos: LineInfo[]): void { + let map: Map = new Map() + for (let info of infos) { + map.set(info.lnum, info) + } + this.stack.push(map) + } + + public checkInsert(lnums: number[]): LineInfo[] | undefined { + if (!this.stack.length) return undefined + let last = this.stack[this.stack.length - 1] + let arr = Array.from(last.keys()).sort((a, b) => a - b) + if (!equals(arr, lnums)) return undefined + this.stack.pop() + return Array.from(last.values()) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/refactor/index.ts b/sources_non_forked/coc.nvim/src/handler/refactor/index.ts new file mode 100644 index 00000000..846f5b81 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/refactor/index.ts @@ -0,0 +1,234 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event, Location, Range, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events from '../../events' +import languages from '../../languages' +import { ConfigurationChangeEvent, HandlerDelegate } from '../../types' +import { disposeAll } from '../../util' +import { getFileLineCount } from '../../util/fs' +import { emptyWorkspaceEdit } from '../../util/textedit' +import workspace from '../../workspace' +import RefactorBuffer, { FileItemDef, FileRangeDef, RefactorConfig, SEPARATOR } from './buffer' +import Search from './search' +const logger = require('../../util/logger')('handler-refactor') + +const name = '__coc_refactor__' +let refactorId = 0 + +export default class Refactor { + private srcId: number + private buffers: Map = new Map() + public config: RefactorConfig + private disposables: Disposable[] = [] + private readonly _onCreate = new Emitter() + public readonly onCreate: Event = this._onCreate.event + constructor( + private nvim: Neovim, + private handler: HandlerDelegate + ) { + this.setConfiguration() + workspace.onDidChangeConfiguration(this.setConfiguration, this, this.disposables) + events.on('BufUnload', bufnr => { + let buf = this.buffers.get(bufnr) + if (buf) { + buf.dispose() + this.buffers.delete(bufnr) + } + }, null, this.disposables) + workspace.onDidChangeTextDocument(e => { + let buf = this.buffers.get(e.bufnr) + if (buf) buf.onChange(e) + }, null, this.disposables) + } + + public async init(): Promise { + if (workspace.isNvim && this.nvim.hasFunction('nvim_create_namespace')) { + this.srcId = await this.nvim.createNamespace('coc-refactor') + } + } + + public has(bufnr: number): boolean { + return this.buffers.has(bufnr) + } + + private setConfiguration(e?: ConfigurationChangeEvent): void { + if (e && !e.affectsConfiguration('refactor')) return + let config = workspace.getConfiguration('refactor') + this.config = Object.assign(this.config || {}, { + afterContext: config.get('afterContext', 3), + beforeContext: config.get('beforeContext', 3), + openCommand: config.get('openCommand', 'edit'), + saveToFile: config.get('saveToFile', true), + showMenu: config.get('showMenu', '') + }) + } + + /** + * Refactor of current symbol + */ + public async doRefactor(): Promise { + let { doc, position } = await this.handler.getCurrentState() + if (!languages.hasProvider('rename', doc.textDocument)) { + throw new Error(`Rename provider not found for current buffer`) + } + await doc.synchronize() + let edit = await this.handler.withRequestToken('refactor', async token => { + let res = await languages.prepareRename(doc.textDocument, position, token) + if (token.isCancellationRequested) return null + if (res === false) throw new Error(`Provider returns null on prepare, unable to rename at current position`) + let edit = await languages.provideRenameEdits(doc.textDocument, position, 'NewName', token) + if (token.isCancellationRequested) return null + if (!edit) throw new Error('Provider returns null for rename edits.') + return edit + }) + if (edit) { + await this.fromWorkspaceEdit(edit, doc.filetype) + } + } + + /** + * Search by rg + */ + public async search(args: string[]): Promise { + let buf = await this.createRefactorBuffer() + let cwd = await this.nvim.call('getcwd', []) + let search = new Search(this.nvim) + await search.run(args, cwd, buf) + } + + public async save(bufnr: number): Promise { + let buf = this.buffers.get(bufnr) + if (buf) return await buf.save() + } + + public getBuffer(bufnr: number): RefactorBuffer { + return this.buffers.get(bufnr) + } + + /** + * Create initialized refactor buffer + */ + public async createRefactorBuffer(filetype?: string, conceal = false): Promise { + let { nvim } = this + let [fromWinid, cwd] = await nvim.eval('[win_getid(),getcwd()]') as [number, string] + let { openCommand } = this.config + nvim.pauseNotification() + nvim.command(`${openCommand} ${name}${refactorId++}`, true) + nvim.command(`setl buftype=acwrite nobuflisted bufhidden=wipe nofen wrap conceallevel=2 concealcursor=n`, true) + nvim.command(`setl undolevels=-1 nolist nospell noswapfile foldmethod=expr foldexpr=coc#util#refactor_foldlevel(v:lnum)`, true) + nvim.command(`setl foldtext=coc#util#refactor_fold_text(v:foldstart)`, true) + nvim.call('setline', [1, ['Save current buffer to make changes', SEPARATOR]], true) + nvim.call('matchadd', ['Comment', '\\%1l'], true) + nvim.call('matchadd', ['Conceal', '^\\%u3000'], true) + nvim.call('matchadd', ['Label', '^\\%u3000\\zs\\S\\+'], true) + nvim.command('setl nomod', true) + if (filetype) nvim.command(`runtime! syntax/${filetype}.vim`, true) + nvim.call('coc#util#do_autocmd', ['CocRefactorOpen'], true) + await nvim.resumeNotification() + let [bufnr, win] = await nvim.eval('[bufnr("%"),win_getid()]') as [number, number] + let opts = { fromWinid, winid: win, cwd } + await workspace.document + let buf = new RefactorBuffer(bufnr, conceal ? undefined : this.srcId, this.nvim, this.config, opts) + this.buffers.set(bufnr, buf) + return buf + } + + /** + * Create refactor buffer from lines + */ + public async fromLines(lines: string[]): Promise { + let buf = await this.createRefactorBuffer() + await buf.buffer.setLines(lines, { start: 0, end: -1, strictIndexing: false }) + return buf + } + + /** + * Create refactor buffer from locations + */ + public async fromLocations(locations: Location[], filetype?: string): Promise { + if (!locations || locations.length == 0) return undefined + let changes: { [uri: string]: TextEdit[] } = {} + let edit: WorkspaceEdit = { changes } + for (let location of locations) { + let edits: TextEdit[] = changes[location.uri] || [] + edits.push({ range: location.range, newText: '' }) + changes[location.uri] = edits + } + return await this.fromWorkspaceEdit(edit, filetype) + } + + /** + * Start refactor from workspaceEdit + */ + public async fromWorkspaceEdit(edit: WorkspaceEdit, filetype?: string): Promise { + if (!edit || emptyWorkspaceEdit(edit)) return undefined + let items: FileItemDef[] = [] + let { beforeContext, afterContext } = this.config + let { changes, documentChanges } = edit + if (!changes) { + changes = {} + for (let change of documentChanges || []) { + if (TextDocumentEdit.is(change)) { + let { textDocument, edits } = change + changes[textDocument.uri] = edits + } + } + } + for (let key of Object.keys(changes)) { + let max = await this.getLineCount(key) + let edits = changes[key] + let ranges: FileRangeDef[] = [] + // start end highlights + let start = null + let end = null + let highlights: Range[] = [] + edits.sort((a, b) => a.range.start.line - b.range.start.line) + for (let edit of edits) { + let { line } = edit.range.start + let s = Math.max(0, line - beforeContext) + if (start != null && s < end) { + end = Math.min(max, line + afterContext + 1) + highlights.push(adjustRange(edit.range, start)) + } else { + if (start != null) ranges.push({ start, end, highlights }) + start = s + end = Math.min(max, line + afterContext + 1) + highlights = [adjustRange(edit.range, start)] + } + } + if (start != null) ranges.push({ start, end, highlights }) + items.push({ + ranges, + filepath: URI.parse(key).fsPath + }) + } + let buf = await this.createRefactorBuffer(filetype) + await buf.addFileItems(items) + return buf + } + + private async getLineCount(uri: string): Promise { + let doc = workspace.getDocument(uri) + if (doc) return doc.lineCount + return await getFileLineCount(URI.parse(uri).fsPath) + } + + public reset(): void { + for (let buf of this.buffers.values()) { + buf.dispose() + } + this.buffers.clear() + } + + public dispose(): void { + this._onCreate.dispose() + this.buffers.clear() + disposeAll(this.disposables) + } +} + +function adjustRange(range: Range, offset: number): Range { + let { start, end } = range + return Range.create(start.line - offset, start.character, end.line - offset, end.character) +} diff --git a/sources_non_forked/coc.nvim/src/handler/refactor/search.ts b/sources_non_forked/coc.nvim/src/handler/refactor/search.ts new file mode 100644 index 00000000..5bf2aa5c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/refactor/search.ts @@ -0,0 +1,190 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { ChildProcess, spawn } from 'child_process' +import { EventEmitter } from 'events' +import path from 'path' +import readline from 'readline' +import { Range } from 'vscode-languageserver-types' +import Highlighter from '../../model/highligher' +import { ansiparse } from '../../util/ansiparse' +import { Mutex } from '../../util/mutex' +import window from '../../window' +import RefactorBuffer, { FileItem, FileItemDef } from './buffer' +const logger = require('../../util/logger')('handler-search') + +const defaultArgs = ['--color', 'ansi', '--colors', 'path:fg:black', '--colors', 'line:fg:green', '--colors', 'match:fg:red', '--no-messages', '--heading', '-n'] +const controlCode = '\x1b' + +// emit FileItem +class Task extends EventEmitter { + private process: ChildProcess + public start(cmd: string, args: string[], cwd: string): void { + this.process = spawn(cmd, args, { cwd }) + this.process.on('error', e => { + this.emit('error', e.message) + }) + const rl = readline.createInterface(this.process.stdout) + let start: number + let fileItem: FileItemDef + let lines: string[] = [] + let highlights: Range[] = [] + let create = true + rl.on('line', content => { + if (content.includes(controlCode)) { + let items = ansiparse(content) + if (items[0].foreground == 'black') { + fileItem = { filepath: path.join(cwd, items[0].text), ranges: [] } + return + } + let normalLine = items[0].foreground == 'green' + if (normalLine) { + let lnum = parseInt(items[0].text, 10) - 1 + let padlen = items[0].text.length + 1 + if (create) { + start = lnum + create = false + } + let line = '' + for (let item of items) { + if (item.foreground == 'red') { + let l = lnum - start + let c = line.length - padlen + highlights.push(Range.create(l, c, l, c + item.text.length)) + } + line += item.text + } + let currline = line.slice(padlen) + lines.push(currline) + } + } else { + let fileEnd = content.trim().length == 0 + if (fileItem && (fileEnd || content.trim() == '--')) { + fileItem.ranges.push({ lines, highlights, start }) + } + if (fileEnd) { + this.emit('item', fileItem) + fileItem = null + } + lines = [] + highlights = [] + create = true + } + }) + rl.on('close', () => { + if (fileItem) { + if (lines.length) { + fileItem.ranges.push({ lines, highlights, start, }) + } + this.emit('item', fileItem) + } + lines = highlights = fileItem = null + this.emit('end') + }) + } + + public dispose(): void { + if (this.process) { + this.process.kill() + } + } +} + +export default class Search { + private task: Task + constructor(private nvim: Neovim, private cmd = 'rg') { + } + + public run(args: string[], cwd: string, refactorBuf: RefactorBuffer): Promise { + let { nvim, cmd } = this + let { afterContext, beforeContext } = refactorBuf.config + let argList = ['-A', afterContext.toString(), '-B', beforeContext.toString()].concat(defaultArgs, args) + let p = getPathFromArgs(args) + if (p) argList.pop() + argList.push('--', p ? path.isAbsolute(p) ? p : `./${p.replace(/^\.\//, '')}` : './') + this.task = new Task() + this.task.start(cmd, argList, cwd) + let mutex: Mutex = new Mutex() + let files = 0 + let matches = 0 + let start = Date.now() + // remaining items + let fileItems: FileItem[] = [] + const addFileItems = async () => { + if (fileItems.length == 0) return + let items = fileItems.slice() + fileItems = [] + const release = await mutex.acquire() + try { + await refactorBuf.addFileItems(items) + } catch (e) { + logger.error(e) + } + release() + } + return new Promise((resolve, reject) => { + let interval = setInterval(addFileItems, 300) + this.task.on('item', async (fileItem: FileItem) => { + files++ + matches = matches + fileItem.ranges.reduce((p, r) => p + r.highlights.length, 0) + fileItems.push(fileItem) + }) + this.task.on('error', message => { + clearInterval(interval) + window.showMessage(`Error on command "${cmd}": ${message}`, 'error') + this.task = null + reject(new Error(message)) + }) + this.task.on('end', async () => { + clearInterval(interval) + try { + await addFileItems() + const release = await mutex.acquire() + release() + this.task.removeAllListeners() + this.task = null + let buf = refactorBuf.buffer + if (buf) { + nvim.pauseNotification() + if (files == 0) { + buf.setLines(['No match found'], { start: 1, end: 2, strictIndexing: false }, true) + // eslint-disable-next-line @typescript-eslint/no-floating-promises + buf.addHighlight({ line: 1, srcId: -1, colEnd: -1, colStart: 0, hlGroup: 'Error' }) + buf.setOption('modified', false, true) + } else { + let highligher = new Highlighter() + highligher.addText('Files', 'MoreMsg') + highligher.addText(': ') + highligher.addText(`${files} `, 'Number') + highligher.addText('Matches', 'MoreMsg') + highligher.addText(': ') + highligher.addText(`${matches} `, 'Number') + highligher.addText('Duration', 'MoreMsg') + highligher.addText(': ') + highligher.addText(`${Date.now() - start}ms`, 'Number') + highligher.render(buf, 1, 2) + } + buf.setOption('modified', false, true) + nvim.resumeNotification(false, true) + } + } catch (e) { + reject(e) + return + } + resolve() + }) + }) + } + + public abort(): void { + this.task?.dispose() + } +} + +// rg requires `-- [path]` at the end +export function getPathFromArgs(args: string[]): string | undefined { + if (args.length < 2) return undefined + let len = args.length + if (args[len - 1].startsWith('-')) return undefined + if (args[len - 2].startsWith('-')) return undefined + return args[len - 1] +} diff --git a/sources_non_forked/coc.nvim/src/handler/rename.ts b/sources_non_forked/coc.nvim/src/handler/rename.ts new file mode 100644 index 00000000..1a75e684 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/rename.ts @@ -0,0 +1,71 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Range, WorkspaceEdit } from 'vscode-languageserver-protocol' +import languages from '../languages' +import { HandlerDelegate } from '../types' +import { emptyRange } from '../util/position' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-rename') + +export default class Rename { + constructor( + private nvim: Neovim, + private handler: HandlerDelegate) { + } + + public async getWordEdit(): Promise { + let { doc, position } = await this.handler.getCurrentState() + let range = doc.getWordRangeAtPosition(position) + if (!range || emptyRange(range)) return null + let curname = doc.textDocument.getText(range) + if (languages.hasProvider('rename', doc.textDocument)) { + await doc.synchronize() + let requestTokenSource = new CancellationTokenSource() + let res = await languages.prepareRename(doc.textDocument, position, requestTokenSource.token) + if (res === false) return null + let newName = curname.startsWith('a') ? 'b' : 'a' + let edit = await languages.provideRenameEdits(doc.textDocument, position, newName, requestTokenSource.token) + if (edit) return edit + } + window.showMessage('Rename provider not found, extract word ranges from current buffer', 'more') + let ranges = doc.getSymbolRanges(curname) + return { + changes: { + [doc.uri]: ranges.map(r => ({ range: r, newText: curname })) + } + } + } + + public async rename(newName?: string): Promise { + let { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('rename', doc.textDocument) + await doc.synchronize() + let token = (new CancellationTokenSource()).token + let res = await languages.prepareRename(doc.textDocument, position, token) + if (res === false) { + void window.showWarningMessage('Invalid position for rename') + return false + } + let curname: string + if (!newName) { + if (Range.is(res)) { + curname = doc.textDocument.getText(res) + await window.moveTo(res.start) + } else if (res && typeof res.placeholder === 'string') { + curname = res.placeholder + } else { + curname = await this.nvim.eval('expand("")') as string + } + const config = workspace.getConfiguration('coc.preferences') + newName = await window.requestInput('New name', config.get('renameFillCurrent', true) ? curname : undefined) + } + if (newName === '') void window.showWarningMessage('Empty word, rename canceled') + if (!newName) return false + let edit = await languages.provideRenameEdits(doc.textDocument, position, newName, token) + if (token.isCancellationRequested || !edit) return false + await workspace.applyEdit(edit) + this.nvim.redrawVim() + return true + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/selectionRange.ts b/sources_non_forked/coc.nvim/src/handler/selectionRange.ts new file mode 100644 index 00000000..db75577d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/selectionRange.ts @@ -0,0 +1,84 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Position, Range, SelectionRange } from 'vscode-languageserver-protocol' +import languages from '../languages' +import { HandlerDelegate } from '../types' +import { equals } from '../util/object' +import { positionInRange } from '../util/position' +import window from '../window' +import workspace from '../workspace' + +export default class SelectionRangeHandler { + private selectionRange: SelectionRange = null + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + } + + public async getSelectionRanges(): Promise { + let { doc, position } = await this.handler.getCurrentState() + this.handler.checkProvier('selectionRange', doc.textDocument) + await doc.synchronize() + let selectionRanges: SelectionRange[] = await this.handler.withRequestToken('selection ranges', token => { + return languages.getSelectionRanges(doc.textDocument, [position], token) + }) + return selectionRanges + } + + public async selectRange(visualmode: string, forward: boolean): Promise { + let { nvim } = this + let { doc } = await this.handler.getCurrentState() + this.handler.checkProvier('selectionRange', doc.textDocument) + let positions: Position[] = [] + if (!forward && (!this.selectionRange || !visualmode)) return + if (visualmode) { + let range = await window.getSelectedRange(visualmode) + positions.push(range.start, range.end) + } else { + let position = await window.getCursorPosition() + positions.push(position) + } + if (!forward) { + let curr = Range.create(positions[0], positions[1]) + let { selectionRange } = this + while (selectionRange && selectionRange.parent) { + if (equals(selectionRange.parent.range, curr)) { + break + } + selectionRange = selectionRange.parent + } + if (selectionRange && selectionRange.parent) { + await window.selectRange(selectionRange.range) + } + return + } + await doc.synchronize() + let selectionRanges: SelectionRange[] = await this.handler.withRequestToken('selection ranges', token => { + return languages.getSelectionRanges(doc.textDocument, positions, token) + }) + if (!selectionRanges || selectionRanges.length == 0) return + let mode = await nvim.eval('mode()') + if (mode != 'n') await nvim.eval(`feedkeys("\\", 'in')`) + let selectionRange: SelectionRange + if (selectionRanges.length == 1) { + selectionRange = selectionRanges[0] + } else { + let end = positions[1] || positions[0] + let r = Range.create(positions[0], end) + selectionRange = selectionRanges[0] + while (selectionRange) { + if (equals(r, selectionRange.range)) { + selectionRange = selectionRange.parent + continue + } + if ( + positionInRange(positions[0], selectionRange.range) == 0 && + positionInRange(end, selectionRange.range) == 0) { + break + } + selectionRange = selectionRange.parent + } + } + if (!selectionRange) return + this.selectionRange = selectionRanges[0] + await window.selectRange(selectionRange.range) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/semanticTokens/buffer.ts b/sources_non_forked/coc.nvim/src/handler/semanticTokens/buffer.ts new file mode 100644 index 00000000..0fc7c210 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/semanticTokens/buffer.ts @@ -0,0 +1,475 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationToken, CancellationTokenSource, Emitter, Event, Range, SemanticTokens, SemanticTokensDelta, SemanticTokensLegend, uinteger } from 'vscode-languageserver-protocol' +import languages from '../../languages' +import { SyncItem } from '../../model/bufferSync' +import Document from '../../model/document' +import Regions from '../../model/regions' +import { HighlightItem } from '../../types' +import { wait, waitImmediate } from '../../util/index' +import { byteIndex, upperFirst } from '../../util/string' +import window from '../../window' +import workspace from '../../workspace' +const logger = require('../../util/logger')('semanticTokens-buffer') +const yieldEveryMilliseconds = 15 + +export const HLGROUP_PREFIX = 'CocSem' +export const NAMESPACE = 'semanticTokens' + +export type TokenRange = [number, number, number] // line, startCol, endCol + +export interface SemanticTokensConfig { + filetypes: string[] + highlightPriority: number + incrementTypes: string[] + combinedModifiers: string[] + highlightGroups?: string[] +} + +export interface SemanticTokenRange { + range: TokenRange + tokenType: string + tokenModifiers: string[] + hlGroup?: string + combine: boolean +} + +interface SemanticTokensPreviousResult { + readonly version: number + readonly resultId: string | undefined, + readonly tokens?: uinteger[], +} + +interface RangeHighlights { + highlights: SemanticTokenRange[] + /** + * 0 based + */ + start: number + /** + * 0 based exclusive + */ + end: number +} + +// should be higher than document debounce +const debounceInterval = 50 + +export default class SemanticTokensBuffer implements SyncItem { + private _highlights: [number, SemanticTokenRange[]] + private _dirty = false + private _version: number | undefined + private regions = new Regions() + private tokenSource: CancellationTokenSource + private rangeTokenSource: CancellationTokenSource + private previousResults: SemanticTokensPreviousResult | undefined + private readonly _onDidRefresh = new Emitter() + public readonly onDidRefresh: Event = this._onDidRefresh.event + public highlight: Function & { clear(): void } + constructor( + private nvim: Neovim, + private doc: Document, + private readonly config: SemanticTokensConfig) { + this.highlight = debounce(() => { + void this.doHighlight() + }, debounceInterval) + this.highlight() + } + + public get bufnr(): number { + return this.doc.bufnr + } + + public onChange(): void { + this.highlight() + } + + public onTextChange(): void { + this.cancel() + } + + public async forceHighlight(): Promise { + this.previousResults = undefined + this._highlights = undefined + this.clearHighlight() + this.cancel() + await this.doHighlight(true) + } + + public async onShown(): Promise { + // Should be refreshed by onCursorMoved + if (this.shouldRangeHighlight) return + const { doc } = this + if (doc.dirty || doc.version === this._version) return + await this.doHighlight(false, true) + } + + public get hasProvider(): boolean { + let { textDocument } = this.doc + return languages.hasProvider('semanticTokens', textDocument) || languages.hasProvider('semanticTokensRange', textDocument) + } + + private get hasLegend(): boolean { + let { textDocument } = this.doc + return languages.getLegend(textDocument) != null || languages.getLegend(textDocument, true) != null + } + + public get rangeProviderOnly(): boolean { + let { textDocument } = this.doc + return !languages.hasProvider('semanticTokens', textDocument) && languages.hasProvider('semanticTokensRange', textDocument) + } + + public get shouldRangeHighlight(): boolean { + let { textDocument } = this.doc + return languages.hasProvider('semanticTokensRange', textDocument) && this.previousResults == null + } + + private get lineCount(): number { + return this.doc.lineCount + } + + /** + * Get current highlight items + */ + public get highlights(): ReadonlyArray | undefined { + if (!this._highlights) return undefined + if (this._highlights[0] == this.doc.version) return this._highlights[1] + return undefined + } + + private get buffer(): Buffer { + return this.nvim.createBuffer(this.bufnr) + } + + public get enabled(): boolean { + if (!this.config.filetypes.length) return false + if (!workspace.env.updateHighlight) return false + if (!this.doc?.attached) return false + if (!this.hasLegend) return false + if (!this.config.filetypes.includes('*') && !this.config.filetypes.includes(this.doc.filetype)) return false + return this.hasProvider + } + + public checkState(): void { + if (!workspace.env.updateHighlight) { + throw new Error(`Can't perform highlight update, highlight update requires vim >= 8.1.1719 or neovim >= 0.5.0`) + } + if (!this.doc.attached) throw new Error('Document not attached') + let { filetypes } = this.config + if (!filetypes?.includes('*') && !filetypes.includes(this.doc.filetype)) { + throw new Error(`Semantic tokens highlight not enabled for current filetype: ${this.doc.filetype}`) + } + if (!this.hasProvider) throw new Error('SemanticTokens provider not found, your languageserver may not support it') + } + + private async getTokenRanges( + tokens: number[], + legend: SemanticTokensLegend, + token: CancellationToken): Promise { + let currentLine = 0 + let currentCharacter = 0 + let tickStart = Date.now() + let highlights: SemanticTokenRange[] = [] + for (let i = 0; i < tokens.length; i += 5) { + if (Date.now() - tickStart > yieldEveryMilliseconds) { + await waitImmediate() + if (token.isCancellationRequested) break + tickStart = Date.now() + } + const deltaLine = tokens[i] + const deltaStartCharacter = tokens[i + 1] + const length = tokens[i + 2] + const tokenType = legend.tokenTypes[tokens[i + 3]] + const tokenModifiers = legend.tokenModifiers.filter((_, m) => tokens[i + 4] & (1 << m)) + const lnum = currentLine + deltaLine + const startCharacter = deltaLine === 0 ? currentCharacter + deltaStartCharacter : deltaStartCharacter + const endCharacter = startCharacter + length + currentLine = lnum + currentCharacter = startCharacter + this.addHighlightItems(highlights, lnum, startCharacter, endCharacter, tokenType, tokenModifiers) + } + if (token.isCancellationRequested) return null + return highlights + } + + /** + * Single line only. + */ + private addHighlightItems(highlights: SemanticTokenRange[], lnum: number, startCharacter: number, endCharacter: number, tokenType: string, tokenModifiers?: string[]): void { + let { highlightGroups, combinedModifiers } = this.config + tokenModifiers = tokenModifiers || [] + let highlightGroup: string + let combine = false + // Compose highlight group CocSem + modifier + type + for (let item of tokenModifiers) { + let hlGroup = HLGROUP_PREFIX + upperFirst(item) + upperFirst(tokenType) + if (highlightGroups.includes(hlGroup)) { + combine = combinedModifiers.includes(item) + highlightGroup = hlGroup + break + } + } + if (!highlightGroup) { + for (let item of tokenModifiers) { + let hlGroup = HLGROUP_PREFIX + upperFirst(item) + if (highlightGroups.includes(hlGroup)) { + highlightGroup = hlGroup + combine = combinedModifiers.includes(item) + break + } + } + } + if (!highlightGroup) { + let hlGroup = HLGROUP_PREFIX + upperFirst(tokenType) + if (highlightGroups.includes(hlGroup)) { + highlightGroup = hlGroup + } + } + let line = this.doc.getline(lnum) + let colStart = byteIndex(line, startCharacter) + let colEnd = byteIndex(line, endCharacter) + highlights.push({ + range: [lnum, colStart, colEnd], + tokenType, + combine, + hlGroup: highlightGroup, + tokenModifiers, + }) + } + + private toHighlightItems(highlights: ReadonlyArray, startLine?: number, endLine?: number): HighlightItem[] { + let { incrementTypes } = this.config + let filter = typeof startLine === 'number' && typeof endLine === 'number' + let res: HighlightItem[] = [] + for (let hi of highlights) { + if (!hi.hlGroup) continue + let lnum = hi.range[0] + if (filter && (lnum < startLine || lnum >= endLine)) continue + let item: HighlightItem = { + lnum, + hlGroup: hi.hlGroup, + colStart: hi.range[1], + colEnd: hi.range[2], + combine: hi.combine + } + if (incrementTypes.includes(hi.tokenType)) { + item.end_incl = true + item.start_incl = true + } + res.push(item) + } + return res + } + + public async doHighlight(forceFull = false, onShown = false): Promise { + this.cancel() + if (!this.enabled) return + let tokenSource = this.tokenSource = new CancellationTokenSource() + let token = tokenSource.token + if (!onShown) { + let hidden = await this.nvim.eval(`get(get(getbufinfo(${this.bufnr}),0,{}),'hidden',0)`) + if (hidden == 1 || token.isCancellationRequested) return + } + if (this.shouldRangeHighlight) { + let rangeTokenSource = this.rangeTokenSource = new CancellationTokenSource() + await this.doRangeHighlight(rangeTokenSource.token) + if (token.isCancellationRequested || this.rangeProviderOnly) return + } + const { doc } = this + const version = doc.version + let tokenRanges: SemanticTokenRange[] | undefined + // TextDocument not changed, need perform highlight since lines possible replaced. + if (version === this.previousResults?.version) { + if (this._highlights && this._highlights[0] == version) { + tokenRanges = this._highlights[1] + } else { + // possible cancelled. + const tokens = this.previousResults.tokens + const legend = languages.getLegend(doc.textDocument) + tokenRanges = await this.getTokenRanges(tokens, legend, token) + if (tokenRanges) this._highlights = [version, tokenRanges] + } + } else { + tokenRanges = await this.requestAllHighlights(token, forceFull) + if (tokenRanges) this._highlights = [version, tokenRanges] + } + // request cancelled or can't work + if (!tokenRanges || token.isCancellationRequested) return + if (!this._dirty || tokenRanges.length < 200) { + let items = this.toHighlightItems(tokenRanges) + let diff = await window.diffHighlights(this.bufnr, NAMESPACE, items, undefined, token) + if (token.isCancellationRequested || !diff) return + this._dirty = true + this._version = version + const priority = this.config.highlightPriority + await window.applyDiffHighlights(this.bufnr, NAMESPACE, priority, diff) + } else { + this.regions.clear() + await this.highlightRegions(token) + } + this._onDidRefresh.fire() + } + + public async waitRefresh(): Promise { + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + disposable.dispose() + reject(new Error(`Timeout after 500ms`)) + }, 500) + let disposable = this.onDidRefresh(() => { + disposable.dispose() + clearTimeout(timer) + resolve() + }) + }) + } + + /** + * Perform range highlight request and update. + */ + public async doRangeHighlight(token: CancellationToken): Promise { + if (!this.enabled) return + let { version } = this.doc + let res = await this.requestRangeHighlights(token) + if (!res || token.isCancellationRequested) return + const { highlights, start, end } = res + if (this.rangeProviderOnly || !this.previousResults) { + if (!this._highlights || version !== this._highlights[0]) { + this._highlights = [version, []] + } + let tokenRanges = this._highlights[1] + let used: Set = tokenRanges.reduce((p, c) => p.add(c.range[0]), new Set()) + highlights.forEach(hi => { + if (!used.has(hi.range[0])) { + tokenRanges.push(hi) + } + }) + } + const items = this.toHighlightItems(highlights) + const priority = this.config.highlightPriority + let diff = await window.diffHighlights(this.bufnr, NAMESPACE, items, [start, end], token) + if (diff) { + await window.applyDiffHighlights(this.bufnr, NAMESPACE, priority, diff, true) + this._dirty = true + } + } + + /** + * highlight current visible regions + */ + public async highlightRegions(token: CancellationToken): Promise { + let { regions, highlights, config, lineCount, bufnr } = this + if (!highlights) return + let priority = config.highlightPriority + let spans: [number, number][] = await this.nvim.call('coc#window#visible_ranges', [bufnr]) + if (token.isCancellationRequested || spans.length === 0) return + let height = workspace.env.lines + spans.forEach(o => { + let s = o[0] + o[0] = Math.max(0, Math.floor(s - height * 1.5)) + o[1] = Math.min(lineCount, Math.ceil(o[1] + height * 1.5), s + height * 2) + }) + for (let [start, end] of Regions.mergeSpans(spans)) { + if (regions.has(start, end)) continue + let items = this.toHighlightItems(highlights, start, end) + let diff = await window.diffHighlights(bufnr, NAMESPACE, items, [start, end], token) + if (token.isCancellationRequested) break + regions.add(start, end) + if (diff) void window.applyDiffHighlights(bufnr, NAMESPACE, priority, diff, true) + } + } + + public async onCursorMoved(): Promise { + this.cancel(true) + if (!this.enabled || this.doc.dirty) return + let rangeTokenSource = this.rangeTokenSource = new CancellationTokenSource() + let token = rangeTokenSource.token + await wait(global.__TEST__ ? 10 : 100) + if (token.isCancellationRequested) return + if (this.shouldRangeHighlight) { + await this.doRangeHighlight(token) + } else { + await this.highlightRegions(token) + } + } + + /** + * Request highlights for visible range. + */ + private async requestRangeHighlights(token: CancellationToken): Promise { + let { nvim, doc } = this + let region = await nvim.call('coc#window#visible_range', [this.bufnr]) as [number, number] + if (!region || token.isCancellationRequested) return null + const endLine = Math.min(region[0] + workspace.env.lines * 2, region[1]) + let range = Range.create(region[0] - 1, 0, endLine, 0) + let res = await languages.provideDocumentRangeSemanticTokens(doc.textDocument, range, token) + if (!res || !SemanticTokens.is(res) || token.isCancellationRequested) return null + let legend = languages.getLegend(doc.textDocument, true) + let highlights = await this.getTokenRanges(res.data, legend, token) + if (token.isCancellationRequested) return null + return { highlights, start: region[0] - 1, end: region[1] } + } + + /** + * Request highlights from provider, return undefined when can't request or request cancelled + * Use range provider only when not semanticTokens provider exists. + */ + private async requestAllHighlights(token: CancellationToken, forceFull: boolean): Promise { + const { doc } = this + const legend = languages.getLegend(doc.textDocument) + const hasEditProvider = languages.hasSemanticTokensEdits(doc.textDocument) + const previousResult = forceFull ? null : this.previousResults + const version = doc.version + let result: SemanticTokens | SemanticTokensDelta + if (hasEditProvider && previousResult?.resultId) { + result = await languages.provideDocumentSemanticTokensEdits(doc.textDocument, previousResult.resultId, token) + } else { + result = await languages.provideDocumentSemanticTokens(doc.textDocument, token) + } + if (token.isCancellationRequested || result == null) return + let tokens: uinteger[] = [] + if (SemanticTokens.is(result)) { + tokens = result.data + } else if (previousResult && Array.isArray(result.edits)) { + tokens = previousResult.tokens + result.edits.forEach(e => { + tokens.splice(e.start, e.deleteCount ? e.deleteCount : 0, ...(e.data ?? [])) + }) + } + this.previousResults = { resultId: result.resultId, tokens, version } + return await this.getTokenRanges(tokens, legend, token) + } + + public clearHighlight(): void { + this.buffer.clearNamespace(NAMESPACE) + } + + public abandonResult(): void { + this.previousResults = undefined + } + + public cancel(rangeOnly = false): void { + if (this.rangeTokenSource) { + this.rangeTokenSource.cancel() + this.rangeTokenSource.dispose() + this.rangeTokenSource = null + } + if (rangeOnly) return + this.regions.clear() + this.highlight.clear() + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public dispose(): void { + this.cancel() + this.previousResults = undefined + this._highlights = undefined + this._onDidRefresh.dispose() + this.regions.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/semanticTokens/index.ts b/sources_non_forked/coc.nvim/src/handler/semanticTokens/index.ts new file mode 100644 index 00000000..7e6b0f7c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/semanticTokens/index.ts @@ -0,0 +1,242 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import commands from '../../commands' +import events from '../../events' +import languages from '../../languages' +import BufferSync from '../../model/bufferSync' +import FloatFactory from '../../model/floatFactory' +import Highlighter from '../../model/highligher' +import { ConfigurationChangeEvent, Documentation, HandlerDelegate } from '../../types' +import { disposeAll } from '../../util' +import { distinct } from '../../util/array' +import { upperFirst } from '../../util/string' +import workspace from '../../workspace' +import SemanticTokensBuffer, { HLGROUP_PREFIX, NAMESPACE, SemanticTokensConfig } from './buffer' +const logger = require('../../util/logger')('semanticTokens') +const headGroup = 'Statement' + +export default class SemanticTokens { + // shared with buffers + private config: SemanticTokensConfig + private disposables: Disposable[] = [] + private highlighters: BufferSync + private floatFactory: FloatFactory + + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.loadConfiguration() + this.floatFactory = new FloatFactory(nvim) + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + commands.register({ + id: 'semanticTokens.checkCurrent', + execute: async () => { + await this.showHighlightInfo() + } + }, false, 'show semantic tokens highlight information of current buffer') + commands.register({ + id: 'semanticTokens.refreshCurrent', + execute: () => { + return this.highlightCurrent() + } + }, false, 'refresh semantic tokens highlight of current buffer.') + commands.register({ + id: 'semanticTokens.inspect', + execute: () => { + return this.inspectSemanticToken() + } + }, false, 'Inspect semantic token information at cursor position.') + commands.register({ + id: 'semanticTokens.clearCurrent', + execute: async () => { + let buf = await nvim.buffer + buf.clearNamespace(NAMESPACE, 0, -1) + } + }, false, 'clear semantic tokens highlight of current buffer') + commands.register({ + id: 'semanticTokens.clearAll', + execute: async () => { + let bufs = await nvim.buffers + for (let buf of bufs) { + buf.clearNamespace(NAMESPACE, 0, -1) + } + } + }, false, 'clear semantic tokens highlight of all buffers') + this.highlighters = workspace.registerBufferSync(doc => { + return new SemanticTokensBuffer(this.nvim, doc, this.config) + }) + languages.onDidSemanticTokensRefresh(async selector => { + let visibleBufs = await this.nvim.call('coc#window#bufnrs') as number[] + for (let item of this.highlighters.items) { + let doc = workspace.getDocument(item.bufnr) + if (!doc || !workspace.match(selector, doc.textDocument)) continue + item.abandonResult() + if (visibleBufs.includes(item.bufnr)) { + item.highlight() + } + } + }, null, this.disposables) + events.on('BufWinEnter', async bufnr => { + let item = this.highlighters.getItem(bufnr) + if (item) await item.onShown() + }, null, this.disposables) + events.on('CursorMoved', async bufnr => { + let item = this.highlighters.getItem(bufnr) + if (item) await item.onCursorMoved() + }, null, this.disposables) + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('semanticTokens')) { + let highlightGroups = [] + if (this.config?.highlightGroups) { + highlightGroups = this.config.highlightGroups + } else { + highlightGroups = workspace.env.semanticHighlights || [] + } + let config = workspace.getConfiguration('semanticTokens') + this.config = Object.assign(this.config || {}, { + highlightGroups, + filetypes: config.get('filetypes', []), + highlightPriority: config.get('highlightPriority', 2048), + incrementTypes: config.get('incrementTypes', []), + combinedModifiers: config.get('combinedModifiers', []) + }) + } + } + + public async inspectSemanticToken(): Promise { + let item = await this.getCurrentItem() + if (!item || !item.enabled) { + this.floatFactory.close() + return + } + let [_, line, col] = await this.nvim.call('getcurpos', []) + let highlights = item.highlights ?? [] + let highlight = highlights.find(o => { + let column = col - 1 + return o.range[0] === line - 1 && column >= o.range[1] && column < o.range[2] + }) + if (highlight) { + let modifiers = highlight.tokenModifiers || [] + let highlights = [] + if (highlight.hlGroup) { + let s = 'Highlight group: '.length + highlights.push({ + lnum: 2, + colStart: s, + colEnd: s + highlight.hlGroup.length, + hlGroup: highlight.hlGroup + }) + } + let docs: Documentation[] = [{ + filetype: 'txt', + content: `Type: ${highlight.tokenType}\nModifiers: ${modifiers.join(', ')}\nHighlight group: ${highlight.hlGroup || ''}`, + highlights + }] + await this.floatFactory.show(docs, { + autoHide: true, + focusable: true, + title: 'Semantic token info', + borderhighlight: 'MoreMsg', + border: [1, 1, 1, 1] + }) + } else { + this.floatFactory.close() + } + } + + public async fetchHighlightGroups(): Promise { + let res = await this.nvim.call('coc#util#semantic_hlgroups') as string[] + this.config.highlightGroups = res + } + + public async getCurrentItem(): Promise { + let buf = await this.nvim.buffer + let highlighter = this.highlighters.getItem(buf.id) + if (!highlighter) null + return highlighter + } + + public getItem(bufnr: number): SemanticTokensBuffer | null { + return this.highlighters.getItem(bufnr) + } + /** + * Force highlight of current buffer + */ + public async highlightCurrent(): Promise { + let item = await this.getCurrentItem() + if (!item || !item.enabled) throw new Error(`Unable to perform semantic highlights for current buffer.`) + await this.fetchHighlightGroups() + await item.forceHighlight() + } + + /** + * Show semantic highlight info in temporarily buffer + */ + public async showHighlightInfo(): Promise { + let buf = await this.nvim.buffer + let { nvim } = this + let item = this.highlighters.getItem(buf.id) + if (!item) return nvim.echoError('Document not attached.') + let hl = new Highlighter() + nvim.pauseNotification() + nvim.command(`vs +setl\\ buftype=nofile __coc_semantic_highlights_${buf.id}__`, true) + nvim.command(`setl bufhidden=wipe noswapfile nobuflisted wrap undolevels=-1`, true) + nvim.call('bufnr', ['%'], true) + let res = await nvim.resumeNotification() + hl.addLine('Semantic highlights info', headGroup) + hl.addLine('') + try { + item.checkState() + let highlights = item.highlights ?? [] + hl.addLine('The number of semantic tokens: ') + hl.addText(String(highlights.length), 'Number') + hl.addLine('') + hl.addLine('Semantic highlight groups used by current buffer', headGroup) + hl.addLine('') + const groups = distinct(highlights.filter(o => o.hlGroup != null).map(({ hlGroup }) => hlGroup)) + for (const hlGroup of groups) { + hl.addTexts([{ text: '-', hlGroup: 'Comment' }, { text: ' ' }, { text: hlGroup, hlGroup }]) + } + hl.addLine('') + hl.addLine('Tokens types that current Language Server supported:', headGroup) + hl.addLine('') + let doc = workspace.getDocument(item.bufnr) + let legend = languages.getLegend(doc.textDocument) ?? languages.getLegend(doc.textDocument, true) + if (legend.tokenTypes.length) { + for (const t of [...new Set(legend.tokenTypes)]) { + let text = HLGROUP_PREFIX + upperFirst(t) + hl.addTexts([{ text: '-', hlGroup: 'Comment' }, { text: ' ' }, { text, hlGroup: text }]) + } + hl.addLine('') + } else { + hl.addLine('No token types supported', 'Comment') + hl.addLine('') + } + hl.addLine('Tokens modifiers that current Language Server supported:', headGroup) + hl.addLine('') + if (legend.tokenModifiers.length) { + for (const t of [...new Set(legend.tokenModifiers)]) { + let text = HLGROUP_PREFIX + upperFirst(t) + hl.addTexts([{ text: '-', hlGroup: 'Comment' }, { text: ' ' }, { text, hlGroup: text }]) + } + hl.addLine('') + } else { + hl.addLine('No token modifiers exist', 'Comment') + hl.addLine('') + } + } catch (e) { + hl.addLine(e instanceof Error ? e.message : e.toString(), 'Error') + } + nvim.pauseNotification() + let bufnr = res[0][2] as number + hl.render(nvim.createBuffer(bufnr)) + nvim.resumeNotification(true, true) + } + + public dispose(): void { + this.floatFactory.dispose() + this.highlighters.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/signature.ts b/sources_non_forked/coc.nvim/src/handler/signature.ts new file mode 100644 index 00000000..824f20d9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/signature.ts @@ -0,0 +1,277 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, MarkupContent, Position, SignatureHelp, SignatureHelpTriggerKind } from 'vscode-languageserver-protocol' +import events from '../events' +import languages from '../languages' +import Document from '../model/document' +import FloatFactory from '../model/floatFactory' +import { ConfigurationChangeEvent, FloatConfig, HandlerDelegate } from '../types' +import { disposeAll, isMarkdown } from '../util' +import { byteLength } from '../util/string' +import workspace from '../workspace' +const logger = require('../util/logger')('handler-signature') + +interface SignatureConfig { + wait: number + trigger: boolean + target: string + preferAbove: boolean + hideOnChange: boolean + floatConfig: FloatConfig +} + +interface SignaturePosition { + bufnr: number + lnum: number + col: number +} + +interface SignaturePart { + text: string + type: 'Label' | 'MoreMsg' | 'Normal' +} + +export default class Signature { + private timer: NodeJS.Timer + private config: SignatureConfig + private signatureFactory: FloatFactory + private lastPosition: SignaturePosition | undefined + private disposables: Disposable[] = [] + private tokenSource: CancellationTokenSource | undefined + constructor(private nvim: Neovim, private handler: HandlerDelegate) { + this.signatureFactory = new FloatFactory(nvim) + this.loadConfiguration() + this.disposables.push(this.signatureFactory) + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + events.on('CursorMovedI', async (bufnr, cursor) => { + let pos = this.lastPosition + if (!pos) return + // avoid close signature for valid position. + if (pos.bufnr == bufnr && pos.lnum == cursor[0] && pos.col <= cursor[1]) return + this.signatureFactory.close() + }, null, this.disposables) + events.on(['InsertLeave', 'BufEnter'], () => { + this.tokenSource?.cancel() + }, null, this.disposables) + events.on('TextChangedI', () => { + if (this.config.hideOnChange) { + this.signatureFactory.close() + } + }, null, this.disposables) + events.on('TextInsert', async (bufnr, info, character) => { + if (!this.config.trigger) return + let doc = this.getTextDocument(bufnr) + if (!doc || !languages.shouldTriggerSignatureHelp(doc.textDocument, character)) return + await this._triggerSignatureHelp(doc, { line: info.lnum - 1, character: info.pre.length }, false) + }, null, this.disposables) + } + + private getTextDocument(bufnr: number): Document | undefined { + let doc = workspace.getDocument(bufnr) + if (!doc || doc.isCommandLine || !doc.attached) return + return doc + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('signature')) { + let config = workspace.getConfiguration('signature') + let target = config.get('target', 'float') + if (target == 'float' && !workspace.floatSupported) { + target = 'echo' + } + this.config = { + target, + floatConfig: config.get('floatConfig', {}), + trigger: config.get('enable', true), + wait: Math.max(config.get('triggerSignatureWait', 500), 200), + preferAbove: config.get('preferShownAbove', true), + hideOnChange: config.get('hideOnTextChange', false), + } + } + } + + public async triggerSignatureHelp(): Promise { + let { doc, position } = await this.handler.getCurrentState() + if (!languages.hasProvider('signature', doc.textDocument)) return false + return await this._triggerSignatureHelp(doc, position, true, 0) + } + + private async _triggerSignatureHelp(doc: Document, position: Position, invoke = true, offset = 0): Promise { + this.tokenSource?.cancel() + let tokenSource = this.tokenSource = new CancellationTokenSource() + let token = tokenSource.token + token.onCancellationRequested(() => { + tokenSource.dispose() + this.tokenSource = undefined + }) + let { target } = this.config + let timer = this.timer = setTimeout(() => { + tokenSource.cancel() + }, this.config.wait) + await doc.patchChange(true) + let signatureHelp = await languages.getSignatureHelp(doc.textDocument, position, token, { + isRetrigger: this.signatureFactory.checkRetrigger(doc.bufnr), + triggerKind: invoke ? SignatureHelpTriggerKind.Invoked : SignatureHelpTriggerKind.TriggerCharacter + }) + clearTimeout(timer) + if (token.isCancellationRequested) return false + if (!signatureHelp || signatureHelp.signatures.length == 0) { + this.signatureFactory.close() + return false + } + let { activeSignature, signatures } = signatureHelp + if (activeSignature) { + // make active first + let [active] = signatures.splice(activeSignature, 1) + if (active) signatures.unshift(active) + } + if (target == 'echo') { + this.echoSignature(signatureHelp) + } else { + await this.showSignatureHelp(doc, position, signatureHelp, offset) + } + return true + } + + private async showSignatureHelp(doc: Document, position: Position, signatureHelp: SignatureHelp, offset: number): Promise { + let { signatures, activeParameter } = signatureHelp + let paramDoc: string | MarkupContent = null + let startOffset = offset + let docs = signatures.reduce((p, c, idx) => { + let activeIndexes: [number, number] = null + let activeIndex = c.activeParameter ?? typeof activeParameter === 'number' ? activeParameter : undefined + if (activeIndex === undefined && c.parameters?.length > 0) { + activeIndex = 0 + } + let nameIndex = c.label.indexOf('(') + if (idx == 0 && typeof activeIndex === 'number') { + let active = c.parameters?.[activeIndex] + if (active) { + let after = c.label.slice(nameIndex == -1 ? 0 : nameIndex) + paramDoc = active.documentation + if (typeof active.label === 'string') { + let str = after.slice(0) + let ms = str.match(new RegExp('\\b' + active.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b')) + let index = ms ? ms.index : str.indexOf(active.label) + if (index != -1) { + activeIndexes = [ + index + nameIndex, + index + active.label.length + nameIndex + ] + } + } else { + activeIndexes = active.label + } + } + } + if (activeIndexes == null) { + activeIndexes = [nameIndex + 1, nameIndex + 1] + } + if (offset == startOffset) { + offset = offset + activeIndexes[0] + 1 + } + p.push({ + content: c.label, + filetype: doc.filetype, + active: activeIndexes + }) + if (paramDoc) { + let content = typeof paramDoc === 'string' ? paramDoc : paramDoc.value + if (content.trim().length) { + p.push({ + content, + filetype: isMarkdown(c.documentation) ? 'markdown' : 'txt' + }) + } + } + if (idx == 0 && c.documentation) { + let { documentation } = c + let content = typeof documentation === 'string' ? documentation : documentation.value + if (content.trim().length) { + p.push({ + content, + filetype: isMarkdown(c.documentation) ? 'markdown' : 'txt' + }) + } + } + return p + }, []) + let content = doc.getline(position.line, false).slice(0, position.character) + this.lastPosition = { bufnr: doc.bufnr, lnum: position.line + 1, col: byteLength(content) + 1 } + const excludeImages = workspace.getConfiguration('coc.preferences').get('excludeImageLinksInMarkdownDocument') + let config = this.signatureFactory.applyFloatConfig({ + preferTop: this.config.preferAbove, + autoHide: false, + offsetX: offset, + modes: ['i', 'ic', 's'], + excludeImages + }, this.config.floatConfig) + await this.signatureFactory.show(docs, config) + } + + private echoSignature(signatureHelp: SignatureHelp): void { + let { signatures, activeParameter } = signatureHelp + let columns = workspace.env.columns + signatures = signatures.slice(0, workspace.env.cmdheight) + let signatureList: SignaturePart[][] = [] + for (let signature of signatures) { + let parts: SignaturePart[] = [] + let { label } = signature + label = label.replace(/\n/g, ' ') + if (label.length >= columns - 16) { + label = label.slice(0, columns - 16) + '...' + } + let nameIndex = label.indexOf('(') + if (nameIndex == -1) { + parts = [{ text: label, type: 'Normal' }] + } else { + parts.push({ + text: label.slice(0, nameIndex), + type: 'Label' + }) + let after = label.slice(nameIndex) + if (signatureList.length == 0 && activeParameter != null) { + let active = signature.parameters?.[activeParameter] + if (active) { + let start: number + let end: number + if (typeof active.label === 'string') { + let str = after.slice(0) + let ms = str.match(new RegExp('\\b' + active.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b')) + let idx = ms ? ms.index : str.indexOf(active.label) + if (idx == -1) { + parts.push({ text: after, type: 'Normal' }) + } else { + start = idx + end = idx + active.label.length + } + } else { + [start, end] = active.label + start = start - nameIndex + end = end - nameIndex + } + if (start != null && end != null) { + parts.push({ text: after.slice(0, start), type: 'Normal' }) + parts.push({ text: after.slice(start, end), type: 'MoreMsg' }) + parts.push({ text: after.slice(end), type: 'Normal' }) + } + } + } else { + parts.push({ + text: after, + type: 'Normal' + }) + } + } + signatureList.push(parts) + } + this.nvim.callTimer('coc#ui#echo_signatures', [signatureList], true) + } + + public dispose(): void { + disposeAll(this.disposables) + if (this.timer) { + clearTimeout(this.timer) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/symbols/buffer.ts b/sources_non_forked/coc.nvim/src/handler/symbols/buffer.ts new file mode 100644 index 00000000..f89be200 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/symbols/buffer.ts @@ -0,0 +1,91 @@ +'use strict' +import debounce from 'debounce' +import { CancellationTokenSource, Disposable, DocumentSymbol, Emitter, Event, SymbolTag, TextDocument } from 'vscode-languageserver-protocol' +import languages from '../../languages' +import { SyncItem } from '../../model/bufferSync' +import { DidChangeTextDocumentParams } from '../../types' +import { disposeAll } from '../../util' +import workspace from '../../workspace' +import { isDocumentSymbols } from './util' + +export default class SymbolsBuffer implements SyncItem { + private disposables: Disposable[] = [] + public fetchSymbols: (() => void) & { clear(): void } + private version: number + public symbols: DocumentSymbol[] + private tokenSource: CancellationTokenSource + private readonly _onDidUpdate = new Emitter() + public readonly onDidUpdate: Event = this._onDidUpdate.event + constructor(public readonly bufnr: number, private autoUpdateBufnrs: Set) { + this.fetchSymbols = debounce(() => { + this._fetchSymbols().logError() + }, global.hasOwnProperty('__TEST__') ? 10 : 500) + } + + /** + * Enable autoUpdate when invoked. + */ + public async getSymbols(): Promise { + let doc = workspace.getDocument(this.bufnr) + if (!doc) return [] + await doc.patchChange() + this.autoUpdateBufnrs.add(this.bufnr) + // refresh for empty symbols since some languages server could be buggy first time. + if (doc.version == this.version && this.symbols?.length) return this.symbols + this.cancel() + await this._fetchSymbols() + return this.symbols + } + + public onChange(e: DidChangeTextDocumentParams): void { + if (e.contentChanges.length === 0) return + this.cancel() + if (this.autoUpdateBufnrs.has(this.bufnr)) { + this.fetchSymbols() + } + } + + private get textDocument(): TextDocument | undefined { + return workspace.getDocument(this.bufnr)?.textDocument + } + + private async _fetchSymbols(): Promise { + let { textDocument } = this + if (!textDocument) return + let { version } = textDocument + let tokenSource = this.tokenSource = new CancellationTokenSource() + let { token } = tokenSource + let symbols = await languages.getDocumentSymbol(textDocument, token) + this.tokenSource = undefined + if (symbols == null || token.isCancellationRequested) return + let res: DocumentSymbol[] + if (isDocumentSymbols(symbols)) { + res = symbols + } else { + res = symbols.map(o => { + let sym = DocumentSymbol.create(o.name, '', o.kind, o.location.range, o.location.range) + if (o.deprecated) sym.tags = [SymbolTag.Deprecated] + return sym + }) + } + this.version = version + this.symbols = res + this._onDidUpdate.fire(res) + } + + public cancel(): void { + this.fetchSymbols.clear() + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public dispose(): void { + this.cancel() + this.symbols = undefined + this._onDidUpdate.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/symbols/index.ts b/sources_non_forked/coc.nvim/src/handler/symbols/index.ts new file mode 100644 index 00000000..f06f0779 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/symbols/index.ts @@ -0,0 +1,174 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Range, SymbolInformation } from 'vscode-languageserver-protocol' +import events from '../../events' +import languages from '../../languages' +import BufferSync from '../../model/bufferSync' +import { HandlerDelegate } from '../../types' +import { disposeAll, wait } from '../../util/index' +import { equals } from '../../util/object' +import { positionInRange, rangeInRange } from '../../util/position' +import window from '../../window' +import workspace from '../../workspace' +import SymbolsBuffer from './buffer' +import Outline from './outline' +import { convertSymbols, SymbolInfo } from './util' + +export default class Symbols { + private buffers: BufferSync + private disposables: Disposable[] = [] + private outline: Outline + private autoUpdateBufnrs: Set = new Set() + + constructor( + private nvim: Neovim, + private handler: HandlerDelegate + ) { + this.buffers = workspace.registerBufferSync(doc => { + if (doc.buftype != '') return undefined + let buf = new SymbolsBuffer(doc.bufnr, this.autoUpdateBufnrs) + buf.onDidUpdate(symbols => { + if (!this.outline) return + this.outline.onSymbolsUpdate(buf.bufnr, symbols) + }) + return buf + }) + this.outline = new Outline(nvim, this.buffers, handler) + events.on('CursorHold', async (bufnr: number) => { + if (!this.functionUpdate || !this.buffers.getItem(bufnr)) return + await this.getCurrentFunctionSymbol(bufnr) + }, null, this.disposables) + events.on('InsertEnter', (bufnr: number) => { + let buf = this.buffers.getItem(bufnr) + if (buf) buf.cancel() + }, null, this.disposables) + } + + public get functionUpdate(): boolean { + let config = workspace.getConfiguration('coc.preferences') + return config.get('currentFunctionSymbolAutoUpdate', false) + } + + public get labels(): { [key: string]: string } { + return workspace.getConfiguration('suggest').get('completionItemKindLabels', {}) + } + + public async getWorkspaceSymbols(input: string): Promise { + this.handler.checkProvier('workspaceSymbols', null) + let tokenSource = new CancellationTokenSource() + return await languages.getWorkspaceSymbols(input, tokenSource.token) + } + + public async resolveWorkspaceSymbol(symbolInfo: SymbolInformation): Promise { + if (symbolInfo.location?.uri) return symbolInfo + let tokenSource = new CancellationTokenSource() + return await languages.resolveWorkspaceSymbol(symbolInfo, tokenSource.token) + } + + public async getDocumentSymbols(bufnr?: number): Promise { + if (!bufnr) { + let doc = await workspace.document + if (!doc || doc.isCommandLine || !doc.attached) return undefined + await wait(1) + bufnr = doc.bufnr + } + let buf = this.buffers.getItem(bufnr) + if (!buf) return + let res = await buf.getSymbols() + return res ? convertSymbols(res) : undefined + } + + public async getCurrentFunctionSymbol(bufnr?: number): Promise { + if (!bufnr) bufnr = await this.nvim.call('bufnr', ['%']) + let doc = workspace.getDocument(bufnr) + if (!doc || !doc.attached) return + if (!languages.hasProvider('documentSymbol', doc.textDocument)) return + let position = await window.getCursorPosition() + let symbols = await this.getDocumentSymbols(bufnr) + let buffer = this.nvim.createBuffer(bufnr) + if (!symbols || symbols.length === 0) { + buffer.setVar('coc_current_function', '', true) + this.nvim.call('coc#util#do_autocmd', ['CocStatusChange'], true) + return '' + } + symbols = symbols.filter(s => [ + 'Class', + 'Method', + 'Function', + 'Struct', + ].includes(s.kind)) + let functionName = '' + for (let sym of symbols.reverse()) { + if (sym.range + && positionInRange(position, sym.range) == 0 + && !sym.text.endsWith(') callback')) { + functionName = sym.text + let label = this.labels[sym.kind.toLowerCase()] + if (label) functionName = `${label} ${functionName}` + break + } + } + if (this.functionUpdate) { + buffer.setVar('coc_current_function', functionName, true) + this.nvim.call('coc#util#do_autocmd', ['CocStatusChange'], true) + } + return functionName + } + + /* + * supportedSymbols must be string values of symbolKind + */ + public async selectSymbolRange(inner: boolean, visualmode: string, supportedSymbols: string[]): Promise { + let { doc } = await this.handler.getCurrentState() + this.handler.checkProvier('documentSymbol', doc.textDocument) + let range: Range + if (visualmode) { + range = await window.getSelectedRange(visualmode) + } else { + let pos = await window.getCursorPosition() + range = Range.create(pos, pos) + } + let symbols = await this.getDocumentSymbols(doc.bufnr) + if (!symbols || symbols.length === 0) { + window.showMessage('No symbols found', 'warning') + return + } + symbols = symbols.filter(s => supportedSymbols.includes(s.kind)) + let selectRange: Range + for (let sym of symbols.reverse()) { + if (sym.range && !equals(sym.range, range) && rangeInRange(range, sym.range)) { + selectRange = sym.range + break + } + } + if (inner && selectRange) { + let { start, end } = selectRange + let line = doc.getline(start.line + 1) + let endLine = doc.getline(end.line - 1) + selectRange = Range.create(start.line + 1, line.match(/^\s*/)[0].length, end.line - 1, endLine.length) + } + if (selectRange) { + await window.selectRange(selectRange) + } else if (['v', 'V', '\x16'].includes(visualmode)) { + await this.nvim.command('normal! gv') + } + } + + public async showOutline(keep?: number): Promise { + await this.outline.show(keep) + } + + public async hideOutline(): Promise { + await this.outline.hide() + } + + public hasOutline(bufnr: number): boolean { + return this.outline.has(bufnr) + } + + public dispose(): void { + this.outline.dispose() + this.buffers.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/symbols/outline.ts b/sources_non_forked/coc.nvim/src/handler/symbols/outline.ts new file mode 100644 index 00000000..54bc01e9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/symbols/outline.ts @@ -0,0 +1,343 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CodeActionKind, Disposable, DocumentSymbol, Position, Range, SymbolKind, SymbolTag } from 'vscode-languageserver-protocol' +import events from '../../events' +import languages from '../../languages' +import BufferSync from '../../model/bufferSync' +import BasicDataProvider, { TreeNode } from '../../tree/BasicDataProvider' +import BasicTreeView from '../../tree/TreeView' +import { ConfigurationChangeEvent, HandlerDelegate } from '../../types' +import { disposeAll } from '../../util' +import { comparePosition, positionInRange } from '../../util/position' +import window from '../../window' +import workspace from '../../workspace' +import SymbolsBuffer from './buffer' +const logger = require('../../util/logger')('symbols-outline') + +// Support expand level. +interface OutlineNode extends TreeNode { + kind: SymbolKind + range: Range + selectRange: Range +} + +interface OutlineConfig { + splitCommand: string + switchSortKey: string + followCursor: boolean + keepWindow: boolean + expandLevel: number + checkBufferSwitch: boolean + showLineNumber: boolean + autoWidth: boolean + detailAsDescription: boolean + codeActionKinds: CodeActionKind[] + sortBy: 'position' | 'name' | 'category' +} + +/** + * Manage TreeViews and Providers of outline. + */ +export default class SymbolsOutline { + private treeViewList: BasicTreeView[] = [] + private providersMap: Map> = new Map() + private sortByMap: Map = new Map() + private config: OutlineConfig + private disposables: Disposable[] = [] + constructor( + private nvim: Neovim, + private buffers: BufferSync, + private handler: HandlerDelegate + ) { + this.loadConfiguration() + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + workspace.onDidCloseTextDocument(async e => { + let { bufnr } = e + let provider = this.providersMap.get(bufnr) + if (!provider) return + let loaded = await nvim.call('bufloaded', [bufnr]) as number + // reload detected + if (loaded) return + this.providersMap.delete(bufnr) + provider.dispose() + }, null, this.disposables) + window.onDidChangeActiveTextEditor(async editor => { + if (!this.config.checkBufferSwitch) return + let view = this.treeViewList.find(v => v.visible && v.targetTabnr == editor.tabpagenr) + if (view) { + await this.showOutline(editor.document.bufnr, editor.tabpagenr) + await nvim.command(`noa call win_gotoid(${editor.winid})`) + } + }, null, this.disposables) + events.on('CursorHold', async bufnr => { + if (!this.config.followCursor) return + let provider = this.providersMap.get(bufnr) + if (!provider) return + let tabnr = await nvim.call('tabpagenr') + let view = this.treeViewList.find(o => o.visible && o.targetBufnr == bufnr && o.targetTabnr == tabnr) + if (!view) return + let pos = await window.getCursorPosition() + await this.revealPosition(view, pos) + }, null, this.disposables) + } + + private async revealPosition(treeView: BasicTreeView, position: Position): Promise { + let curr: OutlineNode + let checkNode = (node: OutlineNode): boolean => { + if (positionInRange(position, node.range) != 0) return false + curr = node + if (Array.isArray(node.children)) { + for (let n of node.children) { + if (n.kind === SymbolKind.Variable) continue + if (checkNode(n)) break + } + } + return true + } + let provider = this.providersMap.get(treeView.targetBufnr) + if (!provider) return + let nodes = await Promise.resolve(provider.getChildren()) + for (let n of nodes) { + if (checkNode(n)) break + } + if (curr) await treeView.reveal(curr) + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('outline')) { + let c = workspace.getConfiguration('outline') + this.config = { + splitCommand: c.get('splitCommand'), + switchSortKey: c.get('switchSortKey'), + followCursor: c.get('followCursor'), + keepWindow: c.get('keepWindow'), + expandLevel: c.get('expandLevel'), + autoWidth: c.get('autoWidth'), + checkBufferSwitch: c.get('checkBufferSwitch'), + detailAsDescription: c.get('detailAsDescription'), + sortBy: c.get<'position' | 'name' | 'category'>('sortBy'), + showLineNumber: c.get('showLineNumber'), + codeActionKinds: c.get('codeActionKinds') + } + } + } + + private convertSymbolToNode(documentSymbol: DocumentSymbol, sortFn: (a: OutlineNode, b: OutlineNode) => number): OutlineNode { + let descs = [] + let { detailAsDescription, showLineNumber } = this.config + if (detailAsDescription && documentSymbol.detail) descs.push(documentSymbol.detail) + if (showLineNumber) descs.push(`${documentSymbol.selectionRange.start.line + 1}`) + return { + label: documentSymbol.name, + tooltip: detailAsDescription ? undefined : documentSymbol.detail, + description: descs.join(' '), + icon: this.handler.getIcon(documentSymbol.kind), + deprecated: documentSymbol.tags?.includes(SymbolTag.Deprecated), + kind: documentSymbol.kind, + range: documentSymbol.range, + selectRange: documentSymbol.selectionRange, + children: Array.isArray(documentSymbol.children) ? documentSymbol.children.map(o => { + return this.convertSymbolToNode(o, sortFn) + }).sort(sortFn) : undefined + } + } + + private setMessage(bufnr: number, msg: string | undefined): void { + let views = this.treeViewList.filter(v => v.valid && v.targetBufnr == bufnr) + if (views) { + views.forEach(view => { + view.message = msg + }) + } + } + + private convertSymbols(bufnr: number, symbols: DocumentSymbol[]): OutlineNode[] { + let sortBy = this.getSortBy(bufnr) + let sortFn = (a: OutlineNode, b: OutlineNode): number => { + if (sortBy === 'name') { + return a.label < b.label ? -1 : 1 + } + if (sortBy === 'category') { + if (a.kind == b.kind) return a.label < b.label ? -1 : 1 + return a.kind - b.kind + } + return comparePosition(a.selectRange.start, b.selectRange.start) + } + return symbols.map(s => this.convertSymbolToNode(s, sortFn)).sort(sortFn) + } + + public onSymbolsUpdate(bufnr: number, symbols: DocumentSymbol[]): void { + let provider = this.providersMap.get(bufnr) + if (provider) provider.update(this.convertSymbols(bufnr, symbols)) + } + + private createProvider(bufnr: number): BasicDataProvider { + let { nvim } = this + let disposable: Disposable + let provider = new BasicDataProvider({ + expandLevel: this.config.expandLevel, + provideData: async () => { + let buf = this.buffers.getItem(bufnr) + if (!buf) throw new Error('Document not attached') + let doc = workspace.getDocument(bufnr) + if (!languages.hasProvider('documentSymbol', doc.textDocument)) { + throw new Error('Document symbol provider not found') + } + let meta = languages.getDocumentSymbolMetadata(doc.textDocument) + if (meta && meta.label) { + let views = this.treeViewList.filter(v => v.valid && v.targetBufnr == bufnr) + views.forEach(view => view.description = meta.label) + } + this.setMessage(bufnr, 'Loading document symbols') + let arr = await buf.getSymbols() + if (!arr || arr.length == 0) { + // server may return empty symbols on buffer initialize, throw error to force reload. + throw new Error('Empty symbols returned from language server. ') + } + this.setMessage(bufnr, undefined) + return this.convertSymbols(bufnr, arr) + }, + handleClick: async item => { + let winnr = await nvim.call('bufwinnr', [bufnr]) + if (winnr == -1) return + nvim.pauseNotification() + nvim.command(`${winnr}wincmd w`, true) + let pos = item.selectRange.start + nvim.call('coc#cursor#move_to', [pos.line, pos.character], true) + nvim.command(`normal! zz`, true) + let buf = nvim.createBuffer(bufnr) + buf.highlightRanges('outline-hover', 'CocHoverRange', [item.selectRange]) + nvim.command('redraw', true) + await nvim.resumeNotification() + setTimeout(() => { + buf.clearNamespace('outline-hover') + nvim.command('redraw', true) + }, global.hasOwnProperty('__TEST__') ? 10 : 300) + }, + resolveActions: async (_, element) => { + let winnr = await nvim.call('bufwinnr', [bufnr]) + if (winnr == -1) return + let doc = workspace.getDocument(bufnr) + let actions = await this.handler.getCodeActions(doc, element.range, this.config.codeActionKinds) + let arr = actions.map(o => { + return { + title: o.title, + handler: async () => { + let position = element.range.start + await nvim.command(`${winnr}wincmd w`) + await this.nvim.call('coc#cursor#move_to', [position.line, position.character]) + await this.handler.applyCodeAction(o) + } + } + }) + return [...arr, { + title: 'Visual Select', + handler: async item => { + await nvim.command(`${winnr}wincmd w`) + await window.selectRange(item.range) + } + }] + }, + onDispose: () => { + if (disposable) disposable.dispose() + for (let view of this.treeViewList) { + if (view.provider === provider) view.dispose() + } + } + }) + return provider + } + + private getSortBy(bufnr: number): string { + return this.sortByMap.get(bufnr) ?? this.config.sortBy + } + + private async showOutline(bufnr: number, tabnr: number): Promise> { + if (!this.providersMap.has(bufnr)) { + this.providersMap.set(bufnr, this.createProvider(bufnr)) + } + let treeView = this.treeViewList.find(v => v.valid && v.targetBufnr == bufnr && v.targetTabnr == tabnr) + if (!treeView) { + treeView = new BasicTreeView('OUTLINE', { + autoWidth: this.config.autoWidth, + bufhidden: 'hide', + enableFilter: true, + treeDataProvider: this.providersMap.get(bufnr), + }) + let sortBy = this.getSortBy(bufnr) + treeView.description = `${sortBy[0].toUpperCase()}${sortBy.slice(1)}` + this.treeViewList.push(treeView) + treeView.onDispose(() => { + let idx = this.treeViewList.findIndex(v => v === treeView) + if (idx !== -1) this.treeViewList.splice(idx, 1) + }) + } + let shown = await treeView.show(this.config.splitCommand) + if (shown) { + treeView.registerLocalKeymap('n', this.config.switchSortKey, async () => { + let arr = ['category', 'name', 'position'] + let curr = this.getSortBy(bufnr) + let items = arr.map(s => { + return { text: s, disabled: s === curr } + }) + let res = await window.showMenuPicker(items, { title: 'Choose sort method' }) + if (res < 0) return + let sortBy = arr[res] + this.sortByMap.set(bufnr, sortBy) + let views = this.treeViewList.filter(o => o.targetBufnr == bufnr) + views.forEach(view => { + view.description = `${sortBy[0].toUpperCase()}${sortBy.slice(1)}` + }) + let item = this.buffers.getItem(bufnr) + if (item && item.symbols) this.onSymbolsUpdate(bufnr, item.symbols) + }) + } + return treeView + } + + /** + * Create outline view. + */ + public async show(keep?: number): Promise { + let [filetype, bufnr, tabnr, winid] = await this.nvim.eval('[&filetype,bufnr("%"),tabpagenr(),win_getid()]') as [string, number, number, number] + if (filetype === 'coctree') return + let position = await window.getCursorPosition() + let treeView = await this.showOutline(bufnr, tabnr) + if (keep == 1 || (keep === undefined && this.config.keepWindow)) { + await this.nvim.command(`noa call win_gotoid(${winid})`) + } else if (this.config.followCursor) { + let disposable = treeView.onDidRefrash(async () => { + disposable.dispose() + let filetype = await this.nvim.eval('&filetype') + if (filetype == 'coctree' && treeView.visible) { + await this.revealPosition(treeView, position) + } + }) + } + } + + public has(bufnr: number): boolean { + return this.providersMap.has(bufnr) + } + + /** + * Hide outline of current tab. + */ + public async hide(): Promise { + let winid = await this.nvim.call('coc#window#find', ['cocViewId', 'OUTLINE']) as number + if (winid == -1) return + await this.nvim.call('coc#window#close', [winid]) + } + + public dispose(): void { + for (let view of this.treeViewList) { + view.dispose() + } + this.treeViewList = [] + for (let provider of this.providersMap.values()) { + provider.dispose() + } + this.providersMap.clear() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/handler/symbols/util.ts b/sources_non_forked/coc.nvim/src/handler/symbols/util.ts new file mode 100644 index 00000000..061bd7e1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/symbols/util.ts @@ -0,0 +1,63 @@ +'use strict' +import { DocumentSymbol, Range, SymbolInformation, SymbolTag } from 'vscode-languageserver-protocol' +import { getSymbolKind } from '../../util/convert' +import { comparePosition } from '../../util/position' + +export interface SymbolInfo { + filepath?: string + lnum: number + col: number + text: string + kind: string + level?: number + detail?: string + deprecated?: boolean + containerName?: string + range: Range + selectionRange?: Range +} + +export function convertSymbols(symbols: DocumentSymbol[]): SymbolInfo[] { + let res: SymbolInfo[] = [] + let arr = symbols.slice() + arr.sort(sortDocumentSymbols) + arr.forEach(s => addDocumentSymbol(res, s, 0)) + return res +} + +export function sortDocumentSymbols(a: DocumentSymbol, b: DocumentSymbol): number { + let ra = a.selectionRange + let rb = b.selectionRange + return comparePosition(ra.start, rb.start) +} + +export function addDocumentSymbol(res: SymbolInfo[], sym: DocumentSymbol, level: number): void { + let { name, selectionRange, detail, kind, children, range, tags } = sym + let { start } = selectionRange || range + let obj: SymbolInfo = { + col: start.character + 1, + lnum: start.line + 1, + text: name, + level, + kind: getSymbolKind(kind), + range, + selectionRange + } + if (detail) obj.detail = detail + if (tags && tags.includes(SymbolTag.Deprecated)) obj.deprecated = true + res.push(obj) + if (children && children.length) { + children.sort(sortDocumentSymbols) + for (let sym of children) { + addDocumentSymbol(res, sym, level + 1) + } + } +} + +function isDocumentSymbol(a: DocumentSymbol | SymbolInformation): a is DocumentSymbol { + return a && !a.hasOwnProperty('location') +} + +export function isDocumentSymbols(a: DocumentSymbol[] | SymbolInformation[]): a is DocumentSymbol[] { + return isDocumentSymbol(a[0]) +} diff --git a/sources_non_forked/coc.nvim/src/handler/workspace.ts b/sources_non_forked/coc.nvim/src/handler/workspace.ts new file mode 100644 index 00000000..317c064e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/handler/workspace.ts @@ -0,0 +1,104 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { URI } from 'vscode-uri' +import fs from 'fs' +import path from 'path' +import extensions from '../extensions' +import { HandlerDelegate, PatternType, WorkspaceConfiguration } from '../types' +import workspace from '../workspace' +import window from '../window' +import snippetManager from '../snippets/manager' +const logger = require('../util/logger')('handler-workspace') +declare const REVISION + +interface RootPatterns { + buffer: string[] + server: string[] + global: string[] +} + +export default class WorkspaceHandler { + constructor( + private nvim: Neovim, + private handler: HandlerDelegate + ) { + } + + public async openLog(): Promise { + let file = logger.logfile + await workspace.jumpTo(URI.file(file).toString()) + } + + public async doAutocmd(id: number, args: any[]): Promise { + await workspace.autocmds.doAutocmd(id, args) + } + + public async getConfiguration(key: string): Promise { + let document = await workspace.document + return workspace.getConfiguration(key, document ? document.uri : undefined) + } + + public getRootPatterns(bufnr: number): RootPatterns | null { + let doc = workspace.getDocument(bufnr) + if (!doc) return null + return { + buffer: workspace.workspaceFolderControl.getRootPatterns(doc, PatternType.Buffer), + server: workspace.workspaceFolderControl.getRootPatterns(doc, PatternType.LanguageServer) || [], + global: workspace.workspaceFolderControl.getRootPatterns(doc, PatternType.Global) + } + } + + public async ensureDocument(): Promise { + let doc = await workspace.document + return doc && !doc.isCommandLine && doc.attached + } + + public async doKeymap(key: string, defaultReturn = '', pressed?: string): Promise { + return await workspace.keymaps.doKeymap(key, defaultReturn, pressed) + } + + public async snippetCheck(checkExpand: boolean, checkJump: boolean): Promise { + if (checkExpand && !extensions.has('coc-snippets')) { + this.nvim.echoError('coc-snippets required for check expand status!') + return false + } + if (checkJump) { + let jumpable = snippetManager.jumpable() + if (jumpable) return true + } + if (checkExpand) { + let api = extensions.getExtensionApi('coc-snippets') as any + if (api && api.hasOwnProperty('expandable')) { + let expandable = await Promise.resolve(api.expandable()) + if (expandable) return true + } + } + return false + } + + public async showInfo(): Promise { + let lines: string[] = [] + let version = workspace.version + (typeof REVISION === 'string' ? '-' + REVISION : '') + lines.push('## versions') + lines.push('') + let out = await this.nvim.call('execute', ['version']) as string + let first = out.trim().split(/\r?\n/, 2)[0].replace(/\(.*\)/, '').trim() + lines.push('vim version: ' + first + `${workspace.isVim ? ' ' + workspace.env.version : ''}`) + lines.push('node version: ' + process.version) + lines.push('coc.nvim version: ' + version) + lines.push('coc.nvim directory: ' + path.dirname(__dirname)) + lines.push('term: ' + (process.env.TERM_PROGRAM || process.env.TERM)) + lines.push('platform: ' + process.platform) + lines.push('') + lines.push('## Log of coc.nvim') + lines.push('') + let file = logger.logfile + if (fs.existsSync(file)) { + let content = fs.readFileSync(file, { encoding: 'utf8' }) + lines.push(...content.split(/\r?\n/)) + } + await this.nvim.command('vnew +setl\\ buftype=nofile\\ bufhidden=wipe\\ nobuflisted') + let buf = await this.nvim.buffer + await buf.setLines(lines, { start: 0, end: -1, strictIndexing: false }) + } +} diff --git a/sources_non_forked/coc.nvim/src/index.ts b/sources_non_forked/coc.nvim/src/index.ts new file mode 100644 index 00000000..e6b50c1f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/index.ts @@ -0,0 +1,152 @@ +'use strict' +import commands from './commands' +import events from './events' +import languages from './languages' +import Mru from './model/mru' +import FloatFactory from './model/floatFactory' +import fetch from './model/fetch' +import download from './model/download' +import Highligher from './model/highligher' +import RelativePattern from './model/relativePattern' +import services from './services' +import sources from './sources/index' +import workspace from './workspace' +import window from './window' +import extensions from './extensions' +import listManager from './list/manager' +import snippetManager from './snippets/manager' +import { SnippetString } from './snippets/string' +import diagnosticManager from './diagnostic/manager' +import { ansiparse } from './util/ansiparse' +import BasicList from './list/basic' +import { Mutex } from './util/mutex' +import { URI } from 'vscode-uri' +import { + CodeActionKind, + Disposable, + Position, + Range, + TextEdit, + RequestType, + RequestType0, + NotificationType, + NotificationType0, + Event, + CancellationToken, + CancellationTokenSource, + Emitter, + Diagnostic, + DiagnosticSeverity, + CompletionItemKind, + InsertTextFormat, + Location, + LocationLink, + MarkupKind, + FileChangeType, + SignatureHelpTriggerKind, + SymbolKind, + DocumentHighlightKind, + CompletionTriggerKind, + DiagnosticTag, + ProgressType, + UniquenessLevel, + MonikerKind, +} from 'vscode-languageserver-protocol' + +import { PatternType, SourceType, MessageLevel, ConfigurationTarget, ServiceStat, FileType } from './types' +import { + State, + NullLogger, + ClientState, + CloseAction, + ErrorAction, + TransportKind, + SettingMonitor, + LanguageClient, + MessageTransports, + RevealOutputChannelOn, +} from './language-client' + +import { disposeAll, concurrent, watchFile, wait, runCommand, isRunning, executable } from './util' +import { TreeItem, TreeItemCollapsibleState } from './tree/index' +import { SemanticTokensBuilder } from './model/semanticTokensBuilder' + +module.exports = { + Uri: URI, + NullLogger, + SettingMonitor, + LanguageClient, + CancellationTokenSource, + ProgressType, + RequestType, + RequestType0, + NotificationType, + NotificationType0, + Highligher, + Mru, + Emitter, + SnippetString, + BasicList, + Mutex, + TreeItem, + SemanticTokensBuilder, + FloatFactory, + RelativePattern, + UniquenessLevel, + MonikerKind, + PatternType, + SourceType, + MessageLevel, + ConfigurationTarget, + ServiceStat, + FileType, + State, + ClientState, + CloseAction, + ErrorAction, + TransportKind, + MessageTransports, + RevealOutputChannelOn, + MarkupKind, + DiagnosticTag, + DocumentHighlightKind, + SymbolKind, + SignatureHelpTriggerKind, + FileChangeType, + CodeActionKind, + Diagnostic, + DiagnosticSeverity, + CompletionItemKind, + InsertTextFormat, + Location, + LocationLink, + CancellationToken, + Position, + Range, + TextEdit, + Disposable, + Event, + workspace, + window, + CompletionTriggerKind, + snippetManager, + events, + services, + commands, + sources, + languages, + diagnosticManager, + extensions, + listManager, + TreeItemCollapsibleState, + fetch, + download, + ansiparse, + disposeAll, + concurrent, + watchFile, + wait, + runCommand, + isRunning, + executable, +} diff --git a/sources_non_forked/coc.nvim/src/inlayHint.ts b/sources_non_forked/coc.nvim/src/inlayHint.ts new file mode 100644 index 00000000..3f8bd1ce --- /dev/null +++ b/sources_non_forked/coc.nvim/src/inlayHint.ts @@ -0,0 +1,179 @@ +'use strict' +import { MarkupContent, TextEdit, Position, Location, Command } from 'vscode-languageserver-protocol' +import * as Is from './util/is' + +/** + * Inlay hint kinds. + * + * @since 3.17.0 + * @proposed + */ +export namespace InlayHintKind { + + /** + * An inlay hint that for a type annotation. + */ + export const Type = 1 + + /** + * An inlay hint that is for a parameter. + */ + export const Parameter = 2 + + export function is(value: number): value is InlayHintKind { + return value === 1 || value === 2 + } +} + +// eslint-disable-next-line no-redeclare +export type InlayHintKind = 1 | 2 + +/** + * An inlay hint label part allows for interactive and composite labels + * of inlay hints. + * + * @since 3.17.0 + * @proposed + */ +export interface InlayHintLabelPart { + + /** + * The value of this label part. + */ + value: string + + /** + * The tooltip text when you hover over this label part. Depending on + * the client capability `inlayHint.resolveSupport` clients might resolve + * this property late using the resolve request. + */ + tooltip?: string | MarkupContent + + /** + * An optional source code location that represents this + * label part. + * + * The editor will use this location for the hover and for code navigation + * features: This part will become a clickable link that resolves to the + * definition of the symbol at the given location (not necessarily the + * location itself), it shows the hover that shows at the given location, + * and it shows a context menu with further code navigation commands. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + location?: Location + + /** + * An optional command for this label part. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + command?: Command +} + +// eslint-disable-next-line no-redeclare +export namespace InlayHintLabelPart { + + export function create(value: string): InlayHintLabelPart { + return { value } + } + + export function is(value: any): value is InlayHintLabelPart { + const candidate: InlayHintLabelPart = value + return Is.objectLiteral(candidate) + && (candidate.tooltip === undefined || Is.string(candidate.tooltip) || MarkupContent.is(candidate.tooltip)) + && (candidate.location === undefined || Location.is(candidate.location)) + && (candidate.command === undefined || Command.is(candidate.command)) + } +} + +/** + * Inlay hint information. + * + * @since 3.17.0 + * @proposed + */ +export interface InlayHint { + + /** + * The position of this hint. + */ + position: Position + + /** + * The label of this hint. A human readable string or an array of + * InlayHintLabelPart label parts. + * + * *Note* that neither the string nor the label part can be empty. + */ + label: string | InlayHintLabelPart[] + + /** + * The kind of this hint. Can be omitted in which case the client + * should fall back to a reasonable default. + */ + kind?: InlayHintKind + + /** + * Optional text edits that are performed when accepting this inlay hint. + * + * *Note* that edits are expected to change the document so that the inlay + * hint (or its nearest variant) is now part of the document and the inlay + * hint itself is now obsolete. + */ + textEdits?: TextEdit[] + + /** + * The tooltip text when you hover over this item. + */ + tooltip?: string | MarkupContent + + /** + * Render padding before the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + paddingLeft?: boolean + + /** + * Render padding after the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + paddingRight?: boolean + + /** + * A data entry field that is preserved on a inlay hint between + * a `textDocument/inlayHint` and a `inlayHint/resolve` request. + */ + data?: any +} + +// eslint-disable-next-line no-redeclare +export namespace InlayHint { + + export function create(position: Position, label: string | InlayHintLabelPart[], kind?: InlayHintKind): InlayHint { + const result: InlayHint = { position, label } + if (kind !== undefined) { + result.kind = kind + } + return result + } + + export function is(value: any): value is InlayHint { + const candidate: InlayHint = value + return Is.objectLiteral(candidate) && Position.is(candidate.position) + && (Is.string(candidate.label) || Is.typedArray(candidate.label, InlayHintLabelPart.is)) + && (candidate.kind === undefined || InlayHintKind.is(candidate.kind)) + && (candidate.textEdits === undefined) || Is.typedArray(candidate.textEdits, TextEdit.is) + && (candidate.tooltip === undefined || Is.string(candidate.tooltip) || MarkupContent.is(candidate.tooltip)) + && (candidate.paddingLeft === undefined || Is.boolean(candidate.paddingLeft)) + && (candidate.paddingRight === undefined || Is.boolean(candidate.paddingRight)) + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/LICENSE.txt b/sources_non_forked/coc.nvim/src/language-client/LICENSE.txt new file mode 100644 index 00000000..9afc63d4 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/LICENSE.txt @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2015 - present Microsoft Corporation + +All rights reserved. + +Permission 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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE 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. diff --git a/sources_non_forked/coc.nvim/src/language-client/callHierarchy.ts b/sources_non_forked/coc.nvim/src/language-client/callHierarchy.ts new file mode 100644 index 00000000..f8ab2f42 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/callHierarchy.ts @@ -0,0 +1,116 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { + CallHierarchyClientCapabilities, CallHierarchyIncomingCall, CallHierarchyIncomingCallsRequest, CallHierarchyItem, CallHierarchyOptions, CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsRequest, CallHierarchyPrepareRequest, CallHierarchyRegistrationOptions, CancellationToken, ClientCapabilities, Disposable, DocumentSelector, Position, ServerCapabilities +} from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { CallHierarchyProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' +import { asTextDocumentPositionParams } from './utils/converter' + +export interface PrepareCallHierarchySignature { + (this: void, document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +export interface CallHierarchyIncomingCallsSignature { + (this: void, item: CallHierarchyItem, token: CancellationToken): ProviderResult +} + +export interface CallHierarchyOutgoingCallsSignature { + (this: void, item: CallHierarchyItem, token: CancellationToken): ProviderResult +} + +/** + * Call hierarchy middleware + * + * @since 3.16.0 + */ +export interface CallHierarchyMiddleware { + prepareCallHierarchy?: (this: void, document: TextDocument, positions: Position, token: CancellationToken, next: PrepareCallHierarchySignature) => ProviderResult + provideCallHierarchyIncomingCalls?: (this: void, item: CallHierarchyItem, token: CancellationToken, next: CallHierarchyIncomingCallsSignature) => ProviderResult + provideCallHierarchyOutgoingCalls?: (this: void, item: CallHierarchyItem, token: CancellationToken, next: CallHierarchyOutgoingCallsSignature) => ProviderResult +} + +export class CallHierarchyFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, CallHierarchyPrepareRequest.type) + } + + public fillClientCapabilities(cap: ClientCapabilities): void { + const capabilities: ClientCapabilities & CallHierarchyClientCapabilities = cap as ClientCapabilities & CallHierarchyClientCapabilities + const capability = ensure(ensure(capabilities, 'textDocument')!, 'callHierarchy')! + capability.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const [id, options] = this.getRegistration(documentSelector, capabilities.callHierarchyProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: CallHierarchyRegistrationOptions): [Disposable, CallHierarchyProvider] { + const provider: CallHierarchyProvider = { + prepareCallHierarchy: (document: TextDocument, position: Position, token: CancellationToken) => { + const client = this._client + const prepareCallHierarchy: PrepareCallHierarchySignature = (document, position, token) => { + const params = asTextDocumentPositionParams(document, position) + return client.sendRequest(CallHierarchyPrepareRequest.type, params, token).then( + res => res, + error => { + return client.handleFailedRequest(CallHierarchyPrepareRequest.type, token, error, null) + } + ) + } + + const middleware = client.clientOptions.middleware + return middleware.prepareCallHierarchy + ? middleware.prepareCallHierarchy(document, position, token, prepareCallHierarchy) + : prepareCallHierarchy(document, position, token) + }, + + provideCallHierarchyIncomingCalls: (item: CallHierarchyItem, token: CancellationToken) => { + const client = this._client + const provideCallHierarchyIncomingCalls: CallHierarchyIncomingCallsSignature = (item, token) => { + return client.sendRequest(CallHierarchyIncomingCallsRequest.type, { item }, token).then( + res => res, + error => { + return client.handleFailedRequest(CallHierarchyIncomingCallsRequest.type, token, error, null) + } + ) + } + + const middleware = client.clientOptions.middleware + return middleware.provideCallHierarchyIncomingCalls + ? middleware.provideCallHierarchyIncomingCalls(item, token, provideCallHierarchyIncomingCalls) + : provideCallHierarchyIncomingCalls(item, token) + }, + + provideCallHierarchyOutgoingCalls: (item: CallHierarchyItem, token: CancellationToken) => { + const client = this._client + const provideCallHierarchyOutgoingCalls: CallHierarchyOutgoingCallsSignature = (item, token) => { + return client.sendRequest(CallHierarchyOutgoingCallsRequest.type, { item }, token).then( + res => res, + error => { + return client.handleFailedRequest(CallHierarchyOutgoingCallsRequest.type, token, error, null) + } + ) + } + + const middleware = client.clientOptions.middleware + return middleware.provideCallHierarchyOutgoingCalls + ? middleware.provideCallHierarchyOutgoingCalls(item, token, provideCallHierarchyOutgoingCalls) + : provideCallHierarchyOutgoingCalls(item, token) + } + } + + return [languages.registerCallHierarchyProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/client.ts b/sources_non_forked/coc.nvim/src/language-client/client.ts new file mode 100644 index 00000000..6d0f15f0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/client.ts @@ -0,0 +1,4430 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +/* eslint-disable */ +import path from 'path' +import { ApplyWorkspaceEditParams, CompletionItemTag, ApplyWorkspaceEditRequest, ApplyWorkspaceEditResponse, CancellationToken, ClientCapabilities, CodeAction, CodeActionContext, CodeActionKind, CodeActionOptions, CodeActionParams, CodeActionRegistrationOptions, CodeActionRequest, CodeLens, CodeLensOptions, CodeLensRegistrationOptions, CodeLensRequest, CodeLensResolveRequest, Command, CompletionContext, CompletionItem, CompletionItemKind, CompletionList, CompletionOptions, CompletionRegistrationOptions, CompletionRequest, CompletionResolveRequest, createProtocolConnection, DeclarationRequest, Definition, DefinitionOptions, DefinitionRegistrationOptions, DefinitionRequest, Diagnostic, DiagnosticSeverity, DiagnosticTag, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeConfigurationRegistrationOptions, DidChangeTextDocumentNotification, DidChangeTextDocumentParams, DidChangeWatchedFilesNotification, DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, DidCloseTextDocumentNotification, DidCloseTextDocumentParams, DidOpenTextDocumentNotification, DidOpenTextDocumentParams, DidSaveTextDocumentNotification, DidSaveTextDocumentParams, Disposable, DocumentColorRequest, DocumentFormattingOptions, DocumentFormattingParams, DocumentFormattingRequest, DocumentHighlight, DocumentHighlightOptions, DocumentHighlightRegistrationOptions, DocumentHighlightRequest, DocumentLink, DocumentLinkOptions, DocumentLinkRegistrationOptions, DocumentLinkRequest, DocumentLinkResolveRequest, DocumentOnTypeFormattingOptions, DocumentOnTypeFormattingParams, DocumentOnTypeFormattingRegistrationOptions, DocumentOnTypeFormattingRequest, DocumentRangeFormattingOptions, DocumentRangeFormattingParams, DocumentRangeFormattingRegistrationOptions, DocumentRangeFormattingRequest, DocumentSelector, DocumentSymbol, DocumentSymbolOptions, DocumentSymbolRegistrationOptions, DocumentSymbolRequest, Emitter, Event, ExecuteCommandParams, ExecuteCommandRegistrationOptions, ExecuteCommandRequest, ExitNotification, FailureHandlingKind, FileChangeType, FileEvent, FoldingRangeRequest, FormattingOptions, GenericNotificationHandler, GenericRequestHandler, Hover, HoverOptions, HoverRegistrationOptions, HoverRequest, ImplementationRequest, InitializedNotification, InitializeError, InitializeParams, InitializeRequest, InitializeResult, Location, Logger, LogMessageNotification, LogMessageParams, MarkupKind, Message, MessageReader, MessageType, MessageWriter, NotificationHandler, NotificationHandler0, NotificationType, NotificationType0, Position, PrepareRenameRequest, ProgressToken, ProgressType, PublishDiagnosticsNotification, PublishDiagnosticsParams, Range, ReferenceOptions, ReferenceRegistrationOptions, ReferencesRequest, RegistrationParams, RegistrationRequest, RenameOptions, RenameParams, RenameRegistrationOptions, RenameRequest, RequestHandler, RequestHandler0, RequestType, RequestType0, ResourceOperationKind, ResponseError, SelectionRangeRequest, ServerCapabilities, ShowMessageNotification, ShowMessageParams, ShowMessageRequest, ShutdownRequest, SignatureHelp, SignatureHelpOptions, SignatureHelpRegistrationOptions, SignatureHelpRequest, StaticRegistrationOptions, SymbolInformation, SymbolKind, SymbolTag, TelemetryEventNotification, TextDocumentChangeRegistrationOptions, TextDocumentEdit, TextDocumentPositionParams, TextDocumentRegistrationOptions, TextDocumentSaveRegistrationOptions, TextDocumentSyncKind, TextDocumentSyncOptions, TextEdit, Trace, TraceFormat, TraceOptions, Tracer, TypeDefinitionRequest, UnregistrationParams, UnregistrationRequest, WatchKind, WillSaveTextDocumentNotification, WillSaveTextDocumentParams, WillSaveTextDocumentWaitUntilRequest, WorkDoneProgressOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceSymbolRegistrationOptions, WorkspaceSymbolRequest, SignatureHelpContext, WorkDoneProgressBegin, WorkDoneProgressEnd, WorkDoneProgressReport, WorkDoneProgress, DefinitionLink, ProtocolRequestType0, ProtocolRequestType, MessageSignature, ProtocolNotificationType0, ProtocolNotificationType, RegistrationType, LSPErrorCodes, SaveOptions, CancellationStrategy, CallHierarchyPrepareRequest, SemanticTokensRegistrationType, CodeActionResolveRequest, CodeLensRefreshRequest, ShowDocumentParams, ShowDocumentRequest, ShowDocumentResult, InsertTextMode, LinkedEditingRangeRequest, DidCreateFilesNotification, FileOperationRegistrationOptions, DidRenameFilesNotification, DidDeleteFilesNotification, WillCreateFilesRequest, WillRenameFilesRequest, WillDeleteFilesRequest, ShowMessageRequestParams, MessageActionItem, PrepareSupportDefaultBehavior } from 'vscode-languageserver-protocol' +import { TextDocument } from "vscode-languageserver-textdocument" +import { URI } from 'vscode-uri' +import commands from '../commands' +import languages from '../languages' +import { ConfigurationChangeEvent, FileSystemWatcher as FileWatcher } from '../types' +import { CallHierarchyProvider, CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentLinkProvider, DocumentRangeFormattingEditProvider, DocumentSymbolProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, LinkedEditingRangeProvider, OnTypeFormattingEditProvider, ProviderResult, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, WorkspaceSymbolProvider } from '../provider' +import { FileCreateEvent, FileDeleteEvent, FileRenameEvent, FileWillCreateEvent, FileWillDeleteEvent, FileWillRenameEvent, OutputChannel, TextDocumentWillSaveEvent, Thenable, MessageItem } from '../types' +import { resolveRoot, sameFile } from '../util/fs' +import * as Is from '../util/is' +import { omit } from '../util/lodash' +import { mergeConfigProperties } from '../configuration/util' +import DiagnosticCollection from '../diagnostic/collection' +import window from '../window' +import workspace from '../workspace' +import sources from '../sources' +import { CallHierarchyMiddleware } from './callHierarchy' +import { ColorProviderMiddleware } from './colorProvider' +import { ConfigurationWorkspaceMiddleware } from './configuration' +import { DeclarationMiddleware } from './declaration' +import { FoldingRangeProviderMiddleware } from './foldingRange' +import { ImplementationMiddleware } from './implementation' +import { ProgressPart } from './progressPart' +import { SelectionRangeProviderMiddleware } from './selectionRange' +import { SemanticTokensMiddleware, SemanticTokensProviders } from './semanticTokens' +import { TypeDefinitionMiddleware } from './typeDefinition' +import { FileOperationsMiddleware } from './fileOperations' +import { Delayer } from './utils/async' +import os from 'os' +import * as cv from './utils/converter' +import * as UUID from './utils/uuid' +import { WorkspaceFolderWorkspaceMiddleware } from './workspaceFolders' +import { LinkedEditingRangeMiddleware } from './linkedEditingRange' +import { comparePosition } from '../util/position' +import { disposeAll } from '../util' + +const logger = require('../util/logger')('language-client-client') + +interface IConnection { + listen(): void + unlisten(): void + + sendRequest(type: ProtocolRequestType0, token?: CancellationToken): Promise + sendRequest(type: ProtocolRequestType, params: P, token?: CancellationToken): Promise + sendRequest(type: RequestType0, token?: CancellationToken): Promise + sendRequest(type: RequestType, params: P, token?: CancellationToken): Promise + sendRequest(method: string, token?: CancellationToken): Promise + sendRequest(method: string, param: any, token?: CancellationToken): Promise + sendRequest(type: string | MessageSignature, ...params: any[]): Promise + + onRequest(type: ProtocolRequestType0, handler: RequestHandler0): Disposable + onRequest(type: ProtocolRequestType, handler: RequestHandler): Disposable + onRequest(type: RequestType0, handler: RequestHandler0): Disposable + onRequest(type: RequestType, handler: RequestHandler): Disposable + onRequest(method: string, handler: GenericRequestHandler): Disposable + onRequest(method: string | MessageSignature, handler: GenericRequestHandler): Disposable + + sendNotification(type: ProtocolNotificationType0): void + sendNotification(type: ProtocolNotificationType, params?: P): void + sendNotification(type: NotificationType0): void + sendNotification

    (type: NotificationType

    , params?: P): void + sendNotification(method: string): void + sendNotification(method: string, params: any): void + sendNotification(method: string | MessageSignature, params?: any): void + + onNotification(type: ProtocolNotificationType0, handler: NotificationHandler0): Disposable + onNotification(type: ProtocolNotificationType, handler: NotificationHandler

    ): Disposable + onNotification(type: NotificationType0, handler: NotificationHandler0): Disposable + onNotification

    (type: NotificationType

    , handler: NotificationHandler

    ): Disposable + onNotification(method: string, handler: GenericNotificationHandler): Disposable + onNotification(method: string | MessageSignature, handler: GenericNotificationHandler): Disposable + + onProgress

    (type: ProgressType

    , token: string | number, handler: NotificationHandler

    ): Disposable + sendProgress

    (type: ProgressType

    , token: string | number, value: P): void + + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void + trace(value: Trace, tracer: Tracer, traceOptions?: TraceOptions): void + + initialize(params: InitializeParams): Promise + shutdown(): Promise + exit(): void + + onLogMessage(handle: NotificationHandler): void + onShowMessage(handler: NotificationHandler): void + onTelemetry(handler: NotificationHandler): void + + didChangeConfiguration(params: DidChangeConfigurationParams): void + didChangeWatchedFiles(params: DidChangeWatchedFilesParams): void + + didOpenTextDocument(params: DidOpenTextDocumentParams): void + didChangeTextDocument(params: DidChangeTextDocumentParams): void + didCloseTextDocument(params: DidCloseTextDocumentParams): void + didSaveTextDocument(params: DidSaveTextDocumentParams): void + onDiagnostics(handler: NotificationHandler): void + + end(): void + dispose(): void +} + +class ConsoleLogger implements Logger { + public error(message: string): void { + logger.error(message) + } + public warn(message: string): void { + logger.warn(message) + } + public info(message: string): void { + logger.info(message) + } + public log(message: string): void { + logger.log(message) + } +} + +export class NullLogger implements Logger { + error(_message: string): void { + } + warn(_message: string): void { + } + info(_message: string): void { + } + log(_message: string): void { + } +} + +interface ConnectionErrorHandler { + (error: Error, message: Message | undefined, count: number | undefined): void +} + +interface ConnectionCloseHandler { + (): void +} + +interface ConnectionOptions { + cancellationStrategy: CancellationStrategy + maxRestartCount?: number +} + +function createConnection( + inputStream: NodeJS.ReadableStream, + outputStream: NodeJS.WritableStream, + errorHandler: ConnectionErrorHandler, + closeHandler: ConnectionCloseHandler, + options?: ConnectionOptions +): IConnection +function createConnection( + reader: MessageReader, + writer: MessageWriter, + errorHandler: ConnectionErrorHandler, + closeHandler: ConnectionCloseHandler, + options?: ConnectionOptions +): IConnection +function createConnection( + input: any, + output: any, + errorHandler: ConnectionErrorHandler, + closeHandler: ConnectionCloseHandler, + options?: ConnectionOptions +): IConnection { + let logger = new ConsoleLogger() + let connection = createProtocolConnection(input, output, logger, options) + let disposables: Disposable[] = [] + connection.onError(data => { + errorHandler(data[0], data[1], data[2]) + }, null, disposables) + connection.onClose(closeHandler, null, disposables) + let result: IConnection = { + listen: (): void => connection.listen(), + unlisten: (): void => { + disposeAll(disposables) + }, + + sendRequest: (type: string | MessageSignature, ...params: any[]): Promise => connection.sendRequest(Is.string(type) ? type : type.method, ...params), + onRequest: (type: string | MessageSignature, handler: GenericRequestHandler): Disposable => connection.onRequest(Is.string(type) ? type : type.method, handler), + + sendNotification: (type: string | MessageSignature, params?: any): void => connection.sendNotification(Is.string(type) ? type : type.method, params), + onNotification: (type: string | MessageSignature, handler: GenericNotificationHandler): Disposable => connection.onNotification(Is.string(type) ? type : type.method, handler), + + onProgress: connection.onProgress, + sendProgress: connection.sendProgress, + + trace: ( + value: Trace, + tracer: Tracer, + sendNotificationOrTraceOptions?: boolean | TraceOptions + ): void => { + const defaultTraceOptions: TraceOptions = { + sendNotification: false, + traceFormat: TraceFormat.Text + } + + if (sendNotificationOrTraceOptions === undefined) { + connection.trace(value, tracer, defaultTraceOptions) + } else if (Is.boolean(sendNotificationOrTraceOptions)) { + connection.trace(value, tracer, sendNotificationOrTraceOptions) + } else { + connection.trace(value, tracer, sendNotificationOrTraceOptions) + } + }, + + initialize: (params: InitializeParams) => + connection.sendRequest(InitializeRequest.type, params), + shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined), + exit: () => connection.sendNotification(ExitNotification.type), + + onLogMessage: (handler: NotificationHandler) => + connection.onNotification(LogMessageNotification.type, handler), + onShowMessage: (handler: NotificationHandler) => + connection.onNotification(ShowMessageNotification.type, handler), + onTelemetry: (handler: NotificationHandler) => + connection.onNotification(TelemetryEventNotification.type, handler), + + didChangeConfiguration: (params: DidChangeConfigurationParams) => + connection.sendNotification( + DidChangeConfigurationNotification.type, + params + ), + didChangeWatchedFiles: (params: DidChangeWatchedFilesParams) => + connection.sendNotification( + DidChangeWatchedFilesNotification.type, + params + ), + + didOpenTextDocument: (params: DidOpenTextDocumentParams) => + connection.sendNotification(DidOpenTextDocumentNotification.type, params), + didChangeTextDocument: (params: DidChangeTextDocumentParams) => + connection.sendNotification( + DidChangeTextDocumentNotification.type, + params + ), + didCloseTextDocument: (params: DidCloseTextDocumentParams) => + connection.sendNotification( + DidCloseTextDocumentNotification.type, + params + ), + didSaveTextDocument: (params: DidSaveTextDocumentParams) => + connection.sendNotification(DidSaveTextDocumentNotification.type, params), + + onDiagnostics: (handler: NotificationHandler) => + connection.onNotification(PublishDiagnosticsNotification.type, handler), + + end: () => connection.end(), + dispose: () => connection.dispose() + } + + return result +} + +/** + * An action to be performed when the connection is producing errors. + */ +export enum ErrorAction { + /** + * Continue running the server. + */ + Continue = 1, + /** + * Shutdown the server. + */ + Shutdown = 2 +} + +/** + * An action to be performed when the connection to a server got closed. + */ +export enum CloseAction { + /** + * Don't restart the server. The connection stays closed. + */ + DoNotRestart = 1, + /** + * Restart the server. + */ + Restart = 2 +} + +/** + * A pluggable error handler that is invoked when the connection is either + * producing errors or got closed. + */ +export interface ErrorHandler { + /** + * An error has occurred while writing or reading from the connection. + * + * @param error - the error received + * @param message - the message to be delivered to the server if know. + * @param count - a count indicating how often an error is received. Will + * be reset if a message got successfully send or received. + */ + error(error: Error, message: Message | undefined, count: number | undefined): ErrorAction + + /** + * The connection to the server got closed. + */ + closed(): CloseAction +} + +class DefaultErrorHandler implements ErrorHandler { + private readonly restarts: number[] + + constructor(private name: string, private maxRestartCount: number) { + this.restarts = [] + } + + public error(_error: Error, _message: Message, count: number): ErrorAction { + if (count && count <= 3) { + return ErrorAction.Continue + } + return ErrorAction.Shutdown + } + public closed(): CloseAction { + this.restarts.push(Date.now()) + if (this.restarts.length < this.maxRestartCount) { + return CloseAction.Restart + } else { + let diff = this.restarts[this.restarts.length - 1] - this.restarts[0] + if (diff <= 3 * 60 * 1000) { + window.showMessage(`The "${this.name}" server crashed ${this.maxRestartCount} times in the last 3 minutes. The server will not be restarted.`, 'error') + return CloseAction.DoNotRestart + } else { + this.restarts.shift() + return CloseAction.Restart + } + } + } +} + +export interface InitializationFailedHandler { + (error: ResponseError | Error | any): boolean +} + +export interface SynchronizeOptions { + configurationSection?: string | string[] + fileEvents?: FileWatcher | FileWatcher[] +} + +export enum RevealOutputChannelOn { + Info = 1, + Warn = 2, + Error = 3, + Never = 4 +} + +export interface HandleWorkDoneProgressSignature { + (this: void, token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd): void +} + +export interface HandleDiagnosticsSignature { + (this: void, uri: string, diagnostics: Diagnostic[]): void +} + +export interface ProvideCompletionItemsSignature { + ( + this: void, + document: TextDocument, + position: Position, + context: CompletionContext, + token: CancellationToken, + ): ProviderResult +} + +export interface ResolveCompletionItemSignature { + (this: void, item: CompletionItem, token: CancellationToken): ProviderResult +} + +export interface ProvideHoverSignature { + ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideSignatureHelpSignature { + ( + this: void, + document: TextDocument, + position: Position, + context: SignatureHelpContext, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideDefinitionSignature { + ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideReferencesSignature { + ( + this: void, + document: TextDocument, + position: Position, + options: { includeDeclaration: boolean }, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideDocumentHighlightsSignature { + ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideDocumentSymbolsSignature { + (this: void, document: TextDocument, token: CancellationToken): ProviderResult +} + +export interface ProvideWorkspaceSymbolsSignature { + (this: void, query: string, token: CancellationToken): ProviderResult +} + +export interface ProvideCodeActionsSignature { + ( + this: void, + document: TextDocument, + range: Range, + context: CodeActionContext, + token: CancellationToken + ): ProviderResult<(Command | CodeAction)[]> +} + +export interface ResolveCodeActionSignature { + (this: void, item: CodeAction, token: CancellationToken): ProviderResult +} + +export interface ProvideCodeLensesSignature { + (this: void, document: TextDocument, token: CancellationToken): ProviderResult +} + +export interface ResolveCodeLensSignature { + (this: void, codeLens: CodeLens, token: CancellationToken): ProviderResult +} + +export interface ProvideDocumentFormattingEditsSignature { + ( + this: void, + document: TextDocument, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideDocumentRangeFormattingEditsSignature { + ( + this: void, + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideOnTypeFormattingEditsSignature { + ( + this: void, + document: TextDocument, + position: Position, + ch: string, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult +} + +export interface PrepareRenameSignature { + (this: void, document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +export interface ProvideRenameEditsSignature { + ( + this: void, + document: TextDocument, + position: Position, + newName: string, + token: CancellationToken + ): ProviderResult +} + +export interface ProvideDocumentLinksSignature { + (this: void, document: TextDocument, token: CancellationToken): ProviderResult +} + +export interface ResolveDocumentLinkSignature { + (this: void, link: DocumentLink, token: CancellationToken): ProviderResult +} + +export interface ExecuteCommandSignature { + (this: void, command: string, args: any[]): ProviderResult +} + +export interface NextSignature { + (this: void, data: P, next: (data: P) => R): R +} + +export interface DidChangeConfigurationSignature { + (this: void, sections: string[] | undefined): void +} + +export interface DidChangeWatchedFileSignature { + (this: void, event: FileEvent): void +} + +export interface _WorkspaceMiddleware { + didChangeConfiguration?: ( + this: void, + sections: string[] | undefined, + next: DidChangeConfigurationSignature + ) => void + didChangeWatchedFile?: (this: void, event: FileEvent, next: DidChangeWatchedFileSignature) => void +} + +export type WorkspaceMiddleware = _WorkspaceMiddleware & ConfigurationWorkspaceMiddleware & WorkspaceFolderWorkspaceMiddleware & FileOperationsMiddleware + +export interface _WindowMiddleware { + showDocument?: (this: void, params: ShowDocumentParams, next: ShowDocumentRequest.HandlerSignature) => Promise +} + +export type WindowMiddleware = _WindowMiddleware + +/** + * The Middleware lets extensions intercept the request and notifications send and received + * from the server + */ +export interface _Middleware { + didOpen?: NextSignature + didChange?: NextSignature + willSave?: NextSignature + willSaveWaitUntil?: NextSignature< + TextDocumentWillSaveEvent, + Thenable + > + didSave?: NextSignature + didClose?: NextSignature + + handleDiagnostics?: ( + this: void, + uri: string, + diagnostics: Diagnostic[], + next: HandleDiagnosticsSignature + ) => void + provideCompletionItem?: ( + this: void, + document: TextDocument, + position: Position, + context: CompletionContext, + token: CancellationToken, + next: ProvideCompletionItemsSignature + ) => ProviderResult + resolveCompletionItem?: ( + this: void, + item: CompletionItem, + token: CancellationToken, + next: ResolveCompletionItemSignature + ) => ProviderResult + provideHover?: ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken, + next: ProvideHoverSignature + ) => ProviderResult + provideSignatureHelp?: ( + this: void, + document: TextDocument, + position: Position, + context: SignatureHelpContext, + token: CancellationToken, + next: ProvideSignatureHelpSignature + ) => ProviderResult + provideDefinition?: ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken, + next: ProvideDefinitionSignature + ) => ProviderResult + provideReferences?: ( + this: void, + document: TextDocument, + position: Position, + options: { includeDeclaration: boolean }, + token: CancellationToken, + next: ProvideReferencesSignature + ) => ProviderResult + provideDocumentHighlights?: ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken, + next: ProvideDocumentHighlightsSignature + ) => ProviderResult + provideDocumentSymbols?: ( + this: void, + document: TextDocument, + token: CancellationToken, + next: ProvideDocumentSymbolsSignature + ) => ProviderResult + provideWorkspaceSymbols?: ( + this: void, + query: string, + token: CancellationToken, + next: ProvideWorkspaceSymbolsSignature + ) => ProviderResult + provideCodeActions?: ( + this: void, + document: TextDocument, + range: Range, + context: CodeActionContext, + token: CancellationToken, + next: ProvideCodeActionsSignature + ) => ProviderResult<(Command | CodeAction)[]> + handleWorkDoneProgress?: ( + this: void, + token: ProgressToken, + params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd, next: HandleWorkDoneProgressSignature + ) => void + resolveCodeAction?: ( + this: void, + item: CodeAction, + token: CancellationToken, + next: ResolveCodeActionSignature + ) => ProviderResult + provideCodeLenses?: ( + this: void, + document: TextDocument, + token: CancellationToken, + next: ProvideCodeLensesSignature + ) => ProviderResult + resolveCodeLens?: ( + this: void, + codeLens: CodeLens, + token: CancellationToken, + next: ResolveCodeLensSignature + ) => ProviderResult + provideDocumentFormattingEdits?: ( + this: void, + document: TextDocument, + options: FormattingOptions, + token: CancellationToken, + next: ProvideDocumentFormattingEditsSignature + ) => ProviderResult + provideDocumentRangeFormattingEdits?: ( + this: void, + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken, + next: ProvideDocumentRangeFormattingEditsSignature + ) => ProviderResult + provideOnTypeFormattingEdits?: ( + this: void, + document: TextDocument, + position: Position, + ch: string, + options: FormattingOptions, + token: CancellationToken, + next: ProvideOnTypeFormattingEditsSignature + ) => ProviderResult + prepareRename?: ( + this: void, document: TextDocument, + position: Position, + token: CancellationToken, + next: PrepareRenameSignature + ) => ProviderResult + provideRenameEdits?: ( + this: void, + document: TextDocument, + position: Position, + newName: string, + token: CancellationToken, + next: ProvideRenameEditsSignature + ) => ProviderResult + provideDocumentLinks?: ( + this: void, + document: TextDocument, + token: CancellationToken, + next: ProvideDocumentLinksSignature + ) => ProviderResult + resolveDocumentLink?: ( + this: void, + link: DocumentLink, + token: CancellationToken, + next: ResolveDocumentLinkSignature + ) => ProviderResult + executeCommand?: ( + this: void, + command: string, + args: any[], + next: ExecuteCommandSignature + ) => ProviderResult + workspace?: WorkspaceMiddleware + window?: WindowMiddleware +} + +export type Middleware = _Middleware & + TypeDefinitionMiddleware & + ImplementationMiddleware & + ColorProviderMiddleware & + DeclarationMiddleware & + FoldingRangeProviderMiddleware & + CallHierarchyMiddleware & + SemanticTokensMiddleware & + LinkedEditingRangeMiddleware & + SelectionRangeProviderMiddleware + +export interface LanguageClientOptions { + ignoredRootPaths?: string[] + documentSelector?: DocumentSelector | string[] + synchronize?: SynchronizeOptions + disableWorkspaceFolders?: boolean + disableDiagnostics?: boolean + disableCompletion?: boolean + diagnosticCollectionName?: string + disableDynamicRegister?: boolean + disableSnippetCompletion?: boolean + disabledFeatures?: string[] + formatterPriority?: number + outputChannelName?: string + outputChannel?: OutputChannel + revealOutputChannelOn?: RevealOutputChannelOn + /** + * The encoding use to read stdout and stderr. Defaults + * to 'utf8' if omitted. + */ + stdioEncoding?: string + initializationOptions?: any | (() => any) + initializationFailedHandler?: InitializationFailedHandler + progressOnInitialization?: boolean + errorHandler?: ErrorHandler + middleware?: Middleware + workspaceFolder?: WorkspaceFolder + connectionOptions?: ConnectionOptions + markdown?: { + isTrusted?: boolean + supportHtml?: boolean + } +} + +interface ResolvedClientOptions { + ignoredRootPaths?: string[] + disabledFeatures: string[] + disableSnippetCompletion: boolean + disableDynamicRegister: boolean + formatterPriority: number + documentSelector?: DocumentSelector + synchronize: SynchronizeOptions + diagnosticCollectionName?: string + outputChannelName: string + revealOutputChannelOn: RevealOutputChannelOn + stdioEncoding: string + initializationOptions?: any | (() => any) + initializationFailedHandler?: InitializationFailedHandler + progressOnInitialization: boolean + errorHandler: ErrorHandler + middleware: Middleware + workspaceFolder?: WorkspaceFolder + connectionOptions?: ConnectionOptions + markdown: { + isTrusted: boolean + supportHtml?: boolean + } +} + +export enum State { + Stopped = 1, + Running = 2, + Starting = 3, +} + +export interface StateChangeEvent { + oldState: State + newState: State +} + +export enum ClientState { + Initial, + Starting, + StartFailed, + Running, + Stopping, + Stopped +} + +const SupportedSymbolKinds: SymbolKind[] = [ + SymbolKind.File, + SymbolKind.Module, + SymbolKind.Namespace, + SymbolKind.Package, + SymbolKind.Class, + SymbolKind.Method, + SymbolKind.Property, + SymbolKind.Field, + SymbolKind.Constructor, + SymbolKind.Enum, + SymbolKind.Interface, + SymbolKind.Function, + SymbolKind.Variable, + SymbolKind.Constant, + SymbolKind.String, + SymbolKind.Number, + SymbolKind.Boolean, + SymbolKind.Array, + SymbolKind.Object, + SymbolKind.Key, + SymbolKind.Null, + SymbolKind.EnumMember, + SymbolKind.Struct, + SymbolKind.Event, + SymbolKind.Operator, + SymbolKind.TypeParameter +] + +const SupportedCompletionItemKinds: CompletionItemKind[] = [ + CompletionItemKind.Text, + CompletionItemKind.Method, + CompletionItemKind.Function, + CompletionItemKind.Constructor, + CompletionItemKind.Field, + CompletionItemKind.Variable, + CompletionItemKind.Class, + CompletionItemKind.Interface, + CompletionItemKind.Module, + CompletionItemKind.Property, + CompletionItemKind.Unit, + CompletionItemKind.Value, + CompletionItemKind.Enum, + CompletionItemKind.Keyword, + CompletionItemKind.Snippet, + CompletionItemKind.Color, + CompletionItemKind.File, + CompletionItemKind.Reference, + CompletionItemKind.Folder, + CompletionItemKind.EnumMember, + CompletionItemKind.Constant, + CompletionItemKind.Struct, + CompletionItemKind.Event, + CompletionItemKind.Operator, + CompletionItemKind.TypeParameter +] + +const SupportedSymbolTags: SymbolTag[] = [ + SymbolTag.Deprecated +] + +export function ensure(target: T, key: K): T[K] { + if (target[key] === undefined) { + target[key] = {} as any + } + return target[key] +} + +interface ResolvedTextDocumentSyncCapabilities { + resolvedTextDocumentSync?: TextDocumentSyncOptions +} + +export interface RegistrationData { + id: string + registerOptions: T +} + +/** + * A static feature. A static feature can't be dynamically activate via the + * server. It is wired during the initialize sequence. + */ +export interface StaticFeature { + /** + * Called to fill the initialize params. + * + * @params the initialize params. + */ + fillInitializeParams?: (params: InitializeParams) => void + + /** + * Called to fill in the client capabilities this feature implements. + * + * @param capabilities The client capabilities to fill. + */ + fillClientCapabilities(capabilities: ClientCapabilities): void + + /** + * Initialize the feature. This method is called on a feature instance + * when the client has successfully received the initialize request from + * the server and before the client sends the initialized notification + * to the server. + * + * @param capabilities the server capabilities + * @param documentSelector the document selector pass to the client's constructor. + * May be `undefined` if the client was created without a selector. + */ + initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector | undefined + ): void + + /** + * Called when the client is stopped to dispose this feature. Usually a feature + * unregisters listeners registered hooked up with the VS Code extension host. + */ + dispose(): void +} + +export interface DynamicFeature { + + /** + * Called to fill the initialize params. + * + * @params the initialize params. + */ + fillInitializeParams?: (params: InitializeParams) => void + + /** + * Called to fill in the client capabilities this feature implements. + * + * @param capabilities The client capabilities to fill. + */ + fillClientCapabilities(capabilities: ClientCapabilities): void + + /** + * Initialize the feature. This method is called on a feature instance + * when the client has successfully received the initialize request from + * the server and before the client sends the initialized notification + * to the server. + * + * @param capabilities the server capabilities. + * @param documentSelector the document selector pass to the client's constructor. + * May be `undefined` if the client was created without a selector. + */ + initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector | undefined + ): void + + /** + * The signature (e.g. method) for which this features support dynamic activation / registration. + */ + registrationType: RegistrationType + + /** + * Is called when the server send a register request for the given message. + * + * @param data additional registration data as defined in the protocol. + */ + register(data: RegistrationData): void + + /** + * Is called when the server wants to unregister a feature. + * + * @param id the id used when registering the feature. + */ + unregister(id: string): void + + /** + * Called when the client is stopped to dispose this feature. Usually a feature + * unregisters listeners registered hooked up with the VS Code extension host. + */ + dispose(): void +} + +export interface NotificationFeature { + /** + * Triggers the corresponding RPC method. + */ + getProvider(document: TextDocument): { send: T } | undefined +} + +namespace DynamicFeature { + export function is(value: any): value is DynamicFeature { + let candidate: DynamicFeature = value + return ( + candidate && + Is.func(candidate.register) && + Is.func(candidate.unregister) && + Is.func(candidate.dispose) && + candidate.registrationType !== undefined + ) + } +} + +interface CreateParamsSignature { + (data: E): P +} + +abstract class DocumentNotifications + implements DynamicFeature, NotificationFeature<(data: E) => void> { + private _listener: Disposable | undefined + protected _selectors: Map = new Map() + + public static textDocumentFilter( + selectors: IterableIterator, + textDocument: TextDocument + ): boolean { + for (const selector of selectors) { + if (workspace.match(selector, textDocument) > 0) { + return true + } + } + return false + } + + constructor( + protected _client: BaseLanguageClient, + private _event: Event, + protected _type: ProtocolNotificationType, + protected _middleware: NextSignature | undefined, + protected _createParams: CreateParamsSignature, + protected _selectorFilter?: ( + selectors: IterableIterator, + data: E + ) => boolean + ) {} + + public abstract registrationType: RegistrationType + + public abstract fillClientCapabilities(capabilities: ClientCapabilities): void + + public abstract initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector | undefined + ): void + + public register( + data: RegistrationData + ): void { + if (!data.registerOptions.documentSelector) { + return + } + if (!this._listener) { + this._listener = this._event(this.callback, this) + } + this._selectors.set(data.id, data.registerOptions.documentSelector) + } + + private callback(data: E): void { + if ( + !this._selectorFilter || + this._selectorFilter(this._selectors.values(), data) + ) { + if (this._middleware) { + this._middleware(data, data => + this._client.sendNotification(this._type, this._createParams(data)) + ) + } else { + this._client.sendNotification(this._type, this._createParams(data)) + } + this.notificationSent(data) + } + } + + protected notificationSent(_data: E): void {} + + public unregister(id: string): void { + this._selectors.delete(id) + if (this._selectors.size === 0 && this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public dispose(): void { + this._selectors.clear() + if (this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public getProvider(document: TextDocument): { send: (data: E) => void } | undefined { + for (const selector of this._selectors.values()) { + if (workspace.match(selector, document)) { + return { + send: (data: E) => { + this.callback(data) + } + } + } + } + return undefined + } +} + +class DidOpenTextDocumentFeature extends DocumentNotifications { + constructor(client: BaseLanguageClient, private _syncedDocuments: Map) { + super( + client, + workspace.onDidOpenTextDocument, + DidOpenTextDocumentNotification.type, + client.clientOptions.middleware!.didOpen, + (textDocument) => { + return { textDocument: cv.convertToTextDocumentItem(textDocument) } + }, + DocumentNotifications.textDocumentFilter + ) + } + + public get registrationType(): RegistrationType { + return DidOpenTextDocumentNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(ensure(capabilities, 'textDocument')!, 'synchronization')!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + let textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.openClose + ) { + this.register({ + id: UUID.generateUuid(), + registerOptions: { documentSelector: documentSelector } + }) + } + } + + public register( + data: RegistrationData + ): void { + super.register(data) + if (!data.registerOptions.documentSelector) { + return + } + let documentSelector = data.registerOptions.documentSelector + workspace.textDocuments.forEach(textDocument => { + let uri: string = textDocument.uri.toString() + if (this._syncedDocuments.has(uri)) { + return + } + if (workspace.match(documentSelector, textDocument) > 0) { + let middleware = this._client.clientOptions.middleware! + let didOpen = (textDocument: TextDocument) => { + this._client.sendNotification( + this._type, + this._createParams(textDocument) + ) + } + if (middleware.didOpen) { + middleware.didOpen(textDocument, didOpen) + } else { + didOpen(textDocument) + } + this._syncedDocuments.set(uri, textDocument) + } + }) + } + + protected notificationSent(textDocument: TextDocument): void { + super.notificationSent(textDocument) + this._syncedDocuments.set(textDocument.uri.toString(), textDocument) + } +} + +class DidCloseTextDocumentFeature extends DocumentNotifications< + DidCloseTextDocumentParams, + TextDocument +> { + constructor( + client: BaseLanguageClient, + private _syncedDocuments: Map + ) { + super( + client, + workspace.onDidCloseTextDocument, + DidCloseTextDocumentNotification.type, + client.clientOptions.middleware!.didClose, + (textDocument) => cv.asCloseTextDocumentParams(textDocument), + DocumentNotifications.textDocumentFilter + ) + } + + public get registrationType(): RegistrationType { + return DidCloseTextDocumentNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'synchronization' + )!.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + let textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.openClose + ) { + this.register({ + id: UUID.generateUuid(), + registerOptions: { documentSelector: documentSelector } + }) + } + } + + protected notificationSent(textDocument: TextDocument): void { + super.notificationSent(textDocument) + this._syncedDocuments.delete(textDocument.uri.toString()) + } + + public unregister(id: string): void { + let selector = this._selectors.get(id)! + // The super call removed the selector from the map + // of selectors. + super.unregister(id) + let selectors = this._selectors.values() + this._syncedDocuments.forEach(textDocument => { + if ( + workspace.match(selector, textDocument) > 0 && + !this._selectorFilter!(selectors, textDocument) + ) { + let middleware = this._client.clientOptions.middleware! + let didClose = (textDocument: TextDocument) => { + this._client.sendNotification(this._type, this._createParams(textDocument)) + } + this._syncedDocuments.delete(textDocument.uri.toString()) + if (middleware.didClose) { + middleware.didClose(textDocument, didClose) + } else { + didClose(textDocument) + } + } + }) + } +} + +interface DidChangeTextDocumentData { + documentSelector: DocumentSelector + syncKind: 0 | 1 | 2 +} + +class DidChangeTextDocumentFeature + implements DynamicFeature, NotificationFeature<(event: DidChangeTextDocumentParams) => void> { + private _listener: Disposable | undefined + private _changeData: Map = new Map() + + constructor(private _client: BaseLanguageClient) {} + + public get registrationType(): RegistrationType { + return DidChangeTextDocumentNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(ensure(capabilities, 'textDocument')!, 'synchronization')!.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + let textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.change !== undefined && + textDocumentSyncOptions.change !== TextDocumentSyncKind.None + ) { + this.register({ + id: UUID.generateUuid(), + registerOptions: Object.assign( + {}, + { documentSelector: documentSelector }, + { syncKind: textDocumentSyncOptions.change } + ) + }) + } + } + + public register( + data: RegistrationData + ): void { + if (!data.registerOptions.documentSelector) { + return + } + if (!this._listener) { + this._listener = workspace.onDidChangeTextDocument(event => { + this.callback({ textDocument: event.textDocument, contentChanges: event.contentChanges.slice() }) + }, this) + } + this._changeData.set(data.id, { + documentSelector: data.registerOptions.documentSelector, + syncKind: data.registerOptions.syncKind + }) + } + + private callback(event: DidChangeTextDocumentParams): void { + // Text document changes are send for dirty changes as well. We don't + // have dirty / undirty events in the LSP so we ignore content changes + // with length zero. + if (event.contentChanges.length === 0) { + return + } + let doc = workspace.getDocument(event.textDocument.uri) + if (!doc) return + let { textDocument } = doc + for (const changeData of this._changeData.values()) { + if (workspace.match(changeData.documentSelector, textDocument) > 0) { + let middleware = this._client.clientOptions.middleware! + if (changeData.syncKind === TextDocumentSyncKind.Incremental) { + let didChange = event => { + this._client.sendNotification( + DidChangeTextDocumentNotification.type, + omit(event, ['bufnr', 'original', 'originalLines']) + ) + } + if (middleware.didChange) { + middleware.didChange(event, didChange) + } else { + didChange(event) + } + } else if (changeData.syncKind === TextDocumentSyncKind.Full) { + let didChange: (event: DidChangeTextDocumentParams) => void = () => { + this._client.sendNotification( + DidChangeTextDocumentNotification.type, + cv.asChangeTextDocumentParams(textDocument) + ) + } + if (middleware.didChange) { + middleware.didChange(event, didChange) + } else { + didChange(event) + } + } + } + } + } + + public unregister(id: string): void { + this._changeData.delete(id) + if (this._changeData.size === 0 && this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public dispose(): void { + this._changeData.clear() + if (this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public getProvider(document: TextDocument): { send: (event: DidChangeTextDocumentParams) => void } | undefined { + for (const changeData of this._changeData.values()) { + if (workspace.match(changeData.documentSelector, document)) { + return { + send: (event: DidChangeTextDocumentParams): void => { + this.callback(event) + } + } + } + } + return undefined + } +} + +class WillSaveFeature extends DocumentNotifications { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onWillSaveTextDocument, + WillSaveTextDocumentNotification.type, + client.clientOptions.middleware!.willSave, + willSaveEvent => cv.asWillSaveTextDocumentParams(willSaveEvent), + (selectors, willSaveEvent) => DocumentNotifications.textDocumentFilter(selectors, willSaveEvent.document) + ) + } + + public get registrationType(): RegistrationType { + return WillSaveTextDocumentNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let value = ensure(ensure(capabilities, 'textDocument')!, 'synchronization')! + value.willSave = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + let textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.willSave + ) { + this.register({ + id: UUID.generateUuid(), + registerOptions: { documentSelector: documentSelector } + }) + } + } +} + +class WillSaveWaitUntilFeature implements DynamicFeature { + private _listener: Disposable | undefined + private _selectors: Map = new Map() + + constructor(private _client: BaseLanguageClient) {} + + public get registrationType(): RegistrationType { + return WillSaveTextDocumentWaitUntilRequest.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let value = ensure(ensure(capabilities, 'textDocument')!, 'synchronization')! + value.willSaveWaitUntil = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + let textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.willSaveWaitUntil + ) { + this.register({ + id: UUID.generateUuid(), + registerOptions: { documentSelector: documentSelector } + }) + } + } + + public register( + data: RegistrationData + ): void { + if (!data.registerOptions.documentSelector) { + return + } + if (!this._listener) { + this._listener = workspace.onWillSaveTextDocument(this.callback, this) + } + this._selectors.set(data.id, data.registerOptions.documentSelector) + } + + private callback(event: TextDocumentWillSaveEvent): void { + if (DocumentNotifications.textDocumentFilter( + this._selectors.values(), + event.document)) { + let middleware = this._client.clientOptions.middleware! + let willSaveWaitUntil = (event: TextDocumentWillSaveEvent): Thenable => { + return this._client + .sendRequest( + WillSaveTextDocumentWaitUntilRequest.type, + cv.asWillSaveTextDocumentParams(event) + ) + .then(edits => { + return edits ? edits : [] + }, e => { + window.showMessage(`Error on willSaveWaitUntil: ${e}`, 'error') + logger.error(e) + return [] + }) + } + event.waitUntil( + middleware.willSaveWaitUntil + ? middleware.willSaveWaitUntil(event, willSaveWaitUntil) + : willSaveWaitUntil(event) + ) + } + } + + public unregister(id: string): void { + this._selectors.delete(id) + if (this._selectors.size === 0 && this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public dispose(): void { + this._selectors.clear() + if (this._listener) { + this._listener.dispose() + this._listener = undefined + } + } +} + +class DidSaveTextDocumentFeature extends DocumentNotifications< + DidSaveTextDocumentParams, + TextDocument +> { + private _includeText: boolean + + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onDidSaveTextDocument, + DidSaveTextDocumentNotification.type, + client.clientOptions.middleware!.didSave, + textDocument => + cv.asSaveTextDocumentParams( + textDocument, + this._includeText + ), + DocumentNotifications.textDocumentFilter + ) + this._includeText = false + } + + public get registrationType(): RegistrationType { + return DidSaveTextDocumentNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'synchronization' + )!.didSave = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const textDocumentSyncOptions = (capabilities as ResolvedTextDocumentSyncCapabilities).resolvedTextDocumentSync + if ( + documentSelector && + textDocumentSyncOptions && + textDocumentSyncOptions.save + ) { + const saveOptions: SaveOptions = typeof textDocumentSyncOptions.save === 'boolean' + ? { includeText: false } + : { includeText: !!textDocumentSyncOptions.save.includeText } + this.register({ + id: UUID.generateUuid(), + registerOptions: Object.assign( + {}, + { documentSelector: documentSelector }, + saveOptions + ) + }) + } + } + + public register( + data: RegistrationData + ): void { + this._includeText = !!data.registerOptions.includeText + super.register(data) + } +} + +class FileSystemWatcherFeature + implements DynamicFeature { + private _watchers: Map = new Map() + + constructor( + _client: BaseLanguageClient, + private _notifyFileEvent: (event: FileEvent) => void + ) {} + + public get registrationType(): RegistrationType { + return DidChangeWatchedFilesNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'workspace')!, + 'didChangeWatchedFiles' + )!.dynamicRegistration = true + } + + public initialize( + _capabilities: ServerCapabilities, + _documentSelector: DocumentSelector + ): void {} + + public register( + data: RegistrationData + ): void { + if (!Array.isArray(data.registerOptions.watchers)) { + return + } + let disposables: Disposable[] = [] + for (let watcher of data.registerOptions.watchers) { + if (!Is.string(watcher.globPattern)) { + continue + } + let watchCreate: boolean = true, + watchChange: boolean = true, + watchDelete: boolean = true + if (watcher.kind != null) { + watchCreate = (watcher.kind & WatchKind.Create) !== 0 + watchChange = (watcher.kind & WatchKind.Change) != 0 + watchDelete = (watcher.kind & WatchKind.Delete) != 0 + } + let fileSystemWatcher = workspace.createFileSystemWatcher( + watcher.globPattern, + !watchCreate, + !watchChange, + !watchDelete + ) + this.hookListeners( + fileSystemWatcher, + watchCreate, + watchChange, + watchDelete, + disposables + ) + disposables.push(fileSystemWatcher) + } + this._watchers.set(data.id, disposables) + } + + public registerRaw(id: string, fileSystemWatchers: FileWatcher[]) { + let disposables: Disposable[] = [] + for (let fileSystemWatcher of fileSystemWatchers) { + disposables.push(fileSystemWatcher) + this.hookListeners(fileSystemWatcher, true, true, true, disposables) + } + this._watchers.set(id, disposables) + } + + private hookListeners( + fileSystemWatcher: FileWatcher, + watchCreate: boolean, + watchChange: boolean, + watchDelete: boolean, + listeners: Disposable[] + ): void { + if (watchCreate) { + fileSystemWatcher.onDidCreate( + resource => + this._notifyFileEvent({ + uri: cv.asUri(resource), + type: FileChangeType.Created + }), + null, + listeners + ) + } + if (watchChange) { + fileSystemWatcher.onDidChange( + resource => + this._notifyFileEvent({ + uri: cv.asUri(resource), + type: FileChangeType.Changed + }), + null, + listeners + ) + } + if (watchDelete) { + fileSystemWatcher.onDidDelete( + resource => + this._notifyFileEvent({ + uri: cv.asUri(resource), + type: FileChangeType.Deleted + }), + null, + listeners + ) + } + } + + public unregister(id: string): void { + let disposables = this._watchers.get(id) + if (disposables) { + for (let disposable of disposables) { + disposable.dispose() + } + } + } + + public dispose(): void { + this._watchers.forEach(disposables => { + for (let disposable of disposables) { + disposable.dispose() + } + }) + this._watchers.clear() + } +} + +interface TextDocumentFeatureRegistration { + disposable: Disposable + data: RegistrationData + provider: PR +} + +export interface TextDocumentProviderFeature { + /** + * Triggers the corresponding RPC method. + */ + getProvider(textDocument: TextDocument): T | undefined +} + +export abstract class TextDocumentFeature< + PO, RO extends TextDocumentRegistrationOptions & PO, PR + > implements DynamicFeature { + private _registrations: Map> = new Map() + + constructor( + protected _client: BaseLanguageClient, + private _registrationType: RegistrationType + ) {} + + public get registrationType(): RegistrationType { + return this._registrationType + } + + public abstract fillClientCapabilities(capabilities: ClientCapabilities): void + + public abstract initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void + + public register(data: RegistrationData): void { + if (!data.registerOptions.documentSelector) { + return + } + let registration = this.registerLanguageProvider(data.registerOptions) + this._registrations.set(data.id, { disposable: registration[0], data, provider: registration[1] }) + } + + protected abstract registerLanguageProvider(options: RO): [Disposable, PR] + + public unregister(id: string): void { + let registration = this._registrations.get(id) + if (registration) { + registration.disposable.dispose() + } + } + + public dispose(): void { + this._registrations.forEach(value => { + value.disposable.dispose() + }) + this._registrations.clear() + } + + protected getRegistration(documentSelector: DocumentSelector | undefined, capability: undefined | PO | (RO & StaticRegistrationOptions)): [string | undefined, (RO & { documentSelector: DocumentSelector }) | undefined] { + if (!capability) { + return [undefined, undefined] + } else if (TextDocumentRegistrationOptions.is(capability)) { + const id = StaticRegistrationOptions.hasId(capability) ? capability.id : UUID.generateUuid() + const selector = capability.documentSelector || documentSelector + if (selector) { + return [id, Object.assign({}, capability, { documentSelector: selector })] + } + } else if (Is.boolean(capability) && capability === true || WorkDoneProgressOptions.is(capability)) { + if (!documentSelector) { + return [undefined, undefined] + } + let options: RO & { documentSelector: DocumentSelector } = (Is.boolean(capability) && capability === true ? { documentSelector } : Object.assign({}, capability, { documentSelector })) as any + return [UUID.generateUuid(), options] + } + return [undefined, undefined] + } + + protected getRegistrationOptions(documentSelector: DocumentSelector | undefined, capability: undefined | PO): (RO & { documentSelector: DocumentSelector }) | undefined { + if (!documentSelector || !capability) { + return undefined + } + return (Is.boolean(capability) && capability === true ? { documentSelector } : Object.assign({}, capability, { documentSelector })) as RO & { documentSelector: DocumentSelector } + } + + public getProvider(textDocument: TextDocument): PR | undefined { + for (const registration of this._registrations.values()) { + let selector = registration.data.registerOptions.documentSelector + if (selector !== null && workspace.match(selector, textDocument) > 0) { + return registration.provider + } + } + return undefined + } + + protected getAllProviders(): Iterable { + const result: PR[] = [] + for (const item of this._registrations.values()) { + result.push(item.provider) + } + return result + } +} + +export interface WorkspaceProviderFeature { + getProviders(): PR[] | undefined +} + +interface WorkspaceFeatureRegistration { + disposable: Disposable + provider: PR +} + +abstract class WorkspaceFeature implements DynamicFeature { + protected _registrations: Map> = new Map() + + constructor( + protected _client: BaseLanguageClient, + private _registrationType: RegistrationType + ) {} + + public get registrationType(): RegistrationType { + return this._registrationType + } + + public abstract fillClientCapabilities(capabilities: ClientCapabilities): void + + public abstract initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector | undefined + ): void + + public register(data: RegistrationData): void { + const registration = this.registerLanguageProvider(data.registerOptions) + this._registrations.set(data.id, { disposable: registration[0], provider: registration[1] }) + } + + protected abstract registerLanguageProvider(options: RO): [Disposable, PR] + + public unregister(id: string): void { + const registration = this._registrations.get(id) + if (registration) registration.disposable.dispose() + } + + public dispose(): void { + this._registrations.forEach(value => { + value.disposable.dispose() + }) + this._registrations.clear() + } + + public getProviders(): PR[] { + const result: PR[] = [] + for (const registration of this._registrations.values()) { + result.push(registration.provider) + } + return result + } +} + +export interface ProvideResolveFeature { + provide: T1 + resolve: T2 +} + +class CompletionItemFeature extends TextDocumentFeature { + private index: number + constructor(client: BaseLanguageClient) { + super(client, CompletionRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let snippetSupport = this._client.clientOptions.disableSnippetCompletion !== true + let completion = ensure(ensure(capabilities, 'textDocument')!, 'completion')! + completion.dynamicRegistration = true + completion.contextSupport = true + completion.completionItem = { + snippetSupport, + commitCharactersSupport: true, + documentationFormat: this._client.supportedMarkupKind, + deprecatedSupport: true, + preselectSupport: true, + insertReplaceSupport: true, + tagSupport: { valueSet: [CompletionItemTag.Deprecated] }, + resolveSupport: { properties: ['documentation', 'detail', 'additionalTextEdits'] }, + insertTextModeSupport: { valueSet: [InsertTextMode.asIs, InsertTextMode.adjustIndentation] } + } + completion.completionItemKind = { valueSet: SupportedCompletionItemKinds } + completion.insertTextMode = InsertTextMode.adjustIndentation + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + this.index = 0 + const options = this.getRegistrationOptions(documentSelector, capabilities.completionProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider(options: CompletionRegistrationOptions): [Disposable, CompletionItemProvider] { + let triggerCharacters = options.triggerCharacters || [] + let allCommitCharacters = options.allCommitCharacters || [] + let priority = (options as any).priority as number + const provider: CompletionItemProvider = { + provideCompletionItems: (document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext): ProviderResult => { + const client = this._client + const middleware = this._client.clientOptions.middleware! + const provideCompletionItems: ProvideCompletionItemsSignature = (document, position, context, token) => { + return client.sendRequest( + CompletionRequest.type, + cv.asCompletionParams(document, position, context), + token + ).then(result => result ?? [], error => { + return client.handleFailedRequest(CompletionRequest.type, token, error, []) + }) + } + + return middleware.provideCompletionItem + ? middleware.provideCompletionItem(document, position, context, token, provideCompletionItems) + : provideCompletionItems(document, position, context, token) + }, + resolveCompletionItem: options.resolveProvider + ? (item: CompletionItem, token: CancellationToken): ProviderResult => { + const client = this._client + const middleware = this._client.clientOptions.middleware! + const resolveCompletionItem: ResolveCompletionItemSignature = (item, token) => { + return client.sendRequest( + CompletionResolveRequest.type, + item, + token + ).then(res => res, error => { + return client.handleFailedRequest(CompletionResolveRequest.type, token, error, item) + }) + } + + return middleware.resolveCompletionItem + ? middleware.resolveCompletionItem(item, token, resolveCompletionItem) + : resolveCompletionItem(item, token) + } + : undefined + } + // index is needed since one language server could create many sources. + let name = this._client.id + (this.index ? '-' + this.index : '') + sources.removeSource(name) + const disposable = languages.registerCompletionItemProvider( + name, + 'LS', + options.documentSelector || this._client.clientOptions.documentSelector, + provider, + triggerCharacters, + priority, + allCommitCharacters) + this.index = this.index + 1 + return [disposable, provider] + } +} + +class HoverFeature extends TextDocumentFeature< + boolean | HoverOptions, HoverRegistrationOptions, HoverProvider +> { + constructor(client: BaseLanguageClient) { + super(client, HoverRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const hoverCapability = ensure( + ensure(capabilities, 'textDocument')!, + 'hover' + )! + hoverCapability.dynamicRegistration = true + hoverCapability.contentFormat = this._client.supportedMarkupKind + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.hoverProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: HoverRegistrationOptions + ): [Disposable, HoverProvider] { + const provider: HoverProvider = { + provideHover: (document, position, token) => { + const client = this._client + const provideHover: ProvideHoverSignature = (document, position, token) => { + return client.sendRequest( + HoverRequest.type, + cv.asTextDocumentPositionParams(document, position), + token + ).then(res => res, error => { + return client.handleFailedRequest(HoverRequest.type, token, error, null) + }) + } + + const middleware = client.clientOptions.middleware! + return middleware.provideHover + ? middleware.provideHover(document, position, token, provideHover) + : provideHover(document, position, token) + } + } + + return [languages.registerHoverProvider(options.documentSelector!, provider), provider] + } +} + +class SignatureHelpFeature extends TextDocumentFeature< + SignatureHelpOptions, SignatureHelpRegistrationOptions, SignatureHelpProvider +> { + constructor(client: BaseLanguageClient) { + super(client, SignatureHelpRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let config = ensure(ensure(capabilities, 'textDocument')!, 'signatureHelp')! + config.dynamicRegistration = true + config.contextSupport = true + config.signatureInformation = { + documentationFormat: this._client.supportedMarkupKind, + activeParameterSupport: true, + parameterInformation: { + labelOffsetSupport: true + } + } as any + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.signatureHelpProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: SignatureHelpRegistrationOptions + ): [Disposable, SignatureHelpProvider] { + const provider: SignatureHelpProvider = { + provideSignatureHelp: (document, position, token, context) => { + const client = this._client + const providerSignatureHelp: ProvideSignatureHelpSignature = (document, position, context, token) => { + return client.sendRequest( + SignatureHelpRequest.type, + cv.asSignatureHelpParams(document, position, context), + token + ).then(res => res, error => { + return client.handleFailedRequest(SignatureHelpRequest.type, token, error, null) + } + ) + } + + const middleware = client.clientOptions.middleware! + return middleware.provideSignatureHelp + ? middleware.provideSignatureHelp(document, position, context, token, providerSignatureHelp) + : providerSignatureHelp(document, position, context, token) + } + } + + const triggerCharacters = options.triggerCharacters || [] + const disposable = languages.registerSignatureHelpProvider(options.documentSelector!, provider, triggerCharacters) + return [disposable, provider] + } +} + +class DefinitionFeature extends TextDocumentFeature< + boolean | DefinitionOptions, DefinitionRegistrationOptions, DefinitionProvider +> { + constructor(client: BaseLanguageClient) { + super(client, DefinitionRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let definitionSupport = ensure(ensure(capabilities, 'textDocument')!, 'definition')! + definitionSupport.dynamicRegistration = true + // definitionSupport.linkSupport = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.definitionProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: DefinitionRegistrationOptions + ): [Disposable, DefinitionProvider] { + const provider: DefinitionProvider = { + provideDefinition: (document, position, token) => { + const client = this._client + const provideDefinition: ProvideDefinitionSignature = (document, position, token) => { + return client.sendRequest( + DefinitionRequest.type, + cv.asTextDocumentPositionParams(document, position), + token + ).then(res => res, error => { + return client.handleFailedRequest(DefinitionRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDefinition + ? middleware.provideDefinition(document, position, token, provideDefinition) + : provideDefinition(document, position, token) + } + } + + return [languages.registerDefinitionProvider(options.documentSelector!, provider), provider] + } +} + +class ReferencesFeature extends TextDocumentFeature< + boolean | ReferenceOptions, ReferenceRegistrationOptions, ReferenceProvider +> { + constructor(client: BaseLanguageClient) { + super(client, ReferencesRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'references' + )!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.referencesProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: TextDocumentRegistrationOptions + ): [Disposable, ReferenceProvider] { + const provider: ReferenceProvider = { + provideReferences: (document, position, options, token) => { + const client = this._client + const _providerReferences: ProvideReferencesSignature = (document, position, options, token) => { + return client.sendRequest( + ReferencesRequest.type, + cv.asReferenceParams(document, position, options), + token + ).then(res => res, error => { + return client.handleFailedRequest(ReferencesRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideReferences + ? middleware.provideReferences(document, position, options, token, _providerReferences) + : _providerReferences(document, position, options, token) + } + } + return [languages.registerReferencesProvider(options.documentSelector!, provider), provider] + } +} + +class DocumentHighlightFeature extends TextDocumentFeature< + boolean | DocumentHighlightOptions, DocumentHighlightRegistrationOptions, DocumentHighlightProvider +> { + constructor(client: BaseLanguageClient) { + super(client, DocumentHighlightRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'documentHighlight' + )!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentHighlightProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: TextDocumentRegistrationOptions + ): [Disposable, DocumentHighlightProvider] { + const provider: DocumentHighlightProvider = { + provideDocumentHighlights: (document, position, token) => { + const client = this._client + const _provideDocumentHighlights: ProvideDocumentHighlightsSignature = (document, position, token) => { + return client.sendRequest( + DocumentHighlightRequest.type, + cv.asTextDocumentPositionParams(document, position), + token + ).then(res => res, error => { + return client.handleFailedRequest(DocumentHighlightRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDocumentHighlights + ? middleware.provideDocumentHighlights(document, position, token, _provideDocumentHighlights) + : _provideDocumentHighlights(document, position, token) + } + } + return [languages.registerDocumentHighlightProvider(options.documentSelector!, provider), provider] + } +} + +class DocumentSymbolFeature extends TextDocumentFeature< + boolean | DocumentSymbolOptions, DocumentSymbolRegistrationOptions, DocumentSymbolProvider +> { + constructor(client: BaseLanguageClient) { + super(client, DocumentSymbolRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let symbolCapabilities = ensure(ensure(capabilities, 'textDocument')!, 'documentSymbol')! as any + symbolCapabilities.dynamicRegistration = true + symbolCapabilities.symbolKind = { + valueSet: SupportedSymbolKinds + } + symbolCapabilities.hierarchicalDocumentSymbolSupport = true + symbolCapabilities.tagSupport = { + valueSet: SupportedSymbolTags + } + symbolCapabilities.labelSupport = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentSymbolProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: DocumentSymbolRegistrationOptions + ): [Disposable, DocumentSymbolProvider] { + const provider: DocumentSymbolProvider = { + provideDocumentSymbols: (document, token) => { + const client = this._client + const _provideDocumentSymbols: ProvideDocumentSymbolsSignature = (document, token) => { + return client.sendRequest( + DocumentSymbolRequest.type, + cv.asDocumentSymbolParams(document), + token + ).then( + (data) => { + if (data === null) { + return undefined + } + if (data.length === 0) { + return [] + } else { + let element = data[0] + if (DocumentSymbol.is(element)) { + return data as DocumentSymbol[] + } else { + return data as SymbolInformation[] + } + } + }, + (error) => { + return client.handleFailedRequest(DocumentSymbolRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDocumentSymbols + ? middleware.provideDocumentSymbols(document, token, _provideDocumentSymbols) + : _provideDocumentSymbols(document, token) + } + } + const metadata = options.label ? { label: options.label } : undefined + return [languages.registerDocumentSymbolProvider(options.documentSelector!, provider, metadata), provider] + } +} + +class WorkspaceSymbolFeature extends WorkspaceFeature { + constructor(client: BaseLanguageClient) { + super(client, WorkspaceSymbolRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let symbolCapabilities = ensure( + ensure(capabilities, 'workspace')!, + 'symbol' + )! as any + symbolCapabilities.dynamicRegistration = true + symbolCapabilities.symbolKind = { + valueSet: SupportedSymbolKinds + } + symbolCapabilities.tagSupport = { + valueSet: SupportedSymbolTags + } + } + + public initialize( + capabilities: ServerCapabilities, + ): void { + if (!capabilities.workspaceSymbolProvider) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: capabilities.workspaceSymbolProvider === true ? { workDoneProgress: false } : capabilities.workspaceSymbolProvider + }) + } + + protected registerLanguageProvider(_options: WorkspaceSymbolRegistrationOptions): [Disposable, WorkspaceSymbolProvider] { + const provider: WorkspaceSymbolProvider = { + provideWorkspaceSymbols: (query, token) => { + const client = this._client + const provideWorkspaceSymbols: ProvideWorkspaceSymbolsSignature = (query, token) => { + return client.sendRequest(WorkspaceSymbolRequest.type, { query }, token).then( + res => res, + error => { + return client.handleFailedRequest(WorkspaceSymbolRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideWorkspaceSymbols + ? middleware.provideWorkspaceSymbols(query, token, provideWorkspaceSymbols) + : provideWorkspaceSymbols(query, token) + } + } + return [languages.registerWorkspaceSymbolProvider(provider), provider] + } +} + +class CodeActionFeature extends TextDocumentFeature { + private disposables: Disposable[] = [] + constructor(client: BaseLanguageClient) { + super(client, CodeActionRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const cap = ensure(ensure(capabilities, 'textDocument')!, 'codeAction')! + cap.dynamicRegistration = true + cap.isPreferredSupport = true + cap.disabledSupport = true + cap.dataSupport = true + cap.honorsChangeAnnotations = false + cap.resolveSupport = { + properties: ['edit'] + } + cap.codeActionLiteralSupport = { + codeActionKind: { + valueSet: [ + CodeActionKind.Empty, + CodeActionKind.QuickFix, + CodeActionKind.Refactor, + CodeActionKind.RefactorExtract, + CodeActionKind.RefactorInline, + CodeActionKind.RefactorRewrite, + CodeActionKind.Source, + CodeActionKind.SourceOrganizeImports + ] + } + } + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.codeActionProvider) + if (!options) { + return + } + + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: CodeActionRegistrationOptions + ): [Disposable, CodeActionProvider] { + const registCommand = (id: string) => { + if (commands.has(id)) return + const client = this._client + const executeCommand: ExecuteCommandSignature = (command: string, args: any[]): any => { + const params: ExecuteCommandParams = { + command, + arguments: args + } + return client.sendRequest(ExecuteCommandRequest.type, params).then(undefined, (error) => { + client.handleFailedRequest(ExecuteCommandRequest.type, undefined, error, undefined) + throw error + }) + } + const middleware = client.clientOptions.middleware! + this.disposables.push(commands.registerCommand(id, (...args: any[]) => { + return middleware.executeCommand + ? middleware.executeCommand(id, args, executeCommand) + : executeCommand(id, args) + }, null, true)) + } + const provider: CodeActionProvider = { + provideCodeActions: (document, range, context, token) => { + const client = this._client + const _provideCodeActions: ProvideCodeActionsSignature = (document, range, context, token) => { + const params: CodeActionParams = { + textDocument: { + uri: document.uri + }, + range, + context, + } + return client.sendRequest(CodeActionRequest.type, params, token).then( + (values) => { + if (values === null) { + return undefined + } + // some server may not registered commands to client. + values.forEach(val => { + let cmd = Command.is(val) ? val.command : val.command?.command + if (cmd && !commands.has(cmd)) registCommand(cmd) + }) + return values + }, + (error) => { + return client.handleFailedRequest(CodeActionRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware! + return middleware.provideCodeActions + ? middleware.provideCodeActions(document, range, context, token, _provideCodeActions) + : _provideCodeActions(document, range, context, token) + }, + resolveCodeAction: options.resolveProvider + ? (item: CodeAction, token: CancellationToken) => { + const client = this._client + const middleware = this._client.clientOptions.middleware! + const resolveCodeAction: ResolveCodeActionSignature = (item, token) => { + return client.sendRequest(CodeActionResolveRequest.type, item, token).then( + (values) => values, + (error) => { + return client.handleFailedRequest(CodeActionResolveRequest.type, token, error, item) + } + ) + } + return middleware.resolveCodeAction + ? middleware.resolveCodeAction(item, token, resolveCodeAction) + : resolveCodeAction(item, token) + } + : undefined + } + return [languages.registerCodeActionProvider(options.documentSelector, provider, this._client.id, options.codeActionKinds), provider] + } + + public dispose(): void { + this.disposables.forEach(o => { + o.dispose() + }) + this.disposables = [] + super.dispose() + } +} + +interface CodeLensProviderData { + provider?: CodeLensProvider + onDidChangeCodeLensEmitter?: Emitter +} + +class CodeLensFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, CodeLensRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'codeLens' + )!.dynamicRegistration = true + ensure(ensure(capabilities, 'workspace')!, + 'codeLens' + )!.refreshSupport = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const client = this._client + client.onRequest(CodeLensRefreshRequest.type, async () => { + for (const provider of this.getAllProviders()) { + provider.onDidChangeCodeLensEmitter.fire() + } + }) + const options = this.getRegistrationOptions(documentSelector, capabilities.codeLensProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: CodeLensRegistrationOptions + ): [Disposable, CodeLensProviderData] { + const emitter: Emitter = new Emitter() + const provider: CodeLensProvider = { + onDidChangeCodeLenses: emitter.event, + provideCodeLenses: (document, token) => { + const client = this._client + const provideCodeLenses: ProvideCodeLensesSignature = (document, token) => { + return client.sendRequest( + CodeLensRequest.type, + cv.asCodeLensParams(document), + token + ).then(res => res, error => { + return client.handleFailedRequest(CodeLensRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideCodeLenses + ? middleware.provideCodeLenses(document, token, provideCodeLenses) + : provideCodeLenses(document, token) + }, + resolveCodeLens: (options.resolveProvider) + ? (codeLens: CodeLens, token: CancellationToken): ProviderResult => { + const client = this._client + const resolveCodeLens: ResolveCodeLensSignature = (codeLens, token) => { + return client.sendRequest( + CodeLensResolveRequest.type, + codeLens, + token + ).then(res => res, error => { + return client.handleFailedRequest(CodeLensResolveRequest.type, token, error, codeLens) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.resolveCodeLens + ? middleware.resolveCodeLens(codeLens, token, resolveCodeLens) + : resolveCodeLens(codeLens, token) + } + : undefined + } + + return [languages.registerCodeLensProvider(options.documentSelector, provider), { provider, onDidChangeCodeLensEmitter: emitter }] + } +} + +class DocumentFormattingFeature extends TextDocumentFeature< + boolean | DocumentFormattingOptions, DocumentHighlightRegistrationOptions, DocumentFormattingEditProvider +> { + + constructor(client: BaseLanguageClient) { + super(client, DocumentFormattingRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'formatting' + )!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentFormattingProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: TextDocumentRegistrationOptions + ): [Disposable, DocumentFormattingEditProvider] { + const provider: DocumentFormattingEditProvider = { + provideDocumentFormattingEdits: (document, options, token) => { + const client = this._client + const provideDocumentFormattingEdits: ProvideDocumentFormattingEditsSignature = (document, options, token) => { + const params: DocumentFormattingParams = { + textDocument: { uri: document.uri }, + options + } + return client.sendRequest(DocumentFormattingRequest.type, params, token).then(res => res, (error) => { + return client.handleFailedRequest(DocumentFormattingRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDocumentFormattingEdits + ? middleware.provideDocumentFormattingEdits(document, options, token, provideDocumentFormattingEdits) + : provideDocumentFormattingEdits(document, options, token) + } + } + + return [ + languages.registerDocumentFormatProvider(options.documentSelector!, provider, this._client.clientOptions.formatterPriority), + provider + ] + } +} + +class DocumentRangeFormattingFeature extends TextDocumentFeature< + boolean | DocumentRangeFormattingOptions, DocumentRangeFormattingRegistrationOptions, DocumentRangeFormattingEditProvider +> { + constructor(client: BaseLanguageClient) { + super(client, DocumentRangeFormattingRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'textDocument')!, + 'rangeFormatting' + )!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentRangeFormattingProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: TextDocumentRegistrationOptions + ): [Disposable, DocumentRangeFormattingEditProvider] { + const provider: DocumentRangeFormattingEditProvider = { + provideDocumentRangeFormattingEdits: (document, range, options, token) => { + const client = this._client + const provideDocumentRangeFormattingEdits: ProvideDocumentRangeFormattingEditsSignature = (document, range, options, token) => { + const params: DocumentRangeFormattingParams = { + textDocument: { uri: document.uri }, + range, + options, + } + return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then(res => res, error => { + return client.handleFailedRequest(DocumentRangeFormattingRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDocumentRangeFormattingEdits + ? middleware.provideDocumentRangeFormattingEdits(document, range, options, token, provideDocumentRangeFormattingEdits) + : provideDocumentRangeFormattingEdits(document, range, options, token) + } + } + + return [languages.registerDocumentRangeFormatProvider(options.documentSelector, provider), provider] + } +} + +class DocumentOnTypeFormattingFeature extends TextDocumentFeature< + DocumentOnTypeFormattingOptions, DocumentOnTypeFormattingRegistrationOptions, OnTypeFormattingEditProvider +> { + + constructor(client: BaseLanguageClient) { + super(client, DocumentOnTypeFormattingRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(ensure(capabilities, 'textDocument')!, 'onTypeFormatting')!.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentOnTypeFormattingProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider(options: DocumentOnTypeFormattingRegistrationOptions): [Disposable, OnTypeFormattingEditProvider] { + const provider: OnTypeFormattingEditProvider = { + provideOnTypeFormattingEdits: (document, position, ch, options, token) => { + const client = this._client + const provideOnTypeFormattingEdits: ProvideOnTypeFormattingEditsSignature = (document, position, ch, options, token) => { + const params: DocumentOnTypeFormattingParams = { + textDocument: cv.asVersionedTextDocumentIdentifier(document), + position, + ch, + options + } + return client.sendRequest(DocumentOnTypeFormattingRequest.type, params, token).then(res => res, (error) => { + return client.handleFailedRequest(DocumentOnTypeFormattingRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideOnTypeFormattingEdits + ? middleware.provideOnTypeFormattingEdits(document, position, ch, options, token, provideOnTypeFormattingEdits) + : provideOnTypeFormattingEdits(document, position, ch, options, token) + } + } + + const moreTriggerCharacter = options.moreTriggerCharacter || [] + const characters = [options.firstTriggerCharacter, ...moreTriggerCharacter] + return [languages.registerOnTypeFormattingEditProvider(options.documentSelector!, provider, characters), provider] + } +} + +interface DefaultBehavior { + defaultBehavior: boolean +} + +class RenameFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, RenameRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let rename = ensure(ensure(capabilities, 'textDocument')!, 'rename')! + rename.dynamicRegistration = true + rename.prepareSupport = true + // TODO: capabilities + // rename.honorsChangeAnnotations = true + // Some language server report bug, renable when it's useful + // rename.prepareSupportDefaultBehavior = PrepareSupportDefaultBehavior.Identifier + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.renameProvider) + if (!options) { + return + } + if (Is.boolean(capabilities.renameProvider)) { + options.prepareProvider = false + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider(options: RenameRegistrationOptions): [Disposable, RenameProvider] { + const provider: RenameProvider = { + provideRenameEdits: (document, position, newName, token) => { + const client = this._client + const provideRenameEdits: ProvideRenameEditsSignature = (document, position, newName, token) => { + const params: RenameParams = { + textDocument: { uri: document.uri }, + position, + newName: newName + } + return client.sendRequest(RenameRequest.type, params, token).then(res => res, (error: ResponseError) => { + return client.handleFailedRequest(RenameRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideRenameEdits + ? middleware.provideRenameEdits(document, position, newName, token, provideRenameEdits) + : provideRenameEdits(document, position, newName, token) + }, + prepareRename: options.prepareProvider + ? (document, position, token) => { + const client = this._client + const prepareRename: PrepareRenameSignature = (document, position, token) => { + const params: TextDocumentPositionParams = { + textDocument: cv.asTextDocumentIdentifier(document), + position + } + return client.sendRequest(PrepareRenameRequest.type, params, token).then( + (result) => { + if (Range.is(result)) { + return result + } else if (this.isDefaultBehavior(result)) { + return result.defaultBehavior === true ? null : Promise.reject(new Error(`The element can't be renamed.`)) + } else if (result && Range.is(result.range)) { + return { + range: result.range, + placeholder: result.placeholder + } + } + // To cancel the rename vscode API expects a rejected promise. + return Promise.reject(new Error(`The element can't be renamed.`)) + }, + (error: ResponseError) => { + return client.handleFailedRequest(PrepareRenameRequest.type, token, error, undefined) + } + ) + } + const middleware = client.clientOptions.middleware! + return middleware.prepareRename + ? middleware.prepareRename(document, position, token, prepareRename) + : prepareRename(document, position, token) + } + : undefined + } + + return [languages.registerRenameProvider(options.documentSelector, provider), provider] + } + + private isDefaultBehavior(value: any): value is DefaultBehavior { + const candidate: DefaultBehavior = value + return candidate && Is.boolean(candidate.defaultBehavior) + } +} + +class DocumentLinkFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, DocumentLinkRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const documentLinkCapabilities = ensure(ensure(capabilities, 'textDocument')!, 'documentLink')! + documentLinkCapabilities.dynamicRegistration = true + documentLinkCapabilities.tooltipSupport = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const options = this.getRegistrationOptions(documentSelector, capabilities.documentLinkProvider) + if (!options) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: options + }) + } + + protected registerLanguageProvider( + options: DocumentLinkRegistrationOptions + ): [Disposable, DocumentLinkProvider] { + const provider: DocumentLinkProvider = { + provideDocumentLinks: (document: TextDocument, token: CancellationToken): ProviderResult => { + const client = this._client + const provideDocumentLinks: ProvideDocumentLinksSignature = (document, token) => { + return client.sendRequest( + DocumentLinkRequest.type, + { + textDocument: { uri: document.uri } + }, + token + ).then(res => res, (error: ResponseError) => { + return client.handleFailedRequest(DocumentLinkRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideDocumentLinks + ? middleware.provideDocumentLinks(document, token, provideDocumentLinks) + : provideDocumentLinks(document, token) + }, + resolveDocumentLink: options.resolveProvider + ? (link, token) => { + const client = this._client + let resolveDocumentLink: ResolveDocumentLinkSignature = (link, token) => { + return client.sendRequest(DocumentLinkResolveRequest.type, link, token).then(res => res, (error: ResponseError) => { + return client.handleFailedRequest(DocumentLinkResolveRequest.type, token, error, link) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.resolveDocumentLink + ? middleware.resolveDocumentLink(link, token, resolveDocumentLink) + : resolveDocumentLink(link, token) + } + : undefined + } + + return [languages.registerDocumentLinkProvider(options.documentSelector, provider), provider] + } +} + +class ConfigurationFeature implements DynamicFeature { + private _listeners: Map = new Map() + + constructor(private _client: BaseLanguageClient) {} + + public get registrationType(): RegistrationType { + return DidChangeConfigurationNotification.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(ensure(capabilities, 'workspace')!, 'didChangeConfiguration')!.dynamicRegistration = true + } + + public initialize(): void { + let section = this._client.clientOptions.synchronize?.configurationSection + if (section !== undefined) { + this.register({ + id: UUID.generateUuid(), + registerOptions: { + section: section + } + }) + } + } + + public register( + data: RegistrationData + ): void { + let { section } = data.registerOptions + let disposable = workspace.onDidChangeConfiguration((event) => { + this.onDidChangeConfiguration(data.registerOptions.section, event) + }) + this._listeners.set(data.id, disposable) + if (section != undefined) { + this.onDidChangeConfiguration(section, undefined) + } + } + + public unregister(id: string): void { + let disposable = this._listeners.get(id) + if (disposable) { + this._listeners.delete(id) + disposable.dispose() + } + } + + public dispose(): void { + for (let disposable of this._listeners.values()) { + disposable.dispose() + } + this._listeners.clear() + } + + private onDidChangeConfiguration(configurationSection: string | string[] | undefined, event: ConfigurationChangeEvent | undefined): void { + let isConfigured = typeof configurationSection === 'string' && configurationSection.startsWith('languageserver.') + let sections: string[] | undefined + if (Is.string(configurationSection)) { + sections = [configurationSection] + } else { + sections = configurationSection + } + if (sections != null && event != null) { + let affected = sections.some((section) => event.affectsConfiguration(section)) + if (!affected) return + } + let didChangeConfiguration = (sections: string[] | undefined): void => { + if (sections == null) { + this._client.sendNotification(DidChangeConfigurationNotification.type, { settings: null }) + return + } + this._client.sendNotification(DidChangeConfigurationNotification.type, { + settings: isConfigured ? this.getConfiguredSettings(sections[0]) : this.extractSettingsInformation(sections) + }) + } + let middleware = this.getMiddleware() + middleware + ? middleware(sections, didChangeConfiguration) + : didChangeConfiguration(sections) + } + + // for configured languageserver + private getConfiguredSettings(key: string): any { + let len = '.settings'.length + let config = workspace.getConfiguration(key.slice(0, - len)) + return mergeConfigProperties(config.get('settings', {})) + } + + private extractSettingsInformation(keys: string[]): any { + function ensurePath(config: any, path: string[]): any { + let current = config + for (let i = 0; i < path.length - 1; i++) { + let obj = current[path[i]] + if (!obj) { + obj = Object.create(null) + current[path[i]] = obj + } + current = obj + } + return current + } + let result = Object.create(null) + for (let i = 0; i < keys.length; i++) { + let key = keys[i] + let index: number = key.indexOf('.') + let config: any = null + if (index >= 0) { + config = workspace.getConfiguration(key.substr(0, index)).get(key.substr(index + 1)) + } else { + config = workspace.getConfiguration(key) + } + if (config) { + let path = keys[i].split('.') + ensurePath(result, path)[path[path.length - 1]] = config + } + } + return result + } + + private getMiddleware() { + let middleware = this._client.clientOptions.middleware! + if (middleware.workspace && middleware.workspace.didChangeConfiguration) { + return middleware.workspace.didChangeConfiguration + } else { + return undefined + } + } +} + +class ExecuteCommandFeature + implements DynamicFeature { + private _commands: Map = new Map() + constructor(private _client: BaseLanguageClient) {} + + public get registrationType(): RegistrationType { + return ExecuteCommandRequest.type + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure( + ensure(capabilities, 'workspace')!, + 'executeCommand' + )!.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities): void { + if (!capabilities.executeCommandProvider) { + return + } + this.register({ + id: UUID.generateUuid(), + registerOptions: Object.assign({}, capabilities.executeCommandProvider) + }) + } + + public register( + data: RegistrationData + ): void { + const client = this._client + const middleware = client.clientOptions.middleware! + const executeCommand: ExecuteCommandSignature = (command: string, args: any[]): any => { + const params: ExecuteCommandParams = { + command, + arguments: args + } + return client.sendRequest(ExecuteCommandRequest.type, params).then(undefined, (error) => { + client.handleFailedRequest(ExecuteCommandRequest.type, undefined, error, undefined) + throw error + }) + } + if (data.registerOptions.commands) { + let disposables: Disposable[] = [] + for (const command of data.registerOptions.commands) { + disposables.push(commands.registerCommand(command, (...args: any[]) => { + return middleware.executeCommand + ? middleware.executeCommand(command, args, executeCommand) + : executeCommand(command, args) + }, null, true)) + } + this._commands.set(data.id, disposables) + } + } + + public unregister(id: string): void { + let disposables = this._commands.get(id) + if (disposables) { + disposables.forEach(disposable => disposable.dispose()) + } + } + + public dispose(): void { + this._commands.forEach(value => { + value.forEach(disposable => disposable.dispose()) + }) + this._commands.clear() + } +} + +export interface MessageTransports { + reader: MessageReader + writer: MessageWriter + detached?: boolean +} + +export namespace MessageTransports { + export function is(value: any): value is MessageTransports { + let candidate: MessageTransports = value + return ( + candidate && + MessageReader.is(value.reader) && + MessageWriter.is(value.writer) + ) + } +} + +class OnReady { + private _used: boolean + constructor(private _resolve: () => void, private _reject: (error: any) => void) { + this._used = false + } + + public get isUsed(): boolean { + return this._used + } + + public resolve(): void { + this._used = true + this._resolve() + } + + public reject(error: any): void { + this._used = true + this._reject(error) + } +} + +export abstract class BaseLanguageClient { + private _id: string + private _name: string + private _markdownSupport: boolean + private _clientOptions: ResolvedClientOptions + private _rootPath: string | false + + protected _state: ClientState + private _onReady: Promise + private _onReadyCallbacks: OnReady + private _onStop: Promise | undefined + private _connectionPromise: Promise | undefined + private _resolvedConnection: IConnection | undefined + private _initializeResult: InitializeResult | undefined + private _outputChannel: OutputChannel | undefined + private _capabilities: ServerCapabilities & ResolvedTextDocumentSyncCapabilities + + private _listeners: Disposable[] | undefined + private _providers: Disposable[] | undefined + private _diagnostics: DiagnosticCollection | undefined + private _syncedDocuments: Map + + private _fileEvents: FileEvent[] + private _fileEventDelayer: Delayer + private _stateChangeEmitter: Emitter + + private _traceFormat: TraceFormat + private _trace: Trace + private _tracer: Tracer + + public constructor( + id: string, + name: string, + clientOptions: LanguageClientOptions + ) { + this._id = id + this._name = name + if (clientOptions.outputChannel) { + this._outputChannel = clientOptions.outputChannel + } else { + this._outputChannel = undefined + } + let disableSnippetCompletion = false + let suggest = workspace.getConfiguration('suggest') + if (suggest.get('snippetsSupport', true) === false || clientOptions.disableSnippetCompletion) { + disableSnippetCompletion = true + } + + const markdown = { isTrusted: false, supportHtml: false } + if (clientOptions.markdown != null) { + markdown.isTrusted = clientOptions.markdown.isTrusted === true + markdown.supportHtml = clientOptions.markdown.supportHtml === true + } + + this._clientOptions = { + disableSnippetCompletion, + disableDynamicRegister: clientOptions.disableDynamicRegister, + disabledFeatures: clientOptions.disabledFeatures || [], + formatterPriority: clientOptions.formatterPriority, + ignoredRootPaths: clientOptions.ignoredRootPaths, + documentSelector: clientOptions.documentSelector || [], + synchronize: clientOptions.synchronize || {}, + diagnosticCollectionName: clientOptions.diagnosticCollectionName, + outputChannelName: clientOptions.outputChannelName || this._id, + revealOutputChannelOn: + clientOptions.revealOutputChannelOn || RevealOutputChannelOn.Never, + stdioEncoding: clientOptions.stdioEncoding || 'utf8', + initializationOptions: clientOptions.initializationOptions, + initializationFailedHandler: clientOptions.initializationFailedHandler, + progressOnInitialization: !!clientOptions.progressOnInitialization, + errorHandler: clientOptions.errorHandler || this.createDefaultErrorHandler(clientOptions.connectionOptions?.maxRestartCount), + middleware: clientOptions.middleware || {}, + workspaceFolder: clientOptions.workspaceFolder, + connectionOptions: clientOptions.connectionOptions, + markdown + } + for (let key of ['disableCompletion', 'disableWorkspaceFolders', 'disableDiagnostics']) { + if (typeof clientOptions[key] === 'boolean') { + let stack = '\n' + Error().stack.split('\n').slice(2, 4).join('\n') + logger.warn(`${key} in the client options is deprecated. use disabledFeatures instead.`, stack) + this.warn(`${key} in the client options is deprecated. use disabledFeatures instead.`, stack) + if (clientOptions[key] === true) { + let s = key.slice(7) + this._clientOptions.disabledFeatures.push(s[0].toLowerCase() + s.slice(1)) + } + } + } + this.state = ClientState.Initial + this._connectionPromise = undefined + this._resolvedConnection = undefined + this._initializeResult = undefined + this._listeners = undefined + this._providers = undefined + this._diagnostics = undefined + + this._fileEvents = [] + this._fileEventDelayer = new Delayer(250) + this._onReady = new Promise((resolve, reject) => { + this._onReadyCallbacks = new OnReady(resolve, reject) + }) + this._onStop = undefined + this._stateChangeEmitter = new Emitter() + this._trace = Trace.Off + this._tracer = { + log: (messageOrDataObject: string | any, data?: string) => { + if (Is.string(messageOrDataObject)) { + this.logTrace(messageOrDataObject, data) + } else { + this.logObjectTrace(messageOrDataObject) + } + } + } + this._syncedDocuments = new Map() + let preferences = workspace.getConfiguration('coc.preferences') + this._markdownSupport = preferences.get('enableMarkdown', true) + this.registerBuiltinFeatures() + } + + public get supportedMarkupKind(): MarkupKind[] { + if (this._markdownSupport) return [MarkupKind.Markdown, MarkupKind.PlainText] + return [MarkupKind.PlainText] + } + + private get state(): ClientState { + return this._state + } + + public get id(): string { + return this._id + } + + public get name(): string { + return this._name + } + + private set state(value: ClientState) { + let oldState = this.getPublicState() + this._state = value + let newState = this.getPublicState() + if (newState !== oldState) { + this._stateChangeEmitter.fire({ oldState, newState }) + } + } + + public getPublicState(): State { + if (this.state === ClientState.Running) { + return State.Running + } else if (this.state === ClientState.Starting) { + return State.Starting + } else { + return State.Stopped + } + } + + public get initializeResult(): InitializeResult | undefined { + return this._initializeResult + } + + public sendRequest(type: ProtocolRequestType0, token?: CancellationToken): Promise + public sendRequest(type: ProtocolRequestType, params: P, token?: CancellationToken): Promise + public sendRequest(type: RequestType0, token?: CancellationToken): Promise + public sendRequest(type: RequestType, params: P, token?: CancellationToken): Promise + public sendRequest(method: string, token?: CancellationToken): Promise + public sendRequest(method: string, param: any, token?: CancellationToken): Promise + public sendRequest(type: string | MessageSignature, ...params: any[]): Promise { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + return this._resolvedConnection!.sendRequest(type, ...params) + } catch (error) { + this.error( + `Sending request ${Is.string(type) ? type : type.method} failed.`, + error + ) + throw error + } + } + + public onRequest(type: ProtocolRequestType0, handler: RequestHandler0): Disposable + public onRequest(type: ProtocolRequestType, handler: RequestHandler): Disposable + public onRequest(type: RequestType0, handler: RequestHandler0): Disposable + public onRequest(type: RequestType, handler: RequestHandler): Disposable + public onRequest(method: string, handler: GenericRequestHandler): Disposable + public onRequest(type: string | MessageSignature, handler: GenericRequestHandler): Disposable { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + return this._resolvedConnection!.onRequest(type, handler) + } catch (error) { + this.error( + `Registering request handler ${Is.string(type) ? type : type.method + } failed.`, + error + ) + throw error + } + } + + public sendNotification(type: ProtocolNotificationType0): void + public sendNotification(type: ProtocolNotificationType, params?: P): void + public sendNotification(type: NotificationType0): void + public sendNotification

    (type: NotificationType

    , params?: P): void + public sendNotification(method: string): void + public sendNotification(method: string, params: any): void + public sendNotification

    (type: string | MessageSignature, params?: P): void { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + this._resolvedConnection!.sendNotification(type, params) + } catch (error) { + this.error( + `Sending notification ${Is.string(type) ? type : type.method} failed.`, + error + ) + throw error + } + } + + public onNotification(type: ProtocolNotificationType0, handler: NotificationHandler0): Disposable + public onNotification(type: ProtocolNotificationType, handler: NotificationHandler

    ): Disposable + public onNotification(type: NotificationType0, handler: NotificationHandler0): Disposable + public onNotification

    (type: NotificationType

    , handler: NotificationHandler

    ): Disposable + public onNotification(method: string, handler: GenericNotificationHandler): Disposable + public onNotification(type: string | MessageSignature, handler: GenericNotificationHandler): Disposable { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + return this._resolvedConnection!.onNotification(type, handler) + } catch (error) { + this.error( + `Registering notification handler ${Is.string(type) ? type : type.method + } failed.`, + error + ) + throw error + } + } + + public onProgress

    (type: ProgressType, token: string | number, handler: NotificationHandler

    ): Disposable { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + if (type == WorkDoneProgress.type) { + const handleWorkDoneProgress = this._clientOptions.middleware!.handleWorkDoneProgress + if (handleWorkDoneProgress !== undefined) { + return this._resolvedConnection!.onProgress(type, token, (params) => { + handleWorkDoneProgress(token, params as any, () => handler(params as unknown as P)) + }) + } + } + return this._resolvedConnection!.onProgress(type, token, handler) + } catch (error) { + this.error(`Registering progress handler for token ${token} failed.`, error) + throw error + } + } + + public sendProgress

    (type: ProgressType

    , token: string | number, value: P): void { + if (!this.isConnectionActive()) { + throw new Error('Language client is not ready yet') + } + try { + this._resolvedConnection!.sendProgress(type, token, value) + } catch (error) { + this.error(`Sending progress for token ${token} failed.`, error) + throw error + } + } + + public get clientOptions(): LanguageClientOptions { + return this._clientOptions + } + + public get onDidChangeState(): Event { + return this._stateChangeEmitter.event + } + + public get outputChannel(): OutputChannel { + if (!this._outputChannel) { + let { outputChannelName } = this._clientOptions + this._outputChannel = window.createOutputChannel(outputChannelName ? outputChannelName : this._name) + } + return this._outputChannel + } + + public get diagnostics(): DiagnosticCollection | undefined { + return this._diagnostics + } + + public createDefaultErrorHandler(maxRestartCount?: number): ErrorHandler { + return new DefaultErrorHandler(this._id, maxRestartCount ?? 4) + } + + public set trace(value: Trace) { + this._trace = value + this.onReady().then( + () => { + this.resolveConnection().then(connection => { + connection.trace(this._trace, this._tracer, { + sendNotification: false, + traceFormat: this._traceFormat + }) + }) + }, + () => {} + ) + } + + private logObjectTrace(data: any): void { + if (data.isLSPMessage && data.type) { + this.outputChannel.append(`[LSP - ${(new Date().toLocaleTimeString())}] `) + } else { + this.outputChannel.append(`[Trace - ${(new Date().toLocaleTimeString())}] `) + } + if (data) { + this.outputChannel.appendLine(`${JSON.stringify(data)}`) + } + } + + private data2String(data: any): string { + if (data instanceof ResponseError) { + const responseError = data as ResponseError + return ` Message: ${responseError.message}\n Code: ${responseError.code + } ${responseError.data ? '\n' + responseError.data.toString() : ''}` + } + if (data instanceof Error) { + if (Is.string(data.stack)) { + return data.stack + } + return (data as Error).message + } + if (Is.string(data)) { + return data + } + return data.toString() + } + + private _appendOutput(type: string, message: string, data?: any): void { + let level = RevealOutputChannelOn.Error + switch (type) { + case 'Info': + level = RevealOutputChannelOn.Info + break + case 'Warn': + level = RevealOutputChannelOn.Warn + break + } + this.outputChannel.appendLine(`[${type} - ${(new Date().toLocaleTimeString())}] ${message}`) + let dataString: string + if (data) { + dataString = this.data2String(data) + this.outputChannel.appendLine(dataString) + } + if (this._clientOptions.revealOutputChannelOn <= level) { + this.outputChannel.show(true) + } + } + + public info(message: string, data?: any): void { + this._appendOutput('Info', message, data) + } + + public warn(message: string, data?: any): void { + this._appendOutput('Warn', message, data) + } + + public error(message: string, data?: any): void { + this._appendOutput('Error', message, data) + } + + private logTrace(message: string, data?: any): void { + this.outputChannel.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`) + if (data) { + this.outputChannel.appendLine(this.data2String(data)) + } + } + + public needsStart(): boolean { + return ( + this.state === ClientState.Initial || + this.state === ClientState.Stopping || + this.state === ClientState.Stopped + ) + } + + public needsStop(): boolean { + return ( + this.state === ClientState.Starting || this.state === ClientState.Running + ) + } + + public onReady(): Promise { + return this._onReady + } + + public get started(): boolean { + return this.state != ClientState.Initial + } + + private isConnectionActive(): boolean { + return this.state === ClientState.Running && !!this._resolvedConnection + } + + public start(): Disposable { + this._rootPath = this.resolveRootPath() + if (this._rootPath === false) { + this.warn(`Required root pattern not resolved, server won't start.`) + return Disposable.create(() => {}) + } + if (this._onReadyCallbacks.isUsed) { + this._onReady = new Promise((resolve, reject) => { + this._onReadyCallbacks = new OnReady(resolve, reject) + }) + } + this._listeners = [] + this._providers = [] + // If we restart then the diagnostics collection is reused. + if (!this._diagnostics) { + let opts = this._clientOptions + let name = opts.diagnosticCollectionName ? opts.diagnosticCollectionName : this._id + if (!opts.disabledFeatures.includes('diagnostics')) { + this._diagnostics = languages.createDiagnosticCollection(name) + } + } + + this.state = ClientState.Starting + this.resolveConnection() + .then(connection => { + connection.onLogMessage(message => { + let kind: string + switch (message.type) { + case MessageType.Error: + kind = 'error' + this.error(message.message) + break + case MessageType.Warning: + kind = 'warning' + this.warn(message.message) + break + case MessageType.Info: + kind = 'info' + this.info(message.message) + break + default: + kind = 'log' + this.outputChannel.appendLine(message.message) + } + if (global.hasOwnProperty('__TEST__')) { + console.log(`[${kind}] ${message.message}`) + return + } + }) + connection.onShowMessage(message => { + switch (message.type) { + case MessageType.Error: + window.showErrorMessage(message.message) + break + case MessageType.Warning: + window.showWarningMessage(message.message) + break + case MessageType.Info: + window.showInformationMessage(message.message) + break + default: + window.showInformationMessage(message.message) + } + }) + connection.onRequest(ShowMessageRequest.type, (params: ShowMessageRequestParams) => { + let messageFunc: (message: string, ...items: T[]) => Thenable + switch (params.type) { + case MessageType.Error: + messageFunc = window.showErrorMessage.bind(window) + break + case MessageType.Warning: + messageFunc = window.showWarningMessage.bind(window) + break + case MessageType.Info: + messageFunc = window.showInformationMessage.bind(window) + break + default: + messageFunc = window.showInformationMessage.bind(window) + } + let actions: MessageActionItem[] = params.actions || [] + return messageFunc(params.message, ...actions).then(res => { + return res == null ? null : res + }) + }) + connection.onRequest(ShowDocumentRequest.type, async (params): Promise => { + const showDocument = async (params: ShowDocumentParams): Promise => { + try { + if (params.external === true || /^https?:\/\//.test(params.uri)) { + await workspace.openResource(params.uri) + return { success: true } + } else { + let { selection, takeFocus } = params + if (takeFocus === false) { + await workspace.loadFile(params.uri) + } else { + await workspace.jumpTo(params.uri, selection?.start) + if (comparePosition(selection.start, selection.end) != 0) { + await window.selectRange(selection) + } + } + return { success: true } + } + } catch (error) { + return { success: true } + } + } + const middleware = this._clientOptions.middleware.window?.showDocument + if (middleware !== undefined) { + return middleware(params, showDocument) + } else { + return showDocument(params) + } + }) + connection.onTelemetry(_data => { + // ignored + }) + connection.listen() + // Error is handled in the initialize call. + return this.initialize(connection) + }).then(undefined, error => { + this.state = ClientState.StartFailed + this._onReadyCallbacks.reject(error) + this.error('Starting client failed ', error) + }) + return Disposable.create(() => { + if (this.needsStop()) { + this.stop() + } + }) + } + + private resolveConnection(): Promise { + if (!this._connectionPromise) { + this._connectionPromise = this.createConnection() + } + return this._connectionPromise + } + + private resolveRootPath(): string | null | false { + if (this._clientOptions.workspaceFolder) { + return URI.parse(this._clientOptions.workspaceFolder.uri).fsPath + } + let { ignoredRootPaths } = this._clientOptions + let config = workspace.getConfiguration(this.id) + let rootPatterns = config.get('rootPatterns', []) + let required = config.get('requireRootPattern', false) + let resolved: string + if (rootPatterns && rootPatterns.length) { + let doc = workspace.getDocument(workspace.bufnr) + if (doc && doc.schema == 'file') { + let dir = path.dirname(URI.parse(doc.uri).fsPath) + resolved = resolveRoot(dir, rootPatterns, workspace.cwd) + } + } + if (required && !resolved) return false + let rootPath = resolved || workspace.rootPath || workspace.cwd + if (sameFile(rootPath, os.homedir()) || (Array.isArray(ignoredRootPaths) && ignoredRootPaths.some(p => sameFile(rootPath, p)))) { + this.warn(`Ignored rootPath ${rootPath} of client "${this._id}"`) + return null + } + return rootPath + } + + private initialize(connection: IConnection): Promise { + let { initializationOptions, progressOnInitialization } = this._clientOptions + this.refreshTrace(connection, false) + let rootPath = this._rootPath + let initParams: any = { + processId: process.pid, + rootPath: rootPath ? rootPath : null, + rootUri: rootPath ? cv.asUri(URI.file(rootPath)) : null, + capabilities: this.computeClientCapabilities(), + initializationOptions: Is.func(initializationOptions) ? initializationOptions() : initializationOptions, + trace: Trace.toString(this._trace), + workspaceFolders: null, + locale: this.getLocale(), + clientInfo: { + name: 'coc.nvim', + version: workspace.version + } + } + this.fillInitializeParams(initParams) + if (progressOnInitialization) { + const token: ProgressToken = UUID.generateUuid() + initParams.workDoneToken = token + const part = new ProgressPart(this._id, connection, token) + part.begin({ title: `Initializing ${this.id}`, kind: 'begin' }) + return this.doInitialize(connection, initParams).then((result) => { + part.done() + return result + }, (error) => { + part.cancel() + throw error + }) + } else { + return this.doInitialize(connection, initParams) + } + } + + private doInitialize(connection: IConnection, initParams: InitializeParams): Promise { + return connection.initialize(initParams).then(result => { + this._resolvedConnection = connection + this._initializeResult = result + this.state = ClientState.Running + + let textDocumentSyncOptions: TextDocumentSyncOptions | undefined = undefined + if (Is.number(result.capabilities.textDocumentSync)) { + if (result.capabilities.textDocumentSync === TextDocumentSyncKind.None) { + textDocumentSyncOptions = { + openClose: false, + change: TextDocumentSyncKind.None, + save: undefined + } + } else { + textDocumentSyncOptions = { + openClose: true, + change: result.capabilities.textDocumentSync, + save: { + includeText: false + } + } + } + } else if (result.capabilities.textDocumentSync != null && result.capabilities.textDocumentSync !== undefined) { + textDocumentSyncOptions = result.capabilities.textDocumentSync as TextDocumentSyncOptions + } + this._capabilities = Object.assign({}, result.capabilities, { + resolvedTextDocumentSync: textDocumentSyncOptions + }) + connection.onDiagnostics(params => this.handleDiagnostics(params)) + connection.onRequest(RegistrationRequest.type, params => + this.handleRegistrationRequest(params) + ) + // See https://github.com/Microsoft/vscode-languageserver-node/issues/199 + connection.onRequest('client/registerFeature', params => + this.handleRegistrationRequest(params) + ) + connection.onRequest(UnregistrationRequest.type, params => + this.handleUnregistrationRequest(params) + ) + // See https://github.com/Microsoft/vscode-languageserver-node/issues/199 + connection.onRequest('client/unregisterFeature', params => + this.handleUnregistrationRequest(params) + ) + connection.onRequest(ApplyWorkspaceEditRequest.type, params => + this.handleApplyWorkspaceEdit(params) + ) + + connection.sendNotification(InitializedNotification.type, {}) + + this.hookFileEvents(connection) + this.hookConfigurationChanged(connection) + this.initializeFeatures(connection) + this._onReadyCallbacks.resolve() + return result + }).then(undefined, error => { + if (this._clientOptions.initializationFailedHandler) { + if (this._clientOptions.initializationFailedHandler(error)) { + this.initialize(connection) + } else { + this.stop() + this._onReadyCallbacks.reject(error) + } + } else if ( + error instanceof ResponseError && + error.data && + error.data.retry + ) { + window.showPrompt(error.message + ' Retry?').then(confirmed => { + if (confirmed) { + this.initialize(connection) + } else { + this.stop() + this._onReadyCallbacks.reject(error) + } + }) + } else { + if (error && error.message) { + window.showMessage(error.message, 'error') + } + this.error('Server initialization failed.', error) + this.stop() + this._onReadyCallbacks.reject(error) + } + throw error + }) + } + + public stop(): Promise { + this._initializeResult = undefined + if (!this._connectionPromise) { + this.state = ClientState.Stopped + return Promise.resolve() + } + if (this.state === ClientState.Stopping && this._onStop) { + return this._onStop + } + this.state = ClientState.Stopping + this.cleanUp() + const shutdown = this.resolveConnection().then(connection => { + let disposed = false + let timer = setTimeout(() => { + disposed = true + connection.end() + connection.dispose() + }, 2000) + return connection.shutdown().then(() => { + clearTimeout(timer) + connection.exit() + return connection + }, err => { + if (disposed) return + connection.end() + connection.dispose() + throw err + }) + }) + // unkook listeners + return (this._onStop = shutdown.then(connection => { + if (connection) connection.unlisten() + }, err => { + logger.error(`Stopping server failed:`, err) + this.error(`Stopping server failed`, err) + throw err + })).finally(() => { + this.state = ClientState.Stopped + this.cleanUpChannel() + this._onStop = undefined + this._connectionPromise = undefined + this._resolvedConnection = undefined + }) + } + + private cleanUp(channel: boolean = true, diagnostics: boolean = true): void { + if (this._listeners) { + this._listeners.forEach(listener => listener.dispose()) + this._listeners = undefined + } + if (this._providers) { + this._providers.forEach(provider => provider.dispose()) + this._providers = undefined + } + for (let feature of this._features.values()) { + if (typeof feature.dispose === 'function') { + feature.dispose() + } else { + logger.error(`Feature can't be disposed`, feature) + } + } + if (this._syncedDocuments) { + this._syncedDocuments.clear() + } + if (channel) { + this.cleanUpChannel() + } + if (this._diagnostics) { + if (diagnostics) { + this._diagnostics.dispose() + this._diagnostics = undefined + } else { + this._diagnostics.clear() + } + } + } + + private cleanUpChannel(): void { + if (this._outputChannel) { + this._outputChannel.dispose() + this._outputChannel = undefined + } + } + + private notifyFileEvent(event: FileEvent): void { + const client = this + function didChangeWatchedFile(this: void, event: FileEvent) { + client._fileEvents.push(event) + client._fileEventDelayer.trigger(() => { + client.onReady().then(() => { + client.resolveConnection().then(connection => { + if (client.isConnectionActive()) { + connection.didChangeWatchedFiles({ changes: client._fileEvents }) + } + client._fileEvents = [] + }) + }, (error) => { + client.error(`Notify file events failed.`, error) + }) + }) + } + const workSpaceMiddleware = this.clientOptions.middleware?.workspace + workSpaceMiddleware?.didChangeWatchedFile ? workSpaceMiddleware.didChangeWatchedFile(event, didChangeWatchedFile) : didChangeWatchedFile(event) + } + + private handleDiagnostics(params: PublishDiagnosticsParams) { + if (!this._diagnostics) return + let { uri, diagnostics, version } = params + if (typeof version === 'number') { + let doc = workspace.getDocument(uri) + if (!doc || doc.version != version) return + } + let middleware = this.clientOptions.middleware!.handleDiagnostics + if (middleware) { + middleware(uri, diagnostics, (uri, diagnostics) => + this.setDiagnostics(uri, diagnostics) + ) + } else { + this.setDiagnostics(uri, diagnostics) + } + } + + private setDiagnostics(uri: string, diagnostics: Diagnostic[] | undefined) { + if (!this._diagnostics) { + return + } + + const separate = workspace.getConfiguration('diagnostic').get('separateRelatedInformationAsDiagnostics') as boolean + if (separate && diagnostics.length > 0) { + const entries: Map = new Map() + entries.set(uri, diagnostics) + for (const diagnostic of diagnostics) { + if (diagnostic.relatedInformation?.length) { + let message = `${diagnostic.message}\n\nRelated diagnostics:\n` + for (const info of diagnostic.relatedInformation) { + const basename = path.basename(URI.parse(info.location.uri).fsPath) + const ln = info.location.range.start.line + message = `${message}\n${basename}(line ${ln + 1}): ${info.message}` + + const diags: Diagnostic[] = entries.get(info.location.uri) || [] + diags.push(Diagnostic.create(info.location.range, info.message, DiagnosticSeverity.Hint, diagnostic.code, diagnostic.source)) + entries.set(info.location.uri, diags) + } + diagnostic.message = message + } + this._diagnostics.set(Array.from(entries)) + } + } else { + this._diagnostics.set(uri, diagnostics) + } + } + + protected abstract createMessageTransports( + encoding: string + ): Promise + + private createConnection(): Promise { + let errorHandler = (error: Error, message: Message | undefined, count: number | undefined) => { + logger.error('connection error:', error, message) + this.handleConnectionError(error, message, count) + } + + let closeHandler = () => { + this.handleConnectionClosed() + } + + return this.createMessageTransports( + this._clientOptions.stdioEncoding || 'utf8' + ).then(transports => { + return createConnection( + transports.reader, + transports.writer, + errorHandler, + closeHandler, + this._clientOptions.connectionOptions + ) + }) + } + + protected handleConnectionClosed() { + // Check whether this is a normal shutdown in progress or the client stopped normally. + if (this.state === ClientState.Stopped) { + logger.debug(`client ${this._id} normal close`) + return + } + try { + if (this._resolvedConnection) { + this._resolvedConnection.dispose() + } + } catch (error) { + // Disposing a connection could fail if error cases. + } + let action = CloseAction.DoNotRestart + if (this.state !== ClientState.Stopping) { + try { + action = this._clientOptions.errorHandler!.closed() + } catch (error) { + // Ignore errors coming from the error handler. + } + } + this._connectionPromise = undefined + this._resolvedConnection = undefined + if (action === CloseAction.DoNotRestart) { + this.error('Connection to server got closed. Server will not be restarted.') + if (this.state === ClientState.Starting) { + this._onReadyCallbacks.reject(new Error(`Connection to server got closed. Server will not be restarted.`)) + this.state = ClientState.StartFailed + } else { + this.state = ClientState.Stopped + } + this.cleanUp(false, true) + } else if (action === CloseAction.Restart) { + this.info('Connection to server got closed. Server will restart.') + this.cleanUp(false, true) + this.state = ClientState.Initial + this.start() + } + } + + public restart(): void { + this.cleanUp(true, false) + this.start() + } + + private handleConnectionError(error: Error, message: Message, count: number) { + let action = this._clientOptions.errorHandler!.error(error, message, count) + if (action === ErrorAction.Shutdown) { + this.error('Connection to server is erroring. Shutting down server.') + this.stop() + } + } + + private hookConfigurationChanged(connection: IConnection): void { + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(this._id)) { + this.refreshTrace(connection, true) + } + }, null, this._listeners) + } + + private refreshTrace( + connection: IConnection, + sendNotification: boolean = false + ): void { + let config = workspace.getConfiguration(this._id) + let trace: Trace = Trace.Off + let traceFormat: TraceFormat = TraceFormat.Text + if (config) { + const traceConfig = config.get('trace.server', 'off') + + if (typeof traceConfig === 'string') { + trace = Trace.fromString(traceConfig) + } else { + trace = Trace.fromString(config.get('trace.server.verbosity', 'off')) + traceFormat = TraceFormat.fromString(config.get('trace.server.format', 'text')) + } + } + if (sendNotification && this._trace == trace && this._traceFormat == traceFormat) { + return + } + this._trace = trace + this._traceFormat = traceFormat + connection.trace(this._trace, this._tracer, { + sendNotification, + traceFormat: this._traceFormat + }) + } + + private hookFileEvents(_connection: IConnection): void { + let fileEvents = this._clientOptions.synchronize.fileEvents + if (!fileEvents) return + let watchers: FileWatcher[] + if (Array.isArray(fileEvents)) { + watchers = fileEvents + } else { + watchers = [fileEvents] + } + if (!watchers) { + return + } + (this._dynamicFeatures.get( + DidChangeWatchedFilesNotification.type.method + )! as FileSystemWatcherFeature).registerRaw(UUID.generateUuid(), watchers) + } + + private readonly _features: (StaticFeature | DynamicFeature)[] = [] + private readonly _dynamicFeatures: Map> = new Map< + string, + DynamicFeature + >() + + public registerFeatures( + features: (StaticFeature | DynamicFeature)[] + ): void { + for (let feature of features) { + this.registerFeature(feature) + } + } + + public registerFeature(feature: StaticFeature | DynamicFeature): void { + this._features.push(feature) + if (DynamicFeature.is(feature)) { + const registrationType = feature.registrationType + this._dynamicFeatures.set(registrationType.method, feature) + } + } + + public getFeature(request: typeof DidOpenTextDocumentNotification.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => void> + public getFeature(request: typeof DidChangeTextDocumentNotification.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => void> + public getFeature(request: typeof WillSaveTextDocumentNotification.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => void> + public getFeature(request: typeof WillSaveTextDocumentWaitUntilRequest.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => ProviderResult> + public getFeature(request: typeof DidSaveTextDocumentNotification.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => void> + public getFeature(request: typeof DidCloseTextDocumentNotification.method): DynamicFeature & NotificationFeature<(textDocument: TextDocument) => void> + public getFeature(request: typeof DidCreateFilesNotification.method): DynamicFeature & { send: (event: FileCreateEvent) => Promise } + public getFeature(request: typeof DidRenameFilesNotification.method): DynamicFeature & { send: (event: FileRenameEvent) => Promise } + public getFeature(request: typeof DidDeleteFilesNotification.method): DynamicFeature & { send: (event: FileDeleteEvent) => Promise } + public getFeature(request: typeof WillCreateFilesRequest.method): DynamicFeature & { send: (event: FileWillCreateEvent) => Promise } + public getFeature(request: typeof WillRenameFilesRequest.method): DynamicFeature & { send: (event: FileWillRenameEvent) => Promise } + public getFeature(request: typeof WillDeleteFilesRequest.method): DynamicFeature & { send: (event: FileWillDeleteEvent) => Promise } + public getFeature(request: typeof CompletionRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof HoverRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof SignatureHelpRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DefinitionRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof ReferencesRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentHighlightRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof CodeActionRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentFormattingRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentRangeFormattingRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentOnTypeFormattingRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof RenameRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentSymbolRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentLinkRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DocumentColorRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof DeclarationRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof FoldingRangeRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof ImplementationRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof SelectionRangeRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof TypeDefinitionRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof CallHierarchyPrepareRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof SemanticTokensRegistrationType.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof LinkedEditingRangeRequest.method): DynamicFeature & TextDocumentProviderFeature + public getFeature(request: typeof WorkspaceSymbolRequest.method): DynamicFeature & WorkspaceProviderFeature + public getFeature(request: string): DynamicFeature | undefined { + return this._dynamicFeatures.get(request) + } + + protected registerBuiltinFeatures() { + let { disabledFeatures } = this._clientOptions + if (!disabledFeatures.includes('configuration')) { + this.registerFeature(new ConfigurationFeature(this)) + } + this.registerFeature(new DidOpenTextDocumentFeature(this, this._syncedDocuments)) + this.registerFeature(new DidChangeTextDocumentFeature(this)) + this.registerFeature(new DidCloseTextDocumentFeature(this, this._syncedDocuments)) + if (!disabledFeatures.includes('willSave')) { + this.registerFeature(new WillSaveFeature(this)) + } + if (!disabledFeatures.includes('willSaveWaitUntil')) { + this.registerFeature(new WillSaveWaitUntilFeature(this)) + } + if (!disabledFeatures.includes('didSave')) { + this.registerFeature(new DidSaveTextDocumentFeature(this)) + } + if (!disabledFeatures.includes('fileSystemWatcher')) { + this.registerFeature(new FileSystemWatcherFeature(this, event => this.notifyFileEvent(event))) + } + if (!disabledFeatures.includes('completion')) { + this.registerFeature(new CompletionItemFeature(this)) + } + if (!disabledFeatures.includes('hover')) { + this.registerFeature(new HoverFeature(this)) + } + if (!disabledFeatures.includes('signatureHelp')) { + this.registerFeature(new SignatureHelpFeature(this)) + } + if (!disabledFeatures.includes('references')) { + this.registerFeature(new ReferencesFeature(this)) + } + if (!disabledFeatures.includes('definition')) { + this.registerFeature(new DefinitionFeature(this)) + } + if (!disabledFeatures.includes('documentHighlight')) { + this.registerFeature(new DocumentHighlightFeature(this)) + } + if (!disabledFeatures.includes('documentSymbol')) { + this.registerFeature(new DocumentSymbolFeature(this)) + } + if (!disabledFeatures.includes('codeAction')) { + this.registerFeature(new CodeActionFeature(this)) + } + if (!disabledFeatures.includes('workspaceSymbol')) { + this.registerFeature(new WorkspaceSymbolFeature(this)) + } + if (!disabledFeatures.includes('codeLens')) { + this.registerFeature(new CodeLensFeature(this)) + } + if (!disabledFeatures.includes('documentFormatting')) { + this.registerFeature(new DocumentFormattingFeature(this)) + } + if (!disabledFeatures.includes('documentRangeFormatting')) { + this.registerFeature(new DocumentRangeFormattingFeature(this)) + } + if (!disabledFeatures.includes('documentOnTypeFormatting')) { + this.registerFeature(new DocumentOnTypeFormattingFeature(this)) + } + if (!disabledFeatures.includes('rename')) { + this.registerFeature(new RenameFeature(this)) + } + if (!disabledFeatures.includes('documentLink')) { + this.registerFeature(new DocumentLinkFeature(this)) + } + if (!disabledFeatures.includes('executeCommand')) { + this.registerFeature(new ExecuteCommandFeature(this)) + } + } + + private fillInitializeParams(params: InitializeParams): void { + for (let feature of this._features) { + if (Is.func(feature.fillInitializeParams)) { + feature.fillInitializeParams(params) + } + } + } + + private computeClientCapabilities(): ClientCapabilities { + const result: ClientCapabilities = {} + ensure(result, 'workspace')!.applyEdit = true + const workspaceEdit = ensure(ensure(result, 'workspace')!, 'workspaceEdit')! + workspaceEdit.documentChanges = true + workspaceEdit.resourceOperations = [ResourceOperationKind.Create, ResourceOperationKind.Rename, ResourceOperationKind.Delete] + workspaceEdit.failureHandling = FailureHandlingKind.Undo + workspaceEdit.normalizesLineEndings = true + workspaceEdit.changeAnnotationSupport = { + groupsOnLabel: false + } + const diagnostics = ensure(ensure(result, 'textDocument')!, 'publishDiagnostics')! + diagnostics.relatedInformation = true + diagnostics.versionSupport = true + diagnostics.tagSupport = { valueSet: [DiagnosticTag.Unnecessary, DiagnosticTag.Deprecated] } + diagnostics.codeDescriptionSupport = true + diagnostics.dataSupport = true + + const windowCapabilities = ensure(result, 'window')! + const showMessage = ensure(windowCapabilities, 'showMessage')! + showMessage.messageActionItem = { additionalPropertiesSupport: true } + const showDocument = ensure(windowCapabilities, 'showDocument')! + showDocument.support = true + + const generalCapabilities = ensure(result, 'general')! + generalCapabilities.regularExpressions = { engine: 'ECMAScript', version: 'ES2020' } + generalCapabilities.markdown = { parser: 'marked', version: '4.0.10' } + // Added in 3.17.0 + // if (this._clientOptions.markdown.supportHtml) { + // generalCapabilities.markdown.allowedTags = ['ul', 'li', 'p', 'code', 'blockquote', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'em', 'pre', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'div', 'del', 'a', 'strong', 'br', 'img', 'span'] + // } + + for (let feature of this._features) { + feature.fillClientCapabilities(result) + } + return result + } + + private initializeFeatures(_connection: IConnection): void { + let documentSelector = this._clientOptions.documentSelector + for (let feature of this._features) { + feature.initialize(this._capabilities, documentSelector) + } + } + + private handleRegistrationRequest( + params: RegistrationParams + ): Promise { + if (this.clientOptions.disableDynamicRegister) return Promise.resolve() + return new Promise((resolve, reject) => { + for (const registration of params.registrations) { + const feature = this._dynamicFeatures.get(registration.method) + if (!feature) { + reject( + new Error( + `No feature implementation for ${registration.method} found. Registration failed.` + ) + ) + return + } + const options = registration.registerOptions || {} + options.documentSelector = options.documentSelector || this._clientOptions.documentSelector + const data: RegistrationData = { + id: registration.id, + registerOptions: options + } + try { + feature.register(data) + } catch (err) { + reject(err) + return + } + } + resolve() + }) + } + + private handleUnregistrationRequest( + params: UnregistrationParams + ): Promise { + return new Promise((resolve, reject) => { + for (let unregistration of params.unregisterations) { + const feature = this._dynamicFeatures.get(unregistration.method) + if (!feature) { + reject( + new Error( + `No feature implementation for ${unregistration.method} found. Unregistration failed.` + ) + ) + return + } + feature.unregister(unregistration.id) + } + resolve() + }) + } + + private handleApplyWorkspaceEdit( + params: ApplyWorkspaceEditParams + ): Promise { + // This is some sort of workaround since the version check should be done by VS Code in the Workspace.applyEdit. + // However doing it here adds some safety since the server can lag more behind then an extension. + let workspaceEdit: WorkspaceEdit = params.edit + let openTextDocuments: Map = new Map() + workspace.textDocuments.forEach((document) => openTextDocuments.set(document.uri.toString(), document)) + let versionMismatch = false + if (workspaceEdit.documentChanges) { + for (const change of workspaceEdit.documentChanges) { + if (TextDocumentEdit.is(change) && change.textDocument.version && change.textDocument.version >= 0) { + let textDocument = openTextDocuments.get(change.textDocument.uri) + if (textDocument && textDocument.version !== change.textDocument.version) { + versionMismatch = true + break + } + } + } + } + if (versionMismatch) { + return Promise.resolve({ applied: false }) + } + return workspace.applyEdit(params.edit).then(value => { + return { applied: value } + }) + } + + private getLocale(): string { + const lang = process.env.LANG + if (!lang) return 'en' + + return lang.split('.')[0] + } + + public handleFailedRequest(type: MessageSignature, token: CancellationToken | undefined, error: unknown, defaultValue: T): T { + // If we get a request cancel or a content modified don't log anything. + if (error instanceof ResponseError) { + if (error.code === LSPErrorCodes.RequestCancelled) { + if (token !== undefined && token.isCancellationRequested) { + return defaultValue + } + // do not throw error + } else if (error.code === LSPErrorCodes.ContentModified) { + return defaultValue + } + } + this.error(`Request ${type.method} failed.`, error) + } + + public logFailedRequest(type: any, error: any): void { + // If we get a request cancel don't log anything. + if (error instanceof ResponseError && error.code === LSPErrorCodes.RequestCancelled) { + // TODO: handle LSPErrorCodes.ContentModified + return + } + this.error(`Request ${type.method} failed.`, error) + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/colorProvider.ts b/sources_non_forked/coc.nvim/src/language-client/colorProvider.ts new file mode 100644 index 00000000..197f1819 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/colorProvider.ts @@ -0,0 +1,107 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { CancellationToken, ClientCapabilities, Color, ColorInformation, ColorPresentation, ColorPresentationRequest, Disposable, DocumentColorOptions, DocumentColorRegistrationOptions, DocumentColorRequest, DocumentSelector, Range, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { DocumentColorProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' + +export type ProvideDocumentColorsSignature = (document: TextDocument, token: CancellationToken) => ProviderResult + +export type ProvideColorPresentationSignature = ( + color: Color, + context: { document: TextDocument; range: Range }, + token: CancellationToken +) => ProviderResult + +export interface ColorProviderMiddleware { + provideDocumentColors?: ( + this: void, + document: TextDocument, + token: CancellationToken, + next: ProvideDocumentColorsSignature + ) => ProviderResult + provideColorPresentations?: ( + this: void, + color: Color, + context: { document: TextDocument; range: Range }, + token: CancellationToken, + next: ProvideColorPresentationSignature + ) => ProviderResult +} + +export class ColorProviderFeature extends TextDocumentFeature< + boolean | DocumentColorOptions, DocumentColorRegistrationOptions, DocumentColorProvider + > { + constructor(client: BaseLanguageClient) { + super(client, DocumentColorRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(ensure(capabilities, 'textDocument')!, 'colorProvider')!.dynamicRegistration = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + let [id, options] = this.getRegistration(documentSelector, capabilities.colorProvider) + if (!id || !options) { + return + } + + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider( + options: DocumentColorRegistrationOptions + ): [Disposable, DocumentColorProvider] { + const provider: DocumentColorProvider = { + provideColorPresentations: (color, context, token) => { + const client = this._client + const provideColorPresentations: ProvideColorPresentationSignature = (color, context, token) => { + const requestParams = { + color, + textDocument: { uri: context.document.uri }, + range: context.range + } + return client.sendRequest(ColorPresentationRequest.type, requestParams, token).then( + res => res, + (error: any) => { + return client.handleFailedRequest(ColorPresentationRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware + return middleware.provideColorPresentations + ? middleware.provideColorPresentations(color, context, token, provideColorPresentations) + : provideColorPresentations(color, context, token) + }, + provideDocumentColors: (document, token) => { + const client = this._client + const provideDocumentColors: ProvideDocumentColorsSignature = (document, token) => { + const requestParams = { + textDocument: { uri: document.uri } + } + return client.sendRequest(DocumentColorRequest.type, requestParams, token).then( + res => res, + (error: any) => { + return client.handleFailedRequest(ColorPresentationRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware + return middleware.provideDocumentColors + ? middleware.provideDocumentColors(document, token, provideDocumentColors) + : provideDocumentColors(document, token) + } + } + + return [languages.registerDocumentColorProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/configuration.ts b/sources_non_forked/coc.nvim/src/language-client/configuration.ts new file mode 100644 index 00000000..365863ba --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/configuration.ts @@ -0,0 +1,95 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +import { ClientCapabilities, ConfigurationRequest } from 'vscode-languageserver-protocol' +import workspace from '../workspace' +import { BaseLanguageClient, StaticFeature } from './client' +const logger = require('../util/logger')('languageclient-configuration') + +export interface ConfigurationWorkspaceMiddleware { + configuration?: ConfigurationRequest.MiddlewareSignature +} + +export class ConfigurationFeature implements StaticFeature { + private languageserverSection: string | undefined + constructor(private _client: BaseLanguageClient) { + let section = this._client.clientOptions.synchronize?.configurationSection + if (typeof section === 'string' && section.startsWith('languageserver.')) { + this.languageserverSection = section + } + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + capabilities.workspace = capabilities.workspace || {} + capabilities.workspace.configuration = true + } + + public initialize(): void { + let client = this._client + client.onRequest(ConfigurationRequest.type, (params, token) => { + let configuration: ConfigurationRequest.HandlerSignature = params => { + let result: any[] = [] + for (let item of params.items) { + result.push(this.getConfiguration(item.scopeUri, item.section)) + } + return result + } + let middleware = client.clientOptions.middleware.workspace + return middleware && middleware.configuration + ? middleware.configuration(params, token, configuration) + : configuration(params, token) + }) + } + + private getConfiguration( + resource: string | undefined, + section: string | undefined + ): any { + let result: any = null + if (section) { + if (this.languageserverSection) { + section = `${this.languageserverSection}.${section}` + } + let index = section.lastIndexOf('.') + if (index === -1) { + result = toJSONObject(workspace.getConfiguration(undefined, resource).get(section)) + } else { + let config = workspace.getConfiguration(section.substr(0, index), resource) + if (config) { + result = toJSONObject(config.get(section.substr(index + 1))) + } + } + } else { + let config = workspace.getConfiguration(this.languageserverSection, resource) + result = {} + for (let key of Object.keys(config)) { + if (config.has(key)) { + result[key] = toJSONObject(config.get(key)) + } + } + } + return result + } + + public dispose(): void { + } +} + +export function toJSONObject(obj: any): any { + if (obj) { + if (Array.isArray(obj)) { + return obj.map(toJSONObject) + } else if (typeof obj === 'object') { + const res = Object.create(null) + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + res[key] = toJSONObject(obj[key]) + } + } + return res + } + } + return obj +} diff --git a/sources_non_forked/coc.nvim/src/language-client/declaration.ts b/sources_non_forked/coc.nvim/src/language-client/declaration.ts new file mode 100644 index 00000000..f9adbc14 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/declaration.ts @@ -0,0 +1,61 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { CancellationToken, ClientCapabilities, Declaration, DeclarationLink, DeclarationOptions, DeclarationRegistrationOptions, DeclarationRequest, Disposable, DocumentSelector, Position, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { DeclarationProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' +import { asTextDocumentPositionParams } from './utils/converter' + +export interface ProvideDeclarationSignature { + (this: void, document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +export interface DeclarationMiddleware { + provideDeclaration?: (this: void, document: TextDocument, position: Position, token: CancellationToken, next: ProvideDeclarationSignature) => ProviderResult +} + +export class DeclarationFeature extends TextDocumentFeature { + + constructor(client: BaseLanguageClient) { + super(client, DeclarationRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let declarationSupport = ensure(ensure(capabilities, 'textDocument')!, 'declaration')! + declarationSupport.dynamicRegistration = true + // declarationSupport.linkSupport = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const [id, options] = this.getRegistration(documentSelector, capabilities.declarationProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: DeclarationRegistrationOptions): [Disposable, DeclarationProvider] { + const provider: DeclarationProvider = { + provideDeclaration: (document: TextDocument, position: Position, token: CancellationToken) => { + const client = this._client + const provideDeclaration: ProvideDeclarationSignature = (document, position, token) => client.sendRequest(DeclarationRequest.type, asTextDocumentPositionParams(document, position), token).then( + res => res, error => { + return client.handleFailedRequest(DeclarationRequest.type, token, error, null) + } + ) + const middleware = client.clientOptions.middleware + return middleware.provideDeclaration + ? middleware.provideDeclaration(document, position, token, provideDeclaration) + : provideDeclaration(document, position, token) + } + } + + return [languages.registerDeclarationProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/fileOperations.ts b/sources_non_forked/coc.nvim/src/language-client/fileOperations.ts new file mode 100644 index 00000000..fb7a75ac --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/fileOperations.ts @@ -0,0 +1,430 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ + +import * as minimatch from 'minimatch' +import { ClientCapabilities, CreateFilesParams, DeleteFilesParams, DidCreateFilesNotification, DidDeleteFilesNotification, DidRenameFilesNotification, Disposable, Event, FileOperationClientCapabilities, FileOperationOptions, FileOperationPatternKind, FileOperationPatternOptions, FileOperationRegistrationOptions, ProtocolNotificationType, ProtocolRequestType, RegistrationType, RenameFilesParams, ServerCapabilities, WillCreateFilesRequest, WillDeleteFilesRequest, WillRenameFilesRequest, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import { FileCreateEvent, FileDeleteEvent, FileRenameEvent, FileType, FileWillCreateEvent, FileWillDeleteEvent, FileWillRenameEvent } from '../types' +import { statAsync } from '../util/fs' +import workspace from '../workspace' +import { BaseLanguageClient, DynamicFeature, ensure, NextSignature, RegistrationData } from './client' +import * as UUID from './utils/uuid' +const logger = require('../util/logger')('language-client-fileOperations') + +function access(target: T, key: K): T[K] { + return target[key] +} + +function assign(target: T, key: K, value: T[K]): void { + target[key] = value +} + +function asCreateDeleteFilesParams(e: FileCreateEvent | FileDeleteEvent): CreateFilesParams | DeleteFilesParams { + return { + files: e.files.map(f => ({ uri: f.toString() })) + } +} + +function asRenameFilesParams(e: FileRenameEvent | FileWillRenameEvent): RenameFilesParams { + return { + files: e.files.map(f => ({ oldUri: f.oldUri.toString(), newUri: f.newUri.toString() })) + } +} + +/** + * File operation middleware + * + * @since 3.16.0 + */ +export interface FileOperationsMiddleware { + didCreateFiles?: NextSignature + willCreateFiles?: NextSignature> + didRenameFiles?: NextSignature + willRenameFiles?: NextSignature> + didDeleteFiles?: NextSignature + willDeleteFiles?: NextSignature> +} + +interface EventWithFiles { + readonly files: ReadonlyArray +} + +abstract class FileOperationFeature> + implements DynamicFeature { + protected _client: BaseLanguageClient + private _event: Event + private _registrationType: RegistrationType + private _clientCapability: keyof FileOperationClientCapabilities + private _serverCapability: keyof FileOperationOptions + private _listener: Disposable | undefined + private _filters = new Map< + string, + Array<{ + scheme?: string + matcher: minimatch.IMinimatch + kind?: FileOperationPatternKind + }> + >() + + constructor( + client: BaseLanguageClient, + event: Event, + registrationType: RegistrationType, + clientCapability: keyof FileOperationClientCapabilities, + serverCapability: keyof FileOperationOptions + ) { + this._client = client + this._event = event + this._registrationType = registrationType + this._clientCapability = clientCapability + this._serverCapability = serverCapability + } + + public get registrationType(): RegistrationType { + return this._registrationType + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const value = ensure(ensure(capabilities, 'workspace')!, 'fileOperations')! + // this happens n times but it is the same value so we tolerate this. + assign(value, 'dynamicRegistration', true) + assign(value, this._clientCapability, true) + } + + public initialize(capabilities: ServerCapabilities): void { + const options = capabilities.workspace?.fileOperations + const capability = options !== undefined ? access(options, this._serverCapability) : undefined + if (capability?.filters !== undefined) { + try { + this.register({ + id: UUID.generateUuid(), + registerOptions: { filters: capability.filters }, + }) + } catch (e) { + this._client.warn( + `Ignoring invalid glob pattern for ${this._serverCapability} registration: ${e}` + ) + } + } + } + + public register(data: RegistrationData): void { + if (!this._listener) { + this._listener = this._event(this.send, this) + } + const minimatchFilter = data.registerOptions.filters.map(filter => { + const matcher = new minimatch.Minimatch( + filter.pattern.glob, + FileOperationFeature.asMinimatchOptions(filter.pattern.options) + ) + if (!matcher.makeRe()) { + throw new Error(`Invalid pattern ${filter.pattern.glob}!`) + } + return { scheme: filter.scheme, matcher, kind: filter.pattern.matches } + }) + this._filters.set(data.id, minimatchFilter) + } + + public abstract send(data: E): Promise + + public unregister(id: string): void { + this._filters.delete(id) + if (this._filters.size === 0 && this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + public dispose(): void { + this._filters.clear() + if (this._listener) { + this._listener.dispose() + this._listener = undefined + } + } + + protected async filter(event: E, prop: (i: I) => URI): Promise { + // (Asynchronously) map each file onto a boolean of whether it matches + // any of the globs. + const fileMatches = await Promise.all( + event.files.map(async item => { + const uri = prop(item) + // Use fsPath to make this consistent with file system watchers but help + // minimatch to use '/' instead of `\\` if present. + const path = uri.fsPath.replace(/\\/g, '/') + for (const filters of this._filters.values()) { + for (const filter of filters) { + if (filter.scheme !== undefined && filter.scheme !== uri.scheme) { + continue + } + if (filter.matcher.match(path)) { + // The pattern matches. If kind is undefined then everything is ok + if (filter.kind === undefined) { + return true + } + const fileType = await FileOperationFeature.getFileType(uri) + // If we can't determine the file type than we treat it as a match. + // Dropping it would be another alternative. + if (fileType === undefined) { + this._client.error( + `Failed to determine file type for ${uri.toString()}.` + ) + return true + } + if ( + (fileType === FileType.File && filter.kind === FileOperationPatternKind.file) || + (fileType === FileType.Directory && filter.kind === FileOperationPatternKind.folder) + ) { + return true + } + } else if (filter.kind === FileOperationPatternKind.folder) { + const fileType = await FileOperationFeature.getFileType(uri) + if (fileType === FileType.Directory && filter.matcher.match(`${path}/`)) { + return true + } + } + } + } + return false + }) + ) + + // Filter the files to those that matched. + const files = event.files.filter((_, index) => fileMatches[index]) + + return { ...event, files } + } + + private static async getFileType(uri: URI): Promise { + try { + const stat = await statAsync(uri.fsPath) + if (stat.isFile()) { + return FileType.File + } + if (stat.isDirectory()) { + return FileType.Directory + } + if (stat.isSymbolicLink()) { + return FileType.SymbolicLink + } + return FileType.Unknown + } catch (e) { + return undefined + } + } + + private static asMinimatchOptions(options: FileOperationPatternOptions | undefined): minimatch.IOptions | undefined { + if (options === undefined) { + return undefined + } + if (options.ignoreCase === true) { + return { nocase: true } + } + return undefined + } +} + +abstract class NotificationFileOperationFeature }, P> extends FileOperationFeature { + + private _notificationType: ProtocolNotificationType + private _accessUri: (i: I) => URI + private _createParams: (e: E) => P + + constructor( + client: BaseLanguageClient, + event: Event, + notificationType: ProtocolNotificationType, + clientCapability: keyof FileOperationClientCapabilities, + serverCapability: keyof FileOperationOptions, + accessUri: (i: I) => URI, + createParams: (e: E) => P + ) { + super(client, event, notificationType, clientCapability, serverCapability) + this._notificationType = notificationType + this._accessUri = accessUri + this._createParams = createParams + } + + public async send(originalEvent: E): Promise { + // Create a copy of the event that has the files filtered to match what the + // server wants. + const filteredEvent = await this.filter(originalEvent, this._accessUri) + if (filteredEvent.files.length) { + const next = async (event: E): Promise => { + this._client.sendNotification( + this._notificationType, + this._createParams(event) + ) + } + this.doSend(filteredEvent, next) + } + } + + protected abstract doSend(event: E, next: (event: E) => void): void +} + +export class DidCreateFilesFeature extends NotificationFileOperationFeature { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onDidCreateFiles, + DidCreateFilesNotification.type, + 'didCreate', + 'didCreate', + (i: URI) => i, + e => asCreateDeleteFilesParams(e), + ) + } + + protected doSend(event: FileCreateEvent, next: (event: FileCreateEvent) => void): void { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.didCreateFiles ? middleware.didCreateFiles(event, next) : next(event) + } +} + +export class DidRenameFilesFeature extends NotificationFileOperationFeature<{ oldUri: URI; newUri: URI }, FileRenameEvent, RenameFilesParams> { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onDidRenameFiles, + DidRenameFilesNotification.type, + 'didRename', + 'didRename', + (i: { oldUri: URI; newUri: URI }) => i.oldUri, + e => asRenameFilesParams(e) + ) + } + + protected doSend(event: FileRenameEvent, next: (event: FileRenameEvent) => void): void { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.didRenameFiles ? middleware.didRenameFiles(event, next) : next(event) + } +} + +export class DidDeleteFilesFeature extends NotificationFileOperationFeature { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onDidDeleteFiles, + DidDeleteFilesNotification.type, + 'didDelete', + 'didDelete', + (i: URI) => i, + e => asCreateDeleteFilesParams(e) + ) + } + + protected doSend(event: FileCreateEvent, next: (event: FileCreateEvent) => void): void { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.didDeleteFiles ? middleware.didDeleteFiles(event, next) : next(event) + } +} + +interface RequestEvent { + readonly files: ReadonlyArray + waitUntil(thenable: Thenable): void +} + +abstract class RequestFileOperationFeature, P> extends FileOperationFeature { + private _requestType: ProtocolRequestType + private _accessUri: (i: I) => URI + private _createParams: (e: EventWithFiles) => P + + constructor( + client: BaseLanguageClient, + event: Event, + requestType: ProtocolRequestType, + clientCapability: keyof FileOperationClientCapabilities, + serverCapability: keyof FileOperationOptions, + accessUri: (i: I) => URI, + createParams: (e: EventWithFiles) => P + ) { + super(client, event, requestType, clientCapability, serverCapability) + this._requestType = requestType + this._accessUri = accessUri + this._createParams = createParams + } + + public async send(originalEvent: E & RequestEvent): Promise { + const waitUntil = this.waitUntil(originalEvent) + originalEvent.waitUntil(waitUntil) + } + + private async waitUntil(originalEvent: E): Promise { + // Create a copy of the event that has the files filtered to match what the + // server wants. + const filteredEvent = await this.filter(originalEvent, this._accessUri) + + if (filteredEvent.files.length) { + const next = (event: EventWithFiles): Promise => { + return this._client.sendRequest(this._requestType, this._createParams(event)) + } + return this.doSend(filteredEvent, next) + } else { + return undefined + } + } + + protected abstract doSend(event: E, next: (event: EventWithFiles) => Thenable | Thenable): Thenable | Thenable +} + +export class WillCreateFilesFeature extends RequestFileOperationFeature { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onWillCreateFiles, + WillCreateFilesRequest.type, + 'willCreate', + 'willCreate', + (i: URI) => i, + e => asCreateDeleteFilesParams(e) + ) + } + + protected doSend(event: FileWillCreateEvent, next: (event: FileWillCreateEvent) => Thenable | Thenable): Thenable | Thenable { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.willCreateFiles ? middleware.willCreateFiles(event, next) : next(event) + } +} + +export class WillRenameFilesFeature extends RequestFileOperationFeature<{ oldUri: URI; newUri: URI }, FileWillRenameEvent, RenameFilesParams> { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onWillRenameFiles, + WillRenameFilesRequest.type, + 'willRename', + 'willRename', + (i: { oldUri: URI; newUri: URI }) => i.oldUri, + e => asRenameFilesParams(e) + ) + } + + protected doSend(event: FileWillRenameEvent, next: (event: FileWillRenameEvent) => Thenable | Thenable): Thenable | Thenable { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.willRenameFiles ? middleware.willRenameFiles(event, next) : next(event) + } +} + +export class WillDeleteFilesFeature extends RequestFileOperationFeature { + constructor(client: BaseLanguageClient) { + super( + client, + workspace.onWillDeleteFiles, + WillDeleteFilesRequest.type, + 'willDelete', + 'willDelete', + (i: URI) => i, + e => asCreateDeleteFilesParams(e) + ) + } + + protected doSend(event: FileWillDeleteEvent, next: (event: FileWillDeleteEvent) => Thenable | Thenable): Thenable | Thenable { + const middleware = this._client.clientOptions.middleware?.workspace + return middleware?.willDeleteFiles ? middleware.willDeleteFiles(event, next) : next(event) + } +} + diff --git a/sources_non_forked/coc.nvim/src/language-client/foldingRange.ts b/sources_non_forked/coc.nvim/src/language-client/foldingRange.ts new file mode 100644 index 00000000..69170cdc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/foldingRange.ts @@ -0,0 +1,81 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { CancellationToken, ClientCapabilities, Disposable, DocumentSelector, FoldingRange, FoldingRangeOptions, FoldingRangeParams, FoldingRangeRegistrationOptions, FoldingRangeRequest, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { FoldingContext, FoldingRangeProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' + +export type ProvideFoldingRangeSignature = ( + this: void, + document: TextDocument, + context: FoldingContext, + token: CancellationToken +) => ProviderResult + +export interface FoldingRangeProviderMiddleware { + provideFoldingRanges?: ( + this: void, + document: TextDocument, + context: FoldingContext, + token: CancellationToken, + next: ProvideFoldingRangeSignature + ) => ProviderResult +} + +export class FoldingRangeFeature extends TextDocumentFeature< + boolean | FoldingRangeOptions, FoldingRangeRegistrationOptions, FoldingRangeProvider + > { + constructor(client: BaseLanguageClient) { + super(client, FoldingRangeRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + let capability = ensure(ensure(capabilities, 'textDocument')!, 'foldingRange')! + capability.dynamicRegistration = true + capability.rangeLimit = 5000 + capability.lineFoldingOnly = true + } + + public initialize( + capabilities: ServerCapabilities, + documentSelector: DocumentSelector + ): void { + const [id, options] = this.getRegistration(documentSelector, capabilities.foldingRangeProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider( + options: FoldingRangeRegistrationOptions + ): [Disposable, FoldingRangeProvider] { + const provider: FoldingRangeProvider = { + provideFoldingRanges: (document, context, token) => { + const client = this._client + const provideFoldingRanges: ProvideFoldingRangeSignature = (document, _, token) => { + const requestParams: FoldingRangeParams = { + textDocument: { uri: document.uri } + } + return client.sendRequest(FoldingRangeRequest.type, requestParams, token).then( + res => res, (error: any) => { + return client.handleFailedRequest(FoldingRangeRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware + return middleware.provideFoldingRanges + ? middleware.provideFoldingRanges(document, context, token, provideFoldingRanges) + : provideFoldingRanges(document, context, token) + } + } + + return [languages.registerFoldingRangeProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/implementation.ts b/sources_non_forked/coc.nvim/src/language-client/implementation.ts new file mode 100644 index 00000000..736fc5cc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/implementation.ts @@ -0,0 +1,59 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { CancellationToken, ClientCapabilities, Definition, DefinitionLink, Disposable, DocumentSelector, ImplementationOptions, ImplementationRegistrationOptions, ImplementationRequest, Position, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { ImplementationProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' +import * as cv from './utils/converter' + +export interface ProvideImplementationSignature { + (this: void, document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +export interface ImplementationMiddleware { + provideImplementation?: (this: void, document: TextDocument, position: Position, token: CancellationToken, next: ProvideImplementationSignature) => ProviderResult +} + +export class ImplementationFeature extends TextDocumentFeature { + + constructor(client: BaseLanguageClient) { + super(client, ImplementationRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const implementationSupport = ensure(ensure(capabilities, 'textDocument')!, 'implementation')! + implementationSupport.dynamicRegistration = true + // implementationSupport.linkSupport = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const [id, options] = this.getRegistration(documentSelector, capabilities.implementationProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: ImplementationRegistrationOptions): [Disposable, ImplementationProvider] { + const provider: ImplementationProvider = { + provideImplementation: (document, position, token) => { + const client = this._client + const provideImplementation: ProvideImplementationSignature = (document, position, token) => client.sendRequest(ImplementationRequest.type, cv.asTextDocumentPositionParams(document, position), token).then( + res => res, error => { + return client.handleFailedRequest(ImplementationRequest.type, token, error, null) + } + ) + const middleware = client.clientOptions.middleware + return middleware.provideImplementation + ? middleware.provideImplementation(document, position, token, provideImplementation) + : provideImplementation(document, position, token) + } + } + + return [languages.registerImplementationProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/index.ts b/sources_non_forked/coc.nvim/src/language-client/index.ts new file mode 100644 index 00000000..55088fd5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/index.ts @@ -0,0 +1,655 @@ +'use strict' +/* eslint-disable no-redeclare */ +import cp from 'child_process' +import fs from 'fs' +import path from 'path' +import { createClientPipeTransport, createClientSocketTransport, Disposable, DocumentFilter, generateRandomPipeName, IPCMessageReader, IPCMessageWriter, StreamMessageReader, StreamMessageWriter } from 'vscode-languageserver-protocol/node' +import { ServiceStat } from '../types' +import { disposeAll } from '../util' +import * as Is from '../util/is' +import { terminate } from '../util/processes' +import workspace from '../workspace' +import { BaseLanguageClient, ClientState, DynamicFeature, LanguageClientOptions, MessageTransports, StaticFeature } from './client' +import { ColorProviderFeature } from './colorProvider' +import { ConfigurationFeature as PullConfigurationFeature } from './configuration' +import { DeclarationFeature } from './declaration' +import { FoldingRangeFeature } from './foldingRange' +import { ImplementationFeature } from './implementation' +import { ProgressFeature } from './progress' +import { TypeDefinitionFeature } from './typeDefinition' +import { WorkspaceFoldersFeature } from './workspaceFolders' +import { SelectionRangeFeature } from './selectionRange' +import ChildProcess = cp.ChildProcess +import { CallHierarchyFeature } from './callHierarchy' +import { SemanticTokensFeature } from './semanticTokens' +import { LinkedEditingFeature } from './linkedEditingRange' +import { DidCreateFilesFeature, DidDeleteFilesFeature, DidRenameFilesFeature, WillCreateFilesFeature, WillDeleteFilesFeature, WillRenameFilesFeature } from './fileOperations' + +const logger = require('../util/logger')('language-client-index') + +export * from './client' + +declare let v8debug: any + +export interface ExecutableOptions { + cwd?: string + env?: any + detached?: boolean + shell?: boolean +} + +export interface Executable { + command: string + args?: string[] + options?: ExecutableOptions +} + +namespace Executable { + export function is(value: any): value is Executable { + return Is.string(value.command) + } +} + +export interface ForkOptions { + cwd?: string + env?: any + execPath?: string + encoding?: string + execArgv?: string[] +} + +export enum TransportKind { + stdio, + ipc, + pipe, + socket +} + +export interface SocketTransport { + kind: TransportKind.socket + port: number +} + +namespace Transport { + export function isSocket(value: Transport): value is SocketTransport { + let candidate = value as SocketTransport + return ( + candidate && + candidate.kind === TransportKind.socket && + Is.number(candidate.port) + ) + } +} + +/** + * To avoid any timing, pipe name or port number issues the pipe (TransportKind.pipe) + * and the sockets (TransportKind.socket and SocketTransport) are owned by the + * VS Code processes. The server process simply connects to the pipe / socket. + * In node term the VS Code process calls `createServer`, then starts the server + * process, waits until the server process has connected to the pipe / socket + * and then signals that the connection has been established and messages can + * be send back and forth. If the language server is implemented in a different + * program language the server simply needs to create a connection to the + * passed pipe name or port number. + */ +export type Transport = TransportKind | SocketTransport + +export interface NodeModule { + module: string + transport?: Transport + args?: string[] + runtime?: string + options?: ForkOptions +} + +namespace NodeModule { + export function is(value: any): value is NodeModule { + return Is.string(value.module) + } +} + +export interface StreamInfo { + writer: NodeJS.WritableStream + reader: NodeJS.ReadableStream + detached?: boolean +} + +namespace StreamInfo { + export function is(value: any): value is StreamInfo { + let candidate = value as StreamInfo + return ( + candidate && candidate.writer !== void 0 && candidate.reader !== void 0 + ) + } +} + +export interface ChildProcessInfo { + process: ChildProcess + detached: boolean +} + +namespace ChildProcessInfo { + export function is(value: any): value is ChildProcessInfo { + let candidate = value as ChildProcessInfo + return ( + candidate && + candidate.process !== void 0 && + typeof candidate.detached === 'boolean' + ) + } +} + +export type ServerOptions = + | Executable + | { run: Executable; debug: Executable } + | { run: NodeModule; debug: NodeModule } + | NodeModule + | (() => Promise) + +export class LanguageClient extends BaseLanguageClient { + private _forceDebug: boolean + private _serverProcess: ChildProcess | undefined + private _isDetached: boolean | undefined + private _serverOptions: ServerOptions + + public constructor( + name: string, + serverOptions: ServerOptions, + clientOptions: LanguageClientOptions, + forceDebug?: boolean + ) + public constructor( + id: string, + name: string, + serverOptions: ServerOptions, + clientOptions: LanguageClientOptions, + forceDebug?: boolean + ) + public constructor( + arg1: string, + arg2: string | ServerOptions, + arg3: LanguageClientOptions | ServerOptions, + arg4?: boolean | LanguageClientOptions, + arg5?: boolean + ) { + let id: string + let name: string + let serverOptions: ServerOptions + let clientOptions: LanguageClientOptions + let forceDebug: boolean + if (Is.string(arg2)) { + id = arg1 + name = arg2 + serverOptions = arg3 as ServerOptions + clientOptions = arg4 as LanguageClientOptions + forceDebug = !!arg5 + } else { + // first signature + id = arg1.toLowerCase() + name = arg1 + serverOptions = arg2 + clientOptions = arg3 as LanguageClientOptions + forceDebug = arg4 as boolean + } + if (forceDebug === void 0) { + forceDebug = false + } + super(id, name, clientOptions) + this._serverOptions = serverOptions + this._forceDebug = forceDebug + this.registerProposedFeatures() + } + + public stop(): Promise { + return super.stop().then(() => { + if (this._serverProcess) { + let toCheck = this._serverProcess + this._serverProcess = undefined + if (this._isDetached === void 0 || !this._isDetached) { + this.checkProcessDied(toCheck) + } + this._isDetached = undefined + } + }) + } + + public get serviceState(): ServiceStat { + let state = this._state + switch (state) { + case ClientState.Initial: + return ServiceStat.Initial + case ClientState.Running: + return ServiceStat.Running + case ClientState.StartFailed: + return ServiceStat.StartFailed + case ClientState.Starting: + return ServiceStat.Starting + case ClientState.Stopped: + return ServiceStat.Stopped + case ClientState.Stopping: + return ServiceStat.Stopping + default: + logger.error(`Unknown state: ${state}`) + return ServiceStat.Stopped + } + } + + public static stateName(state: ClientState): string { + switch (state) { + case ClientState.Initial: + return 'Initial' + case ClientState.Running: + return 'Running' + case ClientState.StartFailed: + return 'StartFailed' + case ClientState.Starting: + return 'Starting' + case ClientState.Stopped: + return 'Stopped' + case ClientState.Stopping: + return 'Stopping' + default: + return 'Unknown' + } + } + + private checkProcessDied(childProcess: ChildProcess | undefined): void { + if (!childProcess || global.__TEST__) return + setTimeout(() => { + // Test if the process is still alive. Throws an exception if not + try { + process.kill(childProcess.pid, 0) + terminate(childProcess) + } catch (error) { + // All is fine. + } + }, 2000) + } + + protected handleConnectionClosed(): void { + this._serverProcess = undefined + super.handleConnectionClosed() + } + + protected createMessageTransports(encoding: string): Promise { + + function getEnvironment(env: any, fork: boolean): any { + if (!env && !fork) { + return undefined + } + let result: any = Object.create(null) + Object.keys(process.env).forEach(key => result[key] = process.env[key]) + if (env) { + Object.keys(env).forEach(key => result[key] = env[key]) + } + return result + } + + const debugStartWith: string[] = ['--debug=', '--debug-brk=', '--inspect=', '--inspect-brk='] + const debugEquals: string[] = ['--debug', '--debug-brk', '--inspect', '--inspect-brk'] + function startedInDebugMode(): boolean { + let args: string[] = (process as any).execArgv + if (args) { + return args.some(arg => { + return debugStartWith.some(value => arg.startsWith(value)) || + debugEquals.some(value => arg === value) + }) + } + return false + } + + function assertStdio(process: cp.ChildProcess): asserts process is cp.ChildProcessWithoutNullStreams { + if (process.stdin === null || process.stdout === null || process.stderr === null) { + throw new Error('Process created without stdio streams') + } + } + + let server = this._serverOptions + // We got a function. + if (Is.func(server)) { + return server().then(result => { + if (MessageTransports.is(result)) { + this._isDetached = !!result.detached + return result + } else if (StreamInfo.is(result)) { + this._isDetached = !!result.detached + return { + reader: new StreamMessageReader(result.reader), + writer: new StreamMessageWriter(result.writer) + } + } else { + let cp: ChildProcess + if (ChildProcessInfo.is(result)) { + cp = result.process + this._isDetached = result.detached + } else { + cp = result + this._isDetached = false + } + cp.stderr!.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + return { + reader: new StreamMessageReader(cp.stdout!), + writer: new StreamMessageWriter(cp.stdin!) + } + } + }) + } + let json: NodeModule | Executable + let runDebug = server as { run: any; debug: any } + if (runDebug.run || runDebug.debug) { + if (typeof v8debug === 'object' || this._forceDebug || startedInDebugMode()) { + json = runDebug.debug + } else { + json = runDebug.run + } + } else { + json = server as NodeModule | Executable + } + return this._getServerWorkingDir(json.options).then(serverWorkingDir => { + if (NodeModule.is(json) && json.module) { + let node = json + let transport = node.transport || TransportKind.stdio + if (node.runtime) { + let args: string[] = [] + let options: ForkOptions = node.options || Object.create(null) + if (options.execArgv) { + options.execArgv.forEach(element => args.push(element)) + } + args.push(node.module) + if (node.args) { + node.args.forEach(element => args.push(element)) + } + const execOptions: cp.SpawnOptionsWithoutStdio = Object.create(null) + execOptions.cwd = serverWorkingDir + execOptions.env = getEnvironment(options.env, false) + const runtime = this._getRuntimePath(node.runtime, serverWorkingDir) + let pipeName: string | undefined + if (transport === TransportKind.ipc) { + // exec options not correctly typed in lib + execOptions.stdio = [null, null, null, 'ipc'] as any + args.push('--node-ipc') + } else if (transport === TransportKind.stdio) { + args.push('--stdio') + } else if (transport === TransportKind.pipe) { + pipeName = generateRandomPipeName() + args.push(`--pipe=${pipeName}`) + } else if (Transport.isSocket(transport)) { + args.push(`--socket=${transport.port}`) + } + args.push(`--clientProcessId=${process.pid.toString()}`) + if (transport === TransportKind.ipc || transport === TransportKind.stdio) { + let serverProcess = cp.spawn(runtime, args, execOptions) + if (!serverProcess || !serverProcess.pid) { + return Promise.reject(`Launching server using runtime ${runtime} failed.`) + } + this._serverProcess = serverProcess + serverProcess.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + if (transport === TransportKind.ipc) { + serverProcess.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + return Promise.resolve({ reader: new IPCMessageReader(serverProcess), writer: new IPCMessageWriter(serverProcess) }) + } else { + return Promise.resolve({ reader: new StreamMessageReader(serverProcess.stdout), writer: new StreamMessageWriter(serverProcess.stdin) }) + } + } else if (transport === TransportKind.pipe) { + return createClientPipeTransport(pipeName!).then(transport => { + let process = cp.spawn(runtime, args, execOptions) + if (!process || !process.pid) { + return Promise.reject(`Launching server using runtime ${runtime} failed.`) + } + this._serverProcess = process + process.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + process.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + return transport.onConnected().then(protocol => { + return { reader: protocol[0], writer: protocol[1] } + }) + }) + } else if (Transport.isSocket(transport)) { + return createClientSocketTransport(transport.port).then(transport => { + let process = cp.spawn(runtime, args, execOptions) + if (!process || !process.pid) { + return Promise.reject(`Launching server using runtime ${runtime} failed.`) + } + this._serverProcess = process + process.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + process.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + return transport.onConnected().then(protocol => { + return { reader: protocol[0], writer: protocol[1] } + }) + }) + } + } else { + let pipeName: string | undefined + return new Promise((resolve, _reject) => { + let args = node.args && node.args.slice() || [] + if (transport === TransportKind.ipc) { + args.push('--node-ipc') + } else if (transport === TransportKind.stdio) { + args.push('--stdio') + } else if (transport === TransportKind.pipe) { + pipeName = generateRandomPipeName() + args.push(`--pipe=${pipeName}`) + } else if (Transport.isSocket(transport)) { + args.push(`--socket=${transport.port}`) + } + args.push(`--clientProcessId=${process.pid.toString()}`) + let options: cp.ForkOptions = node.options || Object.create(null) + options.env = getEnvironment(options.env, true) + options.execArgv = options.execArgv || [] + options.cwd = serverWorkingDir + options.silent = true + if (transport === TransportKind.ipc || transport === TransportKind.stdio) { + let sp = cp.fork(node.module, args || [], options) + assertStdio(sp) + this._serverProcess = sp + sp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + if (transport === TransportKind.ipc) { + sp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + resolve({ reader: new IPCMessageReader(this._serverProcess), writer: new IPCMessageWriter(this._serverProcess) }) + } else { + resolve({ reader: new StreamMessageReader(sp.stdout), writer: new StreamMessageWriter(sp.stdin) }) + } + } else if (transport === TransportKind.pipe) { + void createClientPipeTransport(pipeName!).then(transport => { + let sp = cp.fork(node.module, args || [], options) + assertStdio(sp) + this._serverProcess = sp + sp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + sp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + void transport.onConnected().then(protocol => { + resolve({ reader: protocol[0], writer: protocol[1] }) + }) + }) + } else if (Transport.isSocket(transport)) { + void createClientSocketTransport(transport.port).then(transport => { + let sp = cp.fork(node.module, args || [], options) + assertStdio(sp) + this._serverProcess = sp + sp.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + sp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + void transport.onConnected().then(protocol => { + resolve({ reader: protocol[0], writer: protocol[1] }) + }) + }) + } + }) + } + } else if (Executable.is(json) && json.command) { + let command: Executable = json + let args = command.args || [] + let options = Object.assign({}, command.options) + options.env = options.env ? Object.assign({}, process.env, options.env) : process.env + options.cwd = options.cwd || serverWorkingDir + let cmd = workspace.expand(json.command) + let serverProcess = cp.spawn(cmd, args, options) + serverProcess.on('error', e => { + this.error(e.message) + logger.error(e) + }) + if (!serverProcess || !serverProcess.pid) { + return Promise.reject(`Launching server "${this.id}" using command ${command.command} failed.`) + } + logger.info(`Language server "${this.id}" started with ${serverProcess.pid}`) + serverProcess.on('exit', code => { + if (code != 0) this.error(`${command.command} exited with code: ${code}`) + }) + serverProcess.stderr.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding))) + this._serverProcess = serverProcess + this._isDetached = !!options.detached + return Promise.resolve({ reader: new StreamMessageReader(serverProcess.stdout), writer: new StreamMessageWriter(serverProcess.stdin) }) + } + return Promise.reject(`Unsupported server configuration ${JSON.stringify(server, null, 2)}`) + }) + + } + + private _getRuntimePath(runtime: string, serverWorkingDirectory: string | undefined): string { + if (path.isAbsolute(runtime)) { + return runtime + } + const mainRootPath = this._mainGetRootPath() + if (mainRootPath !== undefined) { + const result = path.join(mainRootPath, runtime) + if (fs.existsSync(result)) { + return result + } + } + if (serverWorkingDirectory !== undefined) { + const result = path.join(serverWorkingDirectory, runtime) + if (fs.existsSync(result)) { + return result + } + } + return runtime + } + + private _mainGetRootPath(): string | undefined { + let folders = workspace.workspaceFolders + if (!folders || folders.length === 0) { + return undefined + } + let folder = folders[0] + return folder.uri + } + + public registerProposedFeatures(): void { + this.registerFeatures(ProposedFeatures.createAll(this)) + } + + protected registerBuiltinFeatures(): void { + super.registerBuiltinFeatures() + let { disabledFeatures } = this.clientOptions + if (!disabledFeatures.includes('pullConfiguration')) { + this.registerFeature(new PullConfigurationFeature(this)) + } + if (!disabledFeatures.includes('typeDefinition')) { + this.registerFeature(new TypeDefinitionFeature(this)) + } + if (!disabledFeatures.includes('implementation')) { + this.registerFeature(new ImplementationFeature(this)) + } + if (!disabledFeatures.includes('declaration')) { + this.registerFeature(new DeclarationFeature(this)) + } + if (!disabledFeatures.includes('colorProvider')) { + this.registerFeature(new ColorProviderFeature(this)) + } + if (!disabledFeatures.includes('foldingRange')) { + this.registerFeature(new FoldingRangeFeature(this)) + } + if (!disabledFeatures.includes('selectionRange')) { + this.registerFeature(new SelectionRangeFeature(this)) + } + if (!disabledFeatures.includes('callHierarchy')) { + this.registerFeature(new CallHierarchyFeature(this)) + } + if (!disabledFeatures.includes('progress')) { + this.registerFeature(new ProgressFeature(this)) + } + if (!disabledFeatures.includes('linkedEditing')) { + this.registerFeature(new LinkedEditingFeature(this)) + } + if (!disabledFeatures.includes('fileEvents')) { + this.registerFeature(new DidCreateFilesFeature(this)) + this.registerFeature(new DidRenameFilesFeature(this)) + this.registerFeature(new DidDeleteFilesFeature(this)) + this.registerFeature(new WillCreateFilesFeature(this)) + this.registerFeature(new WillRenameFilesFeature(this)) + this.registerFeature(new WillDeleteFilesFeature(this)) + } + if (!disabledFeatures.includes('semanticTokens')) { + this.registerFeature(new SemanticTokensFeature(this)) + } + if (!disabledFeatures.includes('workspaceFolders')) { + this.registerFeature(new WorkspaceFoldersFeature(this)) + } + } + + private _getServerWorkingDir(options?: { cwd?: string }): Promise { + let cwd = options && options.cwd + if (cwd && !path.isAbsolute(cwd)) cwd = path.join(workspace.cwd, cwd) + if (!cwd) cwd = workspace.cwd + if (cwd) { + // make sure the folder exists otherwise creating the process will fail + return new Promise(s => { + fs.lstat(cwd, (err, stats) => { + s(!err && stats.isDirectory() ? cwd : undefined) + }) + }) + } + return Promise.resolve(undefined) + } + + private appendOutput(data: any, encoding: string): void { + let msg: string = Is.string(data) ? data : data.toString(encoding) + this.outputChannel.append(msg.endsWith('\n') ? msg : msg + '\n') + } +} + +export class SettingMonitor { + private _listeners: Disposable[] + + constructor(private _client: LanguageClient, private _setting: string) { + this._listeners = [] + } + + public start(): Disposable { + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(this._setting)) { + this.onDidChangeConfiguration() + } + }, null, this._listeners) + this.onDidChangeConfiguration() + return { + dispose: () => { + disposeAll(this._listeners) + if (this._client.needsStop()) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this._client.stop() + } + } + } + } + + private onDidChangeConfiguration(): void { + let index = this._setting.indexOf('.') + let primary = index >= 0 ? this._setting.substr(0, index) : this._setting + let rest = index >= 0 ? this._setting.substr(index + 1) : undefined + let enabled = rest + ? workspace.getConfiguration(primary).get(rest, true) + : workspace.getConfiguration(primary) + if (enabled && this._client.needsStart()) { + this._client.start() + } else if (!enabled && this._client.needsStop()) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this._client.stop() + } + } +} + +// Exporting proposed protocol. +export const ProposedFeatures = { + createAll: (_client: BaseLanguageClient): (StaticFeature | DynamicFeature)[] => { + let result: (StaticFeature | DynamicFeature)[] = [] + return result + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/linkedEditingRange.ts b/sources_non_forked/coc.nvim/src/language-client/linkedEditingRange.ts new file mode 100644 index 00000000..d7ed44d8 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/linkedEditingRange.ts @@ -0,0 +1,65 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. +* ------------------------------------------------------------------------------------------ */ + +import { CancellationToken, ClientCapabilities, Disposable, DocumentSelector, LinkedEditingRangeOptions, LinkedEditingRangeRegistrationOptions, LinkedEditingRangeRequest, LinkedEditingRanges, Position, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { LinkedEditingRangeProvider, ProviderResult } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' +import * as cv from './utils/converter' +const logger = require('../util/logger')('languageclient-linkedEditingRange') + +export interface ProvideLinkedEditingRangeSignature { + (this: void, document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +/** + * Linked editing middleware + * + * @since 3.16.0 + */ +export interface LinkedEditingRangeMiddleware { + provideLinkedEditingRange?: (this: void, document: TextDocument, position: Position, token: CancellationToken, next: ProvideLinkedEditingRangeSignature) => ProviderResult +} + +export class LinkedEditingFeature extends TextDocumentFeature { + + constructor(client: BaseLanguageClient) { + super(client, LinkedEditingRangeRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const linkedEditingSupport = ensure(ensure(capabilities, 'textDocument')!, 'linkedEditingRange')! + linkedEditingSupport.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + let [id, options] = this.getRegistration(documentSelector, capabilities.linkedEditingRangeProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: LinkedEditingRangeRegistrationOptions): [Disposable, LinkedEditingRangeProvider] { + const provider: LinkedEditingRangeProvider = { + provideLinkedEditingRanges: (document, position, token) => { + const client = this._client + const provideLinkedEditing: ProvideLinkedEditingRangeSignature = (document, position, token) => { + const params = cv.asTextDocumentPositionParams(document, position) + return client.sendRequest(LinkedEditingRangeRequest.type, params, token).then(result => result, error => { + return client.handleFailedRequest(LinkedEditingRangeRequest.type, token, error, null) + }) + } + const middleware = client.clientOptions.middleware! + return middleware.provideLinkedEditingRange + ? middleware.provideLinkedEditingRange(document, position, token, provideLinkedEditing) + : provideLinkedEditing(document, position, token) + } + } + return [languages.registerLinkedEditingRangeProvider(options.documentSelector!, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/progress.ts b/sources_non_forked/coc.nvim/src/language-client/progress.ts new file mode 100644 index 00000000..34b8dcce --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/progress.ts @@ -0,0 +1,39 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { ClientCapabilities, WorkDoneProgressCreateParams, WorkDoneProgressCreateRequest } from 'vscode-languageserver-protocol' +import { BaseLanguageClient, ensure, StaticFeature } from './client' +import { ProgressPart } from './progressPart' +// const logger = require('../util/logger')('language-client-progress') + +export class ProgressFeature implements StaticFeature { + private activeParts: Set = new Set() + constructor(private _client: BaseLanguageClient) { + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + ensure(capabilities, 'window')!.workDoneProgress = true + } + + public initialize(): void { + let client = this._client + const deleteHandler = (part: ProgressPart) => { + this.activeParts.delete(part) + } + const createHandler = (params: WorkDoneProgressCreateParams) => { + this.activeParts.add(new ProgressPart(this._client.id, this._client, params.token, deleteHandler)) + } + client.onRequest(WorkDoneProgressCreateRequest.type, createHandler) + } + + public dispose(): void { + for (const part of this.activeParts) { + part.done() + } + this.activeParts.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/progressPart.ts b/sources_non_forked/coc.nvim/src/language-client/progressPart.ts new file mode 100644 index 00000000..8ad9c7db --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/progressPart.ts @@ -0,0 +1,110 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +import { Disposable, NotificationHandler, ProgressToken, ProgressType, ProtocolNotificationType, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressReport } from 'vscode-languageserver-protocol' +import { disposeAll } from '../util' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('language-client-progressPart') + +export interface Progress { + report(value: { message?: string; increment?: number }): void +} + +export interface ProgressContext { + onProgress

    (type: ProgressType

    , token: string | number, handler: NotificationHandler

    ): Disposable + sendNotification(type: ProtocolNotificationType, params?: P): void +} + +export class ProgressPart { + private disposables: Disposable[] = [] + private _cancelled = false + private _percent = 0 + private _started = false + private progress: Progress + private _resolve: () => void + + public constructor(private id: string, client: ProgressContext, private token: ProgressToken, done?: (part: ProgressPart) => void) { + if (!workspace.env.dialog) return + this.disposables.push(client.onProgress(WorkDoneProgress.type, this.token, value => { + switch (value.kind) { + case 'begin': + this.begin(value) + break + case 'report': + this.report(value) + break + case 'end': + this.done(value.message) + done && done(this) + break + } + })) + } + + public begin(params: WorkDoneProgressBegin): void { + if (this._started) return + this._started = true + window.withProgress({ + source: `language-client-${this.id}`, + cancellable: params.cancellable, + title: params.title, + }, (progress, token) => { + this.progress = progress + this.report(params) + return new Promise(resolve => { + params.cancellable && token.onCancellationRequested(() => { + this.cancel() + resolve() + }) + this._resolve = resolve + }) + }).catch(e => { + void window.showErrorMessage(e.message) + }).finally(() => { + this._resolve = undefined + this.progress = undefined + }) + } + + private report(params: WorkDoneProgressReport | WorkDoneProgressBegin): void { + if (!this.progress) return + let msg: { message?: string, increment?: number } = {} + if (params.message) msg.message = params.message + if (validPercent(params.percentage)) { + msg.increment = params.percentage - this._percent + this._percent = params.percentage + } + if (Object.keys(msg).length > 0) { + this.progress.report(msg) + } + } + + public cancel(): void { + if (this._cancelled) return + this._cancelled = true + disposeAll(this.disposables) + } + + public done(message?: string): void { + if (this.progress) { + let msg: { message?: string, increment?: number } = {} + if (message) msg.message = message + if (this._percent > 0) msg.increment = 100 - this._percent + this.progress.report(msg) + } + setTimeout(() => { + if (this._resolve) { + this._resolve() + } + }, 300) + this.cancel() + } +} + +function validPercent(n: unknown): boolean { + if (typeof n !== 'number') return false + return n >= 0 && n <= 100 +} diff --git a/sources_non_forked/coc.nvim/src/language-client/selectionRange.ts b/sources_non_forked/coc.nvim/src/language-client/selectionRange.ts new file mode 100644 index 00000000..a4a2239c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/selectionRange.ts @@ -0,0 +1,64 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { CancellationToken, ClientCapabilities, Disposable, DocumentSelector, Position, SelectionRange, SelectionRangeClientCapabilities, SelectionRangeOptions, SelectionRangeParams, SelectionRangeRegistrationOptions, SelectionRangeRequest, ServerCapabilities } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { ProviderResult, SelectionRangeProvider } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' + +export interface ProvideSelectionRangeSignature { + (this: void, document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult +} + +export interface SelectionRangeProviderMiddleware { + provideSelectionRanges?: (this: void, document: TextDocument, positions: Position[], token: CancellationToken, next: ProvideSelectionRangeSignature) => ProviderResult +} + +export class SelectionRangeFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, SelectionRangeRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities & SelectionRangeClientCapabilities): void { + let capability = ensure(ensure(capabilities, 'textDocument')!, 'selectionRange')! + capability.dynamicRegistration = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + let [id, options] = this.getRegistration(documentSelector, capabilities.selectionRangeProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: SelectionRangeRegistrationOptions): [Disposable, SelectionRangeProvider] { + const provider: SelectionRangeProvider = { + provideSelectionRanges: (document, positions, token) => { + const client = this._client + const provideSelectionRanges: ProvideSelectionRangeSignature = (document, positions, token) => { + const requestParams: SelectionRangeParams = { + textDocument: { uri: document.uri }, + positions + } + return client.sendRequest(SelectionRangeRequest.type, requestParams, token).then( + ranges => ranges, + (error: any) => { + return client.handleFailedRequest(SelectionRangeRequest.type, token, error, null) + } + ) + } + const middleware = client.clientOptions.middleware + return middleware.provideSelectionRanges + ? middleware.provideSelectionRanges(document, positions, token, provideSelectionRanges) + : provideSelectionRanges(document, positions, token) + } + } + return [languages.registerSelectionRangeProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/semanticTokens.ts b/sources_non_forked/coc.nvim/src/language-client/semanticTokens.ts new file mode 100644 index 00000000..1bcd3228 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/semanticTokens.ts @@ -0,0 +1,196 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { + CancellationToken, ClientCapabilities, Disposable, DocumentSelector, Emitter, Range, SemanticTokenModifiers, SemanticTokens, SemanticTokensDelta, SemanticTokensDeltaParams, SemanticTokensDeltaRequest, SemanticTokensOptions, SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeRequest, SemanticTokensRefreshRequest, SemanticTokensRegistrationOptions, SemanticTokensRegistrationType, SemanticTokensRequest, SemanticTokenTypes, ServerCapabilities, TokenFormat +} from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, ProviderResult } from '../provider' +import * as Is from '../util/is' +import { BaseLanguageClient, ensure, Middleware, TextDocumentFeature } from './client' +import * as cv from './utils/converter' +const logger = require('../util/logger')('languageclient-semanticTokens') + +export interface DocumentSemanticsTokensSignature { + (this: void, document: TextDocument, token: CancellationToken): ProviderResult +} + +export interface DocumentSemanticsTokensEditsSignature { + (this: void, document: TextDocument, previousResultId: string, token: CancellationToken): ProviderResult +} + +export interface DocumentRangeSemanticTokensSignature { + (this: void, document: TextDocument, range: Range, token: CancellationToken): ProviderResult +} + +/** + * The semantic token middleware + * + * @since 3.16.0 + */ +export interface SemanticTokensMiddleware { + provideDocumentSemanticTokens?: (this: void, document: TextDocument, token: CancellationToken, next: DocumentSemanticsTokensSignature) => ProviderResult + provideDocumentSemanticTokensEdits?: (this: void, document: TextDocument, previousResultId: string, token: CancellationToken, next: DocumentSemanticsTokensEditsSignature) => ProviderResult + provideDocumentRangeSemanticTokens?: (this: void, document: TextDocument, range: Range, token: CancellationToken, next: DocumentRangeSemanticTokensSignature) => ProviderResult +} + +export interface SemanticTokensProviders { + range?: DocumentRangeSemanticTokensProvider + full?: DocumentSemanticTokensProvider + onDidChangeSemanticTokensEmitter: Emitter +} + +export class SemanticTokensFeature extends TextDocumentFeature { + + constructor(client: BaseLanguageClient) { + super(client, SemanticTokensRegistrationType.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const capability = ensure(ensure(capabilities, 'textDocument')!, 'semanticTokens')! + capability.dynamicRegistration = true + capability.tokenTypes = [ + SemanticTokenTypes.namespace, + SemanticTokenTypes.type, + SemanticTokenTypes.class, + SemanticTokenTypes.enum, + SemanticTokenTypes.interface, + SemanticTokenTypes.struct, + SemanticTokenTypes.typeParameter, + SemanticTokenTypes.parameter, + SemanticTokenTypes.variable, + SemanticTokenTypes.property, + SemanticTokenTypes.enumMember, + SemanticTokenTypes.event, + SemanticTokenTypes.function, + SemanticTokenTypes.method, + SemanticTokenTypes.macro, + SemanticTokenTypes.keyword, + SemanticTokenTypes.modifier, + SemanticTokenTypes.comment, + SemanticTokenTypes.string, + SemanticTokenTypes.number, + SemanticTokenTypes.regexp, + SemanticTokenTypes.operator + ] + capability.tokenModifiers = [ + SemanticTokenModifiers.declaration, + SemanticTokenModifiers.definition, + SemanticTokenModifiers.readonly, + SemanticTokenModifiers.static, + SemanticTokenModifiers.deprecated, + SemanticTokenModifiers.abstract, + SemanticTokenModifiers.async, + SemanticTokenModifiers.modification, + SemanticTokenModifiers.documentation, + SemanticTokenModifiers.defaultLibrary + ] + capability.formats = [TokenFormat.Relative] + capability.requests = { + range: true, + full: { + delta: true + } + } + capability.multilineTokenSupport = false + capability.overlappingTokenSupport = false + ensure(ensure(capabilities, 'workspace')!, 'semanticTokens')!.refreshSupport = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const client = this._client + client.onRequest(SemanticTokensRefreshRequest.type, async () => { + for (const provider of this.getAllProviders()) { + provider.onDidChangeSemanticTokensEmitter.fire() + } + }) + const [id, options] = this.getRegistration(documentSelector, capabilities.semanticTokensProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: SemanticTokensRegistrationOptions): [Disposable, SemanticTokensProviders] { + const fullProvider = Is.boolean(options.full) ? options.full : options.full !== undefined + const hasEditProvider = options.full !== undefined && typeof options.full !== 'boolean' && options.full.delta === true + const eventEmitter: Emitter = new Emitter() + const documentProvider: DocumentSemanticTokensProvider | undefined = fullProvider + ? { + onDidChangeSemanticTokens: eventEmitter.event, + provideDocumentSemanticTokens: (document, token) => { + const client = this._client + const middleware = client.clientOptions.middleware! as Middleware & SemanticTokensMiddleware + const provideDocumentSemanticTokens: DocumentSemanticsTokensSignature = (document, token) => { + const params: SemanticTokensParams = { + textDocument: cv.asTextDocumentIdentifier(document) + } + return client.sendRequest(SemanticTokensRequest.type, params, token).then(result => result, (error: any) => { + return client.handleFailedRequest(SemanticTokensRequest.type, token, error, null) + }) + } + return middleware.provideDocumentSemanticTokens + ? middleware.provideDocumentSemanticTokens(document, token, provideDocumentSemanticTokens) + : provideDocumentSemanticTokens(document, token) + }, + provideDocumentSemanticTokensEdits: hasEditProvider + ? (document, previousResultId, token) => { + const client = this._client + const middleware = client.clientOptions.middleware! as Middleware & SemanticTokensMiddleware + const provideDocumentSemanticTokensEdits: DocumentSemanticsTokensEditsSignature = (document, previousResultId, token) => { + const params: SemanticTokensDeltaParams = { + textDocument: cv.asTextDocumentIdentifier(document), + previousResultId + } + return client.sendRequest(SemanticTokensDeltaRequest.type, params, token).then(result => result, (error: any) => { + return client.handleFailedRequest(SemanticTokensDeltaRequest.type, token, error, null) + }) + } + return middleware.provideDocumentSemanticTokensEdits + ? middleware.provideDocumentSemanticTokensEdits(document, previousResultId, token, provideDocumentSemanticTokensEdits) + : provideDocumentSemanticTokensEdits(document, previousResultId, token) + } + : undefined + } + : undefined + + const hasRangeProvider: boolean = options.range === true + const rangeProvider: DocumentRangeSemanticTokensProvider | undefined = hasRangeProvider + ? { + provideDocumentRangeSemanticTokens: (document: TextDocument, range: Range, token: CancellationToken) => { + const client = this._client + const middleware = client.clientOptions.middleware! as Middleware & SemanticTokensMiddleware + const provideDocumentRangeSemanticTokens: DocumentRangeSemanticTokensSignature = (document, range, token) => { + const params: SemanticTokensRangeParams = { + textDocument: cv.asTextDocumentIdentifier(document), + range + } + return client.sendRequest(SemanticTokensRangeRequest.type, params, token).then( + result => result, + (error: any) => { + return client.handleFailedRequest(SemanticTokensRangeRequest.type, token, error, null) + }) + } + return middleware.provideDocumentRangeSemanticTokens + ? middleware.provideDocumentRangeSemanticTokens(document, range, token, provideDocumentRangeSemanticTokens) + : provideDocumentRangeSemanticTokens(document, range, token) + } + } + : undefined + + const disposables: Disposable[] = [] + if (documentProvider !== undefined) { + disposables.push(languages.registerDocumentSemanticTokensProvider(options.documentSelector!, documentProvider, options.legend)) + } + if (rangeProvider !== undefined) { + disposables.push(languages.registerDocumentRangeSemanticTokensProvider(options.documentSelector!, rangeProvider, options.legend)) + } + + return [Disposable.create(() => disposables.forEach(item => item.dispose())), { range: rangeProvider, full: documentProvider, onDidChangeSemanticTokensEmitter: eventEmitter }] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/typeDefinition.ts b/sources_non_forked/coc.nvim/src/language-client/typeDefinition.ts new file mode 100644 index 00000000..a21367f5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/typeDefinition.ts @@ -0,0 +1,68 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { CancellationToken, ClientCapabilities, Definition, DefinitionLink, Disposable, DocumentSelector, Position, ServerCapabilities, TypeDefinitionOptions, TypeDefinitionRegistrationOptions, TypeDefinitionRequest } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import languages from '../languages' +import { ProviderResult, TypeDefinitionProvider } from '../provider' +import { BaseLanguageClient, ensure, TextDocumentFeature } from './client' +import * as cv from './utils/converter' + +export interface ProvideTypeDefinitionSignature { + ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +export interface TypeDefinitionMiddleware { + provideTypeDefinition?: ( + this: void, + document: TextDocument, + position: Position, + token: CancellationToken, + next: ProvideTypeDefinitionSignature + ) => ProviderResult +} + +export class TypeDefinitionFeature extends TextDocumentFeature { + constructor(client: BaseLanguageClient) { + super(client, TypeDefinitionRequest.type) + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + const typeDefinitionSupport = ensure(ensure(capabilities, 'textDocument')!, 'typeDefinition')! + typeDefinitionSupport.dynamicRegistration = true + // typeDefinitionSupport.linkSupport = true + } + + public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { + const [id, options] = this.getRegistration(documentSelector, capabilities.typeDefinitionProvider) + if (!id || !options) { + return + } + this.register({ id, registerOptions: options }) + } + + protected registerLanguageProvider(options: TypeDefinitionRegistrationOptions): [Disposable, TypeDefinitionProvider] { + const provider: TypeDefinitionProvider = { + provideTypeDefinition: (document, position, token) => { + const client = this._client + const provideTypeDefinition: ProvideTypeDefinitionSignature = (document, position, token) => client.sendRequest(TypeDefinitionRequest.type, cv.asTextDocumentPositionParams(document, position), token).then( + res => res, error => { + return client.handleFailedRequest(TypeDefinitionRequest.type, token, error, null) + } + ) + const middleware = client.clientOptions.middleware + return middleware.provideTypeDefinition + ? middleware.provideTypeDefinition(document, position, token, provideTypeDefinition) + : provideTypeDefinition(document, position, token) + } + } + return [languages.registerTypeDefinitionProvider(options.documentSelector, provider), provider] + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/utils/async.ts b/sources_non_forked/coc.nvim/src/language-client/utils/async.ts new file mode 100644 index 00000000..eadc58be --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/utils/async.ts @@ -0,0 +1,88 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ + +import { RAL } from 'vscode-languageserver-protocol' + +export interface ITask { + (): T +} + +export class Delayer { + + public defaultDelay: number + private timeout: RAL.TimeoutHandle | undefined + private completionPromise: Promise | undefined + private onSuccess: ((value: T | Promise | undefined) => void) | undefined + private task: ITask | undefined + + constructor(defaultDelay: number) { + this.defaultDelay = defaultDelay + this.timeout = undefined + this.completionPromise = undefined + this.onSuccess = undefined + this.task = undefined + } + + public trigger(task: ITask, delay: number = this.defaultDelay): Promise { + this.task = task + if (delay >= 0) { + this.cancelTimeout() + } + + if (!this.completionPromise) { + this.completionPromise = new Promise(resolve => { + this.onSuccess = resolve + }).then(() => { + this.completionPromise = undefined + this.onSuccess = undefined + let result = this.task!() + this.task = undefined + return result + }) + } + + if (delay >= 0 || this.timeout === void 0) { + this.timeout = RAL().timer.setTimeout(() => { + this.timeout = undefined + this.onSuccess!(undefined) + }, delay >= 0 ? delay : this.defaultDelay) + } + + return this.completionPromise + } + + public forceDelivery(): T | undefined { + if (!this.completionPromise) { + return undefined + } + this.cancelTimeout() + let result: T = this.task!() + this.completionPromise = undefined + this.onSuccess = undefined + this.task = undefined + return result + } + + public isTriggered(): boolean { + return this.timeout !== void 0 + } + + public cancel(): void { + this.cancelTimeout() + this.completionPromise = undefined + } + + public dispose(): void { + this.cancelTimeout() + } + + private cancelTimeout(): void { + if (this.timeout !== void 0) { + RAL().timer.clearTimeout(this.timeout) + this.timeout = undefined + } + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/utils/converter.ts b/sources_non_forked/coc.nvim/src/language-client/utils/converter.ts new file mode 100644 index 00000000..67e55f1c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/utils/converter.ts @@ -0,0 +1,125 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { CodeLensParams, CompletionContext, CompletionParams, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidSaveTextDocumentParams, DocumentSymbolParams, Position, ReferenceParams, SignatureHelpContext, SignatureHelpParams, TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, VersionedTextDocumentIdentifier, WillSaveTextDocumentParams } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import { TextDocumentWillSaveEvent } from '../../types' +import { omit } from '../../util/lodash' + +export function convertToTextDocumentItem(document: TextDocument): TextDocumentItem { + return { + uri: document.uri, + languageId: document.languageId, + version: document.version, + text: document.getText() + } +} + +export function asCloseTextDocumentParams(document: TextDocument): DidCloseTextDocumentParams { + return { + textDocument: { + uri: document.uri + } + } +} + +export function asChangeTextDocumentParams(document: TextDocument): DidChangeTextDocumentParams { + let result: DidChangeTextDocumentParams = { + textDocument: { + uri: document.uri, + version: document.version + }, + contentChanges: [{ text: document.getText() }] + } + return result +} + +export function asWillSaveTextDocumentParams(event: TextDocumentWillSaveEvent): WillSaveTextDocumentParams { + return { + textDocument: asVersionedTextDocumentIdentifier(event.document), + reason: event.reason + } +} + +export function asVersionedTextDocumentIdentifier(textDocument: TextDocument): VersionedTextDocumentIdentifier { + return { + uri: textDocument.uri, + version: textDocument.version + } +} + +export function asSaveTextDocumentParams(document: TextDocument, includeText: boolean): DidSaveTextDocumentParams { + let result: DidSaveTextDocumentParams = { + textDocument: asVersionedTextDocumentIdentifier(document) + } + if (includeText) { + result.text = document.getText() + } + return result +} + +export function asUri(resource: URI): string { + return resource.toString() +} + +export function asCompletionParams(textDocument: TextDocument, position: Position, context: CompletionContext): CompletionParams { + return { + textDocument: { + uri: textDocument.uri, + }, + position, + context: omit(context, ['option']), + } +} + +export function asTextDocumentPositionParams(textDocument: TextDocument, position: Position): TextDocumentPositionParams { + return { + textDocument: { + uri: textDocument.uri, + }, + position + } +} + +export function asSignatureHelpParams(textDocument: TextDocument, position: Position, context: SignatureHelpContext): SignatureHelpParams { + return { + textDocument: asTextDocumentIdentifier(textDocument), + position, + context + } +} + +export function asTextDocumentIdentifier(textDocument: TextDocument): TextDocumentIdentifier { + return { + uri: textDocument.uri + } +} + +export function asReferenceParams(textDocument: TextDocument, position: Position, options: { includeDeclaration: boolean }): ReferenceParams { + return { + textDocument: { + uri: textDocument.uri, + }, + position, + context: { includeDeclaration: options.includeDeclaration } + } +} + +export function asDocumentSymbolParams(textDocument: TextDocument): DocumentSymbolParams { + return { + textDocument: { + uri: textDocument.uri + } + } +} + +export function asCodeLensParams(textDocument: TextDocument): CodeLensParams { + return { + textDocument: { + uri: textDocument.uri + } + } +} diff --git a/sources_non_forked/coc.nvim/src/language-client/utils/uuid.ts b/sources_non_forked/coc.nvim/src/language-client/utils/uuid.ts new file mode 100644 index 00000000..98530a9a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/utils/uuid.ts @@ -0,0 +1,6 @@ +'use strict' +import { v4 as uuidv4 } from 'uuid' + +export function generateUuid(): string { + return uuidv4() +} diff --git a/sources_non_forked/coc.nvim/src/language-client/workspaceFolders.ts b/sources_non_forked/coc.nvim/src/language-client/workspaceFolders.ts new file mode 100644 index 00000000..f3f80bbf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/language-client/workspaceFolders.ts @@ -0,0 +1,166 @@ +'use strict' +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict' + +import { CancellationToken, ClientCapabilities, DidChangeWorkspaceFoldersNotification, DidChangeWorkspaceFoldersParams, Disposable, InitializeParams, RegistrationType, ServerCapabilities, WorkspaceFolder, WorkspaceFoldersChangeEvent, WorkspaceFoldersRequest } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import { sameFile } from '../util/fs' +import workspace from '../workspace' +import { BaseLanguageClient, DynamicFeature, NextSignature, RegistrationData } from './client' +import * as UUID from './utils/uuid' +const logger = require('../util/logger')('language-client-workspaceFolder') + +function access(target: T | undefined, key: K): T[K] | undefined { + if (target === void 0) { + return undefined + } + return target[key] +} + +function arrayDiff(left: ReadonlyArray, right: ReadonlyArray): T[] { + return left.filter(element => !right.includes(element)) +} + +export interface WorkspaceFolderWorkspaceMiddleware { + workspaceFolders?: WorkspaceFoldersRequest.MiddlewareSignature + didChangeWorkspaceFolders?: NextSignature +} + +export class WorkspaceFoldersFeature implements DynamicFeature { + + private _listeners: Map = new Map() + private _initialFolders: ReadonlyArray | undefined + + constructor(private _client: BaseLanguageClient) { + } + + public get registrationType(): RegistrationType { + return DidChangeWorkspaceFoldersNotification.type + } + + private getValidWorkspaceFolders(): WorkspaceFolder[] | undefined { + let { workspaceFolders } = workspace + if (!workspaceFolders || workspaceFolders.length == 0) return undefined + let { ignoredRootPaths } = this._client.clientOptions + if (!Array.isArray(ignoredRootPaths)) ignoredRootPaths = [] + let arr = workspaceFolders.filter(o => { + let fsPath = URI.parse(o.uri).fsPath + return ignoredRootPaths.every(p => !sameFile(p, fsPath)) + }) + return arr.length ? arr : undefined + } + + private asProtocol(workspaceFolder: WorkspaceFolder): WorkspaceFolder + private asProtocol(workspaceFolder: undefined): null + private asProtocol(workspaceFolder: WorkspaceFolder | undefined): WorkspaceFolder | null { + if (workspaceFolder == null) return null + return { uri: workspaceFolder.uri, name: workspaceFolder.name } + } + + public fillInitializeParams(params: InitializeParams): void { + const folders = this.getValidWorkspaceFolders() + this._initialFolders = folders + if (folders == null) { + this._client.warn(`No valid workspaceFolder exists`) + params.workspaceFolders = null + } else { + params.workspaceFolders = folders.map(folder => this.asProtocol(folder)) + } + } + + public fillClientCapabilities(capabilities: ClientCapabilities): void { + capabilities.workspace = capabilities.workspace || {} + capabilities.workspace.workspaceFolders = true + } + + public initialize(capabilities: ServerCapabilities): void { + let client = this._client + client.onRequest(WorkspaceFoldersRequest.type, (token: CancellationToken) => { + let workspaceFolders: WorkspaceFoldersRequest.HandlerSignature = () => { + let folders = this.getValidWorkspaceFolders() + if (folders === void 0) { + return null + } + let result: WorkspaceFolder[] = folders.map(folder => this.asProtocol(folder)) + return result + } + const middleware = client.clientOptions.middleware.workspace + return middleware && middleware.workspaceFolders + ? middleware.workspaceFolders(token, workspaceFolders) + : workspaceFolders(token) + }) + const value = access(access(access(capabilities, 'workspace'), 'workspaceFolders'), 'changeNotifications') + let id: string | undefined + if (typeof value === 'string') { + id = value + } else if (value === true) { + id = UUID.generateUuid() + } + if (id) { + this.register({ + id, + registerOptions: undefined + }) + } + } + + private doSendEvent(addedFolders: ReadonlyArray, removedFolders: ReadonlyArray): void { + let params: DidChangeWorkspaceFoldersParams = { + event: { + added: addedFolders.map(folder => this.asProtocol(folder)), + removed: removedFolders.map(folder => this.asProtocol(folder)) + } + } + this._client.sendNotification(DidChangeWorkspaceFoldersNotification.type, params) + } + + protected sendInitialEvent(currentWorkspaceFolders: ReadonlyArray | undefined): void { + if (this._initialFolders && currentWorkspaceFolders) { + const removed: WorkspaceFolder[] = arrayDiff(this._initialFolders, currentWorkspaceFolders) + const added: WorkspaceFolder[] = arrayDiff(currentWorkspaceFolders, this._initialFolders) + if (added.length > 0 || removed.length > 0) { + this.doSendEvent(added, removed) + } + } else if (this._initialFolders) { + this.doSendEvent([], this._initialFolders) + } else if (currentWorkspaceFolders) { + this.doSendEvent(currentWorkspaceFolders, []) + } + } + + public register(data: RegistrationData): void { + let id = data.id + let client = this._client + let disposable = workspace.onDidChangeWorkspaceFolders(event => { + let didChangeWorkspaceFolders = (e: WorkspaceFoldersChangeEvent) => { + this.doSendEvent(e.added, e.removed) + } + let middleware = client.clientOptions.middleware.workspace + middleware && middleware.didChangeWorkspaceFolders + ? middleware.didChangeWorkspaceFolders(event, didChangeWorkspaceFolders) + : didChangeWorkspaceFolders(event) + }) + this._listeners.set(id, disposable) + let workspaceFolders = this.getValidWorkspaceFolders() + this.sendInitialEvent(workspaceFolders) + } + + public unregister(id: string): void { + let disposable = this._listeners.get(id) + if (disposable === void 0) { + return + } + this._listeners.delete(id) + disposable.dispose() + } + + public dispose(): void { + for (let disposable of this._listeners.values()) { + disposable.dispose() + } + this._listeners.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/languages.ts b/sources_non_forked/coc.nvim/src/languages.ts new file mode 100644 index 00000000..ea29a24e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/languages.ts @@ -0,0 +1,482 @@ +'use strict' +import { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CancellationToken, CodeAction, CodeActionContext, CodeActionKind, CodeLens, ColorInformation, ColorPresentation, DefinitionLink, Disposable, DocumentHighlight, DocumentLink, DocumentSelector, DocumentSymbol, Emitter, Event, FoldingRange, FormattingOptions, Hover, LinkedEditingRanges, Location, LocationLink, Position, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SemanticTokensLegend, SignatureHelp, SignatureHelpContext, SymbolInformation, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import DiagnosticCollection from './diagnostic/collection' +import diagnosticManager from './diagnostic/manager' +import { CallHierarchyProvider, CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentLinkProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, DocumentSymbolProviderMetadata, FoldingContext, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, LinkedEditingRangeProvider, OnTypeFormattingEditProvider, ReferenceContext, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, WorkspaceSymbolProvider } from './provider' +import CallHierarchyManager from './provider/callHierarchyManager' +import CodeActionManager from './provider/codeActionManager' +import CodeLensManager from './provider/codeLensManager' +import DeclarationManager from './provider/declarationManager' +import DefinitionManager from './provider/definitionManager' +import DocumentColorManager from './provider/documentColorManager' +import DocumentHighlightManager from './provider/documentHighlightManager' +import DocumentLinkManager from './provider/documentLinkManager' +import DocumentSymbolManager from './provider/documentSymbolManager' +import FoldingRangeManager from './provider/foldingRangeManager' +import FormatManager from './provider/formatManager' +import FormatRangeManager from './provider/formatRangeManager' +import HoverManager from './provider/hoverManager' +import ImplementationManager from './provider/implementationManager' +import LinkedEditingRangeManager from './provider/linkedEditingRangeManager' +import OnTypeFormatManager from './provider/onTypeFormatManager' +import ReferenceManager from './provider/referenceManager' +import RenameManager from './provider/renameManager' +import SelectionRangeManager from './provider/selectionRangeManager' +import SemanticTokensManager from './provider/semanticTokensManager' +import SemanticTokensRangeManager from './provider/semanticTokensRangeManager' +import SignatureManager from './provider/signatureManager' +import TypeDefinitionManager from './provider/typeDefinitionManager' +import WorkspaceSymbolManager from './provider/workspaceSymbolsManager' +import InlayHintManger, { InlayHintWithProvider } from './provider/inlayHintManager' +import { ExtendedCodeAction } from './types' +import { disposeAll } from './util' +const logger = require('./util/logger')('languages') + +class Languages { + private readonly _onDidSemanticTokensRefresh = new Emitter() + private readonly _onDidInlayHintRefresh = new Emitter() + public readonly onDidSemanticTokensRefresh: Event = this._onDidSemanticTokensRefresh.event + public readonly onDidInlayHintRefresh: Event = this._onDidInlayHintRefresh.event + private onTypeFormatManager = new OnTypeFormatManager() + private documentLinkManager = new DocumentLinkManager() + private documentColorManager = new DocumentColorManager() + private foldingRangeManager = new FoldingRangeManager() + private renameManager = new RenameManager() + private formatManager = new FormatManager() + private codeActionManager = new CodeActionManager() + private workspaceSymbolsManager = new WorkspaceSymbolManager() + private formatRangeManager = new FormatRangeManager() + private hoverManager = new HoverManager() + private signatureManager = new SignatureManager() + private documentSymbolManager = new DocumentSymbolManager() + private documentHighlightManager = new DocumentHighlightManager() + private definitionManager = new DefinitionManager() + private declarationManager = new DeclarationManager() + private typeDefinitionManager = new TypeDefinitionManager() + private referenceManager = new ReferenceManager() + private implementationManager = new ImplementationManager() + private codeLensManager = new CodeLensManager() + private selectionRangeManager = new SelectionRangeManager() + private callHierarchyManager = new CallHierarchyManager() + private semanticTokensManager = new SemanticTokensManager() + private semanticTokensRangeManager = new SemanticTokensRangeManager() + private linkedEditingManager = new LinkedEditingRangeManager() + private inlayHintManager = new InlayHintManger() + + public hasFormatProvider(doc: TextDocument): boolean { + if (this.formatManager.hasProvider(doc)) { + return true + } + if (this.formatRangeManager.hasProvider(doc)) { + return true + } + return false + } + + public registerOnTypeFormattingEditProvider( + selector: DocumentSelector, + provider: OnTypeFormattingEditProvider, + triggerCharacters: string[] + ): Disposable { + return this.onTypeFormatManager.register(selector, provider, triggerCharacters) + } + + public registerCompletionItemProvider( + name: string, + shortcut: string, + selector: DocumentSelector | null, + provider: CompletionItemProvider, + triggerCharacters: string[] = [], + priority?: number, + allCommitCharacters?: string[] + ): Disposable { + selector = typeof selector == 'string' ? [{ language: selector }] : selector + let sources = require('./sources/index').default + return sources.createLanguageSource(name, shortcut, selector, provider, triggerCharacters, priority, allCommitCharacters) + } + + public registerCodeActionProvider(selector: DocumentSelector, provider: CodeActionProvider, clientId: string | undefined, codeActionKinds?: CodeActionKind[]): Disposable { + return this.codeActionManager.register(selector, provider, clientId, codeActionKinds) + } + + public registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable { + return this.hoverManager.register(selector, provider) + } + + public registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable { + return this.selectionRangeManager.register(selector, provider) + } + + public registerSignatureHelpProvider( + selector: DocumentSelector, + provider: SignatureHelpProvider, + triggerCharacters?: string[]): Disposable { + return this.signatureManager.register(selector, provider, triggerCharacters) + } + + public registerDocumentSymbolProvider(selector: DocumentSelector, provider: DocumentSymbolProvider, metadata?: DocumentSymbolProviderMetadata): Disposable { + return this.documentSymbolManager.register(selector, provider, metadata) + } + + public registerFoldingRangeProvider(selector: DocumentSelector, provider: FoldingRangeProvider): Disposable { + return this.foldingRangeManager.register(selector, provider) + } + + public registerDocumentHighlightProvider(selector: DocumentSelector, provider: DocumentHighlightProvider): Disposable { + return this.documentHighlightManager.register(selector, provider) + } + + public registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable { + return this.codeLensManager.register(selector, provider) + } + + public registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable { + return this.documentLinkManager.register(selector, provider) + } + + public registerDocumentColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable { + return this.documentColorManager.register(selector, provider) + } + + public registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable { + return this.definitionManager.register(selector, provider) + } + + public registerDeclarationProvider(selector: DocumentSelector, provider: DeclarationProvider): Disposable { + return this.declarationManager.register(selector, provider) + } + + public registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable { + return this.typeDefinitionManager.register(selector, provider) + } + + public registerImplementationProvider(selector: DocumentSelector, provider: ImplementationProvider): Disposable { + return this.implementationManager.register(selector, provider) + } + + public registerReferencesProvider(selector: DocumentSelector, provider: ReferenceProvider): Disposable { + return this.referenceManager.register(selector, provider) + } + + public registerRenameProvider(selector: DocumentSelector, provider: RenameProvider): Disposable { + return this.renameManager.register(selector, provider) + } + + public registerWorkspaceSymbolProvider(provider: WorkspaceSymbolProvider): Disposable { + if (arguments.length > 1 && typeof arguments[1].provideWorkspaceSymbols === 'function') { + provider = arguments[1] + } + return this.workspaceSymbolsManager.register(provider) + } + + public registerDocumentFormatProvider(selector: DocumentSelector, provider: DocumentFormattingEditProvider, priority = 0): Disposable { + return this.formatManager.register(selector, provider, priority) + } + + public registerDocumentRangeFormatProvider(selector: DocumentSelector, provider: DocumentRangeFormattingEditProvider, priority = 0): Disposable { + return this.formatRangeManager.register(selector, provider, priority) + } + + public registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable { + return this.callHierarchyManager.register(selector, provider) + } + + public registerDocumentSemanticTokensProvider(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend): Disposable { + // Language server may send refresh short time after initialized. + let timer = setTimeout(() => { + this._onDidSemanticTokensRefresh.fire(selector) + }, 500) + let disposable = this.semanticTokensManager.register(selector, provider, legend, () => { + clearTimeout(timer) + this._onDidSemanticTokensRefresh.fire(selector) + }) + return Disposable.create(() => { + clearTimeout(timer) + disposable.dispose() + }) + } + + public registerDocumentRangeSemanticTokensProvider(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable { + this._onDidSemanticTokensRefresh.fire(selector) + return this.semanticTokensRangeManager.register(selector, provider, legend) + } + + public registerInlayHintsProvider(selector: DocumentSelector, provider: InlayHintsProvider): Disposable { + let disposables: Disposable[] = [] + disposables.push(this.inlayHintManager.register(selector, provider)) + this._onDidInlayHintRefresh.fire(selector) + if (typeof provider.onDidChangeInlayHints === 'function') { + provider.onDidChangeInlayHints(() => { + this._onDidInlayHintRefresh.fire(selector) + }, null, disposables) + } + return Disposable.create(() => { + disposeAll(disposables) + this._onDidInlayHintRefresh.fire(selector) + }) + } + + public registerLinkedEditingRangeProvider(selector: DocumentSelector, provider: LinkedEditingRangeProvider): Disposable { + return this.linkedEditingManager.register(selector, provider) + } + + public shouldTriggerSignatureHelp(document: TextDocument, triggerCharacter: string): boolean { + return this.signatureManager.shouldTrigger(document, triggerCharacter) + } + + public async getHover(document: TextDocument, position: Position, token: CancellationToken): Promise { + return await this.hoverManager.provideHover(document, position, token) + } + + public async getSignatureHelp(document: TextDocument, position: Position, token: CancellationToken, context: SignatureHelpContext): Promise { + return await this.signatureManager.provideSignatureHelp(document, position, token, context) + } + + public async getDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise { + if (!this.definitionManager.hasProvider(document)) return null + return await this.definitionManager.provideDefinition(document, position, token) + } + + public async getDefinitionLinks(document: TextDocument, position: Position, token: CancellationToken): Promise { + if (!this.definitionManager.hasProvider(document)) return null + return await this.definitionManager.provideDefinitionLinks(document, position, token) + } + + public async getDeclaration(document: TextDocument, position: Position, token: CancellationToken): Promise { + if (!this.declarationManager.hasProvider(document)) return null + return await this.declarationManager.provideDeclaration(document, position, token) + } + + public async getTypeDefinition(document: TextDocument, position: Position, token: CancellationToken): Promise { + if (!this.typeDefinitionManager.hasProvider(document)) return null + return await this.typeDefinitionManager.provideTypeDefinition(document, position, token) + } + + public async getImplementation(document: TextDocument, position: Position, token: CancellationToken): Promise { + if (!this.implementationManager.hasProvider(document)) return null + return await this.implementationManager.provideReferences(document, position, token) + } + + public async getReferences(document: TextDocument, context: ReferenceContext, position: Position, token: CancellationToken): Promise { + if (!this.referenceManager.hasProvider(document)) return null + return await this.referenceManager.provideReferences(document, position, context, token) + } + + public async getDocumentSymbol(document: TextDocument, token: CancellationToken): Promise { + return await this.documentSymbolManager.provideDocumentSymbols(document, token) + } + + public getDocumentSymbolMetadata(document: TextDocument): DocumentSymbolProviderMetadata { + return this.documentSymbolManager.getMetaData(document) + } + + public async getSelectionRanges(document: TextDocument, positions: Position[], token): Promise { + return await this.selectionRangeManager.provideSelectionRanges(document, positions, token) + } + + public async getWorkspaceSymbols(query: string, token: CancellationToken): Promise { + query = query || '' + return await this.workspaceSymbolsManager.provideWorkspaceSymbols(query, token) + } + + public async resolveWorkspaceSymbol(symbol: SymbolInformation, token: CancellationToken): Promise { + return await this.workspaceSymbolsManager.resolveWorkspaceSymbol(symbol, token) + } + + public async prepareRename(document: TextDocument, position: Position, token: CancellationToken): Promise { + return await this.renameManager.prepareRename(document, position, token) + } + + public async provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): Promise { + return await this.renameManager.provideRenameEdits(document, position, newName, token) + } + + public async provideDocumentFormattingEdits(document: TextDocument, options: FormattingOptions, token: CancellationToken): Promise { + if (!this.formatManager.hasProvider(document)) { + let hasRangeFormatter = this.formatRangeManager.hasProvider(document) + if (!hasRangeFormatter) return null + let end = document.positionAt(document.getText().length) + let range = Range.create(Position.create(0, 0), end) + return await this.provideDocumentRangeFormattingEdits(document, range, options, token) + } + return await this.formatManager.provideDocumentFormattingEdits(document, options, token) + } + + public async provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): Promise { + if (!this.formatRangeManager.hasProvider(document)) return null + return await this.formatRangeManager.provideDocumentRangeFormattingEdits(document, range, options, token) + } + + public async getCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Promise { + return await this.codeActionManager.provideCodeActions(document, range, context, token) + } + + public async getDocumentHighLight(document: TextDocument, position: Position, token: CancellationToken): Promise { + return await this.documentHighlightManager.provideDocumentHighlights(document, position, token) + } + + public async getDocumentLinks(document: TextDocument, token: CancellationToken): Promise { + if (!this.documentLinkManager.hasProvider(document)) { + return null + } + return (await this.documentLinkManager.provideDocumentLinks(document, token)) || [] + } + + public async resolveDocumentLink(link: DocumentLink, token: CancellationToken): Promise { + return await this.documentLinkManager.resolveDocumentLink(link, token) + } + + public async provideDocumentColors(document: TextDocument, token: CancellationToken): Promise { + return await this.documentColorManager.provideDocumentColors(document, token) + } + + public async provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): Promise { + if (!this.foldingRangeManager.hasProvider(document)) return null + return await this.foldingRangeManager.provideFoldingRanges(document, context, token) + } + + public async provideColorPresentations(color: ColorInformation, document: TextDocument, token: CancellationToken): Promise { + return await this.documentColorManager.provideColorPresentations(color, document, token) + } + + public async getCodeLens(document: TextDocument, token: CancellationToken): Promise<(CodeLens | null)[]> { + return await this.codeLensManager.provideCodeLenses(document, token) + } + + public async resolveCodeLens(codeLens: CodeLens, token: CancellationToken): Promise { + if (codeLens.command != null) return codeLens + return await this.codeLensManager.resolveCodeLens(codeLens, token) + } + + public async resolveCodeAction(codeAction: ExtendedCodeAction, token: CancellationToken): Promise { + return await this.codeActionManager.resolveCodeAction(codeAction, token) + } + + public async provideDocumentOnTypeEdits( + character: string, + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + return this.onTypeFormatManager.onCharacterType(character, document, position, token) + } + + public canFormatOnType(character: string, document: TextDocument): boolean { + return this.onTypeFormatManager.getProvider(document, character) != null + } + + public async prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): Promise { + return this.callHierarchyManager.prepareCallHierarchy(document, position, token) + } + + public async provideIncomingCalls(document: TextDocument, item: CallHierarchyItem, token: CancellationToken): Promise { + return this.callHierarchyManager.provideCallHierarchyIncomingCalls(document, item, token) + } + + public async provideOutgoingCalls(document: TextDocument, item: CallHierarchyItem, token: CancellationToken): Promise { + return this.callHierarchyManager.provideCallHierarchyOutgoingCalls(document, item, token) + } + + public getLegend(document: TextDocument, range?: boolean): SemanticTokensLegend | undefined { + if (range) return this.semanticTokensRangeManager.getLegend(document) + return this.semanticTokensManager.getLegend(document) + } + + public hasSemanticTokensEdits(document: TextDocument): boolean { + return this.semanticTokensManager.hasSemanticTokensEdits(document) + } + + public async provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): Promise { + return this.semanticTokensManager.provideDocumentSemanticTokens(document, token) + } + + public async provideDocumentSemanticTokensEdits(document: TextDocument, previousResultId: string, token: CancellationToken): Promise { + return this.semanticTokensManager.provideDocumentSemanticTokensEdits(document, previousResultId, token) + } + + public async provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): Promise { + return this.semanticTokensRangeManager.provideDocumentRangeSemanticTokens(document, range, token) + } + + public async provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): Promise { + return this.inlayHintManager.provideInlayHints(document, range, token) + } + + public async resolveInlayHint(hint: InlayHintWithProvider, token: CancellationToken): Promise { + return this.inlayHintManager.resolveInlayHint(hint, token) + } + + public hasLinkedEditing(document: TextDocument): boolean { + return this.linkedEditingManager.hasProvider(document) + } + + public async provideLinkedEdits(document: TextDocument, position: Position, token: CancellationToken): Promise { + return this.linkedEditingManager.provideLinkedEditingRanges(document, position, token) + } + + public createDiagnosticCollection(owner: string): DiagnosticCollection { + return diagnosticManager.create(owner) + } + + public hasProvider(id: string, document: TextDocument): boolean { + switch (id) { + case 'formatOnType': + return this.onTypeFormatManager.hasProvider(document) + case 'rename': + return this.renameManager.hasProvider(document) + case 'onTypeEdit': + return this.onTypeFormatManager.hasProvider(document) + case 'documentLink': + return this.documentLinkManager.hasProvider(document) + case 'documentColor': + return this.documentColorManager.hasProvider(document) + case 'foldingRange': + return this.foldingRangeManager.hasProvider(document) + case 'format': + return this.formatManager.hasProvider(document) || this.formatRangeManager.hasProvider(document) + case 'codeAction': + return this.codeActionManager.hasProvider(document) + case 'workspaceSymbols': + return this.workspaceSymbolsManager.hasProvider() + case 'formatRange': + return this.formatRangeManager.hasProvider(document) + case 'hover': + return this.hoverManager.hasProvider(document) + case 'signature': + return this.signatureManager.hasProvider(document) + case 'documentSymbol': + return this.documentSymbolManager.hasProvider(document) + case 'documentHighlight': + return this.documentHighlightManager.hasProvider(document) + case 'definition': + return this.definitionManager.hasProvider(document) + case 'declaration': + return this.declarationManager.hasProvider(document) + case 'typeDefinition': + return this.typeDefinitionManager.hasProvider(document) + case 'reference': + return this.referenceManager.hasProvider(document) + case 'implementation': + return this.implementationManager.hasProvider(document) + case 'codeLens': + return this.codeLensManager.hasProvider(document) + case 'selectionRange': + return this.selectionRangeManager.hasProvider(document) + case 'callHierarchy': + return this.callHierarchyManager.hasProvider(document) + case 'semanticTokens': + return this.semanticTokensManager.hasProvider(document) + case 'semanticTokensRange': + return this.semanticTokensRangeManager.hasProvider(document) + case 'linkedEditing': + return this.linkedEditingManager.hasProvider(document) + case 'inlayHint': + return this.inlayHintManager.hasProvider(document) + default: + throw new Error(`Invalid provider name: ${id}`) + } + } +} + +export default new Languages() diff --git a/sources_non_forked/coc.nvim/src/list/basic.ts b/sources_non_forked/coc.nvim/src/list/basic.ts new file mode 100644 index 00000000..4966a244 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/basic.ts @@ -0,0 +1,323 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import path from 'path' +import readline from 'readline' +import { CancellationToken, Disposable, Location, Position, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import { ProviderResult } from '../provider' +import { IList, ListAction, ListArgument, ListContext, ListItem, ListTask, LocationWithLine, WorkspaceConfiguration } from '../types' +import { disposeAll } from '../util' +import { readFile } from '../util/fs' +import { comparePosition, emptyRange } from '../util/position' +import workspace from '../workspace' +import CommandTask, { CommandTaskOption } from './commandTask' +import ListConfiguration from './configuration' +const logger = require('../util/logger')('list-basic') + +interface ActionOptions { + persist?: boolean + reload?: boolean + parallel?: boolean + tabPersist?: boolean +} + +interface ArgumentItem { + hasValue: boolean + name: string +} + +interface PreviewConfig { + winid: number + position: string + hlGroup: string + maxHeight: number + name?: string + splitRight: boolean + lnum: number + filetype?: string + range?: Range + scheme?: string + toplineStyle: string + toplineOffset: number +} + +export interface PreviewOptions { + bufname?: string + filetype: string + lines: string[] + lnum?: number + range?: Range + sketch?: boolean +} + +export default abstract class BasicList implements IList, Disposable { + public name: string + public defaultAction = 'open' + public readonly actions: ListAction[] = [] + public options: ListArgument[] = [] + protected disposables: Disposable[] = [] + private optionMap: Map + public config: ListConfiguration + + constructor(protected nvim: Neovim) { + this.config = new ListConfiguration() + } + + public get alignColumns(): boolean { + return this.config.get('alignColumns', false) + } + + protected get hlGroup(): string { + return this.config.get('previewHighlightGroup', 'Search') + } + + protected get previewHeight(): number { + return this.config.get('maxPreviewHeight', 12) + } + + protected get splitRight(): boolean { + return this.config.get('previewSplitRight', false) + } + + protected get toplineStyle(): string { + return this.config.get('previewToplineStyle', 'offset') + } + + protected get toplineOffset(): number { + return this.config.get('previewToplineOffset', 3) + } + + public parseArguments(args: string[]): { [key: string]: string | boolean } { + if (!this.optionMap) { + this.optionMap = new Map() + for (let opt of this.options) { + let parts = opt.name.split(/,\s*/g).map(s => s.replace(/\s+.*/g, '')) + let name = opt.key ? opt.key : parts[parts.length - 1].replace(/^-/, '') + for (let p of parts) { + this.optionMap.set(p, { name, hasValue: opt.hasValue }) + } + } + } + let res: { [key: string]: string | boolean } = {} + for (let i = 0; i < args.length; i++) { + let arg = args[i] + let def = this.optionMap.get(arg) + if (!def) continue + let value: string | boolean = true + if (def.hasValue) { + value = args[i + 1] || '' + i = i + 1 + } + res[def.name] = value + } + return res + } + + /** + * Get configuration of current list + */ + protected getConfig(): WorkspaceConfiguration { + return workspace.getConfiguration(`list.source.${this.name}`) + } + + protected addAction(name: string, fn: (item: ListItem, context: ListContext) => ProviderResult, options?: ActionOptions): void { + this.createAction(Object.assign({ + name, + execute: fn + }, options || {})) + } + + protected addMultipleAction(name: string, fn: (item: ListItem[], context: ListContext) => ProviderResult, options?: ActionOptions): void { + this.createAction(Object.assign({ + name, + multiple: true, + execute: fn + }, options || {})) + } + + protected createCommandTask(opt: CommandTaskOption): CommandTask { + return new CommandTask(opt) + } + + public addLocationActions(): void { + this.createAction({ + name: 'preview', + execute: async (item: ListItem, context: ListContext) => { + let loc = await this.convertLocation(item.location) + await this.previewLocation(loc, context) + } + }) + let { nvim } = this + this.createAction({ + name: 'quickfix', + multiple: true, + execute: async (items: ListItem[]) => { + let quickfixItems = await Promise.all(items.map(item => this.convertLocation(item.location).then(loc => workspace.getQuickfixItem(loc)))) + await nvim.call('setqflist', [quickfixItems]) + let openCommand = await nvim.getVar('coc_quickfix_open_command') as string + nvim.command(typeof openCommand === 'string' ? openCommand : 'copen', true) + } + }) + for (let name of ['open', 'tabe', 'drop', 'vsplit', 'split']) { + this.createAction({ + name, + execute: async (item: ListItem, context: ListContext) => { + await this.jumpTo(item.location, name == 'open' ? null : name, context) + }, + tabPersist: name === 'open' + }) + } + } + + public async convertLocation(location: Location | LocationWithLine | string): Promise { + if (typeof location == 'string') return Location.create(location, Range.create(0, 0, 0, 0)) + if (Location.is(location)) return location + let u = URI.parse(location.uri) + if (u.scheme != 'file') return Location.create(location.uri, Range.create(0, 0, 0, 0)) + const rl = readline.createInterface({ + input: fs.createReadStream(u.fsPath, { encoding: 'utf8' }), + }) + let match = location.line + let n = 0 + let resolved = false + let line = await new Promise(resolve => { + rl.on('line', line => { + if (resolved) return + if (line.includes(match)) { + rl.removeAllListeners() + rl.close() + resolved = true + resolve(line) + return + } + n = n + 1 + }) + rl.on('error', e => { + this.nvim.errWriteLine(`Read ${u.fsPath} error: ${e.message}`) + resolve(null) + }) + }) + if (line != null) { + let character = location.text ? line.indexOf(location.text) : 0 + if (character == 0) character = line.match(/^\s*/)[0].length + let end = Position.create(n, character + (location.text ? location.text.length : 0)) + return Location.create(location.uri, Range.create(Position.create(n, character), end)) + } + return Location.create(location.uri, Range.create(0, 0, 0, 0)) + } + + public async jumpTo(location: Location | LocationWithLine | string, command?: string, context?: ListContext): Promise { + if (command == null && context && context.options.position === 'tab') { + command = 'tabe' + } + if (typeof location == 'string') { + await workspace.jumpTo(location, null, command) + return + } + let { range, uri } = await this.convertLocation(location) + let position = range.start + if (position.line == 0 && position.character == 0 && comparePosition(position, range.end) == 0) { + // allow plugin that remember position. + position = null + } + await workspace.jumpTo(uri, position, command) + } + + public createAction(action: ListAction): void { + let { name } = action + let idx = this.actions.findIndex(o => o.name == name) + // allow override + if (idx !== -1) this.actions.splice(idx, 1) + this.actions.push(action) + } + + protected async previewLocation(location: Location, context: ListContext): Promise { + if (!context.listWindow) return + let { nvim } = this + let { uri, range } = location + let doc = workspace.getDocument(location.uri) + let u = URI.parse(uri) + let lines: string[] = [] + if (doc) { + lines = doc.getLines() + } else if (u.scheme == 'file') { + try { + let content = await readFile(u.fsPath, 'utf8') + lines = content.split(/\r?\n/) + } catch (e) { + [`Error on read file ${u.fsPath}`, e.toString()] + } + } + let config: PreviewConfig = { + winid: context.window.id, + range: emptyRange(range) ? null : range, + lnum: range.start.line + 1, + name: u.scheme == 'file' ? u.fsPath : uri, + filetype: toVimFiletype(doc ? doc.languageId : this.getLanguageId(u.fsPath)), + position: context.options.position, + maxHeight: this.previewHeight, + splitRight: this.splitRight, + hlGroup: this.hlGroup, + scheme: u.scheme, + toplineStyle: this.toplineStyle, + toplineOffset: this.toplineOffset, + } + await nvim.call('coc#list#preview', [lines, config]) + } + + public async preview(options: PreviewOptions, context: ListContext): Promise { + let { nvim } = this + let { bufname, filetype, range, lines, lnum } = options + let config: PreviewConfig = { + winid: context.window.id, + lnum: range ? range.start.line + 1 : lnum || 1, + filetype: filetype || 'txt', + position: context.options.position, + maxHeight: this.previewHeight, + splitRight: this.splitRight, + hlGroup: this.hlGroup, + toplineStyle: this.toplineStyle, + toplineOffset: this.toplineOffset, + } + if (bufname) config.name = bufname + if (range) config.range = range + await nvim.call('coc#list#preview', [lines, config]) + nvim.command('redraw', true) + } + + public abstract loadItems(context: ListContext, token?: CancellationToken): Promise + + public doHighlight(): void { + // noop + } + + public dispose(): void { + disposeAll(this.disposables) + } + + /** + * Get filetype by check same extension name buffer. + */ + private getLanguageId(filepath: string): string { + let extname = path.extname(filepath) + if (!extname) return '' + for (let doc of workspace.documents) { + let fsPath = URI.parse(doc.uri).fsPath + if (path.extname(fsPath) == extname) { + return doc.languageId + } + } + return '' + } +} + +export function toVimFiletype(filetype: string): string { + switch (filetype) { + case 'latex': + // LaTeX (LSP language ID 'latex') has Vim filetype 'tex' + return 'tex' + default: + return filetype + } +} diff --git a/sources_non_forked/coc.nvim/src/list/commandTask.ts b/sources_non_forked/coc.nvim/src/list/commandTask.ts new file mode 100644 index 00000000..e0e694d0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/commandTask.ts @@ -0,0 +1,62 @@ +'use strict' +import { spawn } from 'child_process' +import { EventEmitter } from 'events' +import readline from 'readline' +import { Disposable } from 'vscode-languageserver-protocol' +import { ListItem, ListTask } from '../types' +import { disposeAll } from '../util' +import workspace from '../workspace' +const logger = require('../util/logger')('list-commandTask') + +export interface CommandTaskOption { + /** + * Command to run. + */ + cmd: string + /** + * Arguments of command. + */ + args: string[] + cwd?: string + env?: NodeJS.ProcessEnv + /** + * Runs for each line, return undefined for invalid item. + */ + onLine: (line: string) => ListItem | undefined +} + +export default class CommandTask extends EventEmitter implements ListTask { + private disposables: Disposable[] = [] + constructor(private opt: CommandTaskOption) { + super() + this.start() + } + + private start(): void { + let { cmd, args, cwd, onLine } = this.opt + let proc = spawn(cmd, args, { cwd: cwd || workspace.cwd, windowsHide: true }) + this.disposables.push({ + dispose: () => { + proc.kill() + } + }) + proc.on('error', e => { + this.emit('error', e.message) + }) + proc.stderr.on('data', chunk => { + logger.error(`[${cmd} Error]`, chunk.toString('utf8')) + }) + const rl = readline.createInterface(proc.stdout) + rl.on('line', line => { + let res = onLine(line) + if (res) this.emit('data', res) + }) + rl.on('close', () => { + this.emit('end') + }) + } + + public dispose(): void { + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/configuration.ts b/sources_non_forked/coc.nvim/src/list/configuration.ts new file mode 100644 index 00000000..022ff3f1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/configuration.ts @@ -0,0 +1,121 @@ +'use strict' +import workspace from '../workspace' +import window from '../window' +import { WorkspaceConfiguration } from '../types' +import { EventEmitter } from 'events' +import { Disposable } from 'vscode-languageserver-protocol' + +export const validKeys = [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '<2-LeftMouse>', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', +] + +export default class ListConfiguration extends EventEmitter { + private configuration: WorkspaceConfiguration + private disposable: Disposable + constructor() { + super() + this.configuration = workspace.getConfiguration('list') + this.disposable = workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('list')) { + this.configuration = workspace.getConfiguration('list') + this.emit('change') + } + }) + } + + public get(key: string, defaultValue?: T): T { + return this.configuration.get(key, defaultValue) + } + + public get previousKey(): string { + return this.fixKey(this.configuration.get('previousKeymap', '')) + } + + public get nextKey(): string { + return this.fixKey(this.configuration.get('nextKeymap', '')) + } + + public dispose(): void { + this.disposable.dispose() + this.removeAllListeners() + } + + public fixKey(key: string): string { + if (validKeys.includes(key)) return key + let find = validKeys.find(s => s.toLowerCase() == key.toLowerCase()) + if (find) return find + window.showMessage(`Configured key "${key}" not supported.`, 'error') + return null + } +} diff --git a/sources_non_forked/coc.nvim/src/list/formatting.ts b/sources_non_forked/coc.nvim/src/list/formatting.ts new file mode 100644 index 00000000..918fe0b4 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/formatting.ts @@ -0,0 +1,56 @@ +'use strict' +import { ListItem } from '../types' +import path from 'path' + +export type PathFormatting = "full" | "short" | "filename" | "hidden" + +export interface UnformattedListItem extends Omit { + label: string[] +} + +export function formatListItems(align: boolean, list: UnformattedListItem[]): ListItem[] { + if (list.length === 0) { + return [] + } + + let processedList: ListItem[] = [] + if (align) { + const maxWidths = Array(Math.min(...list.map(item => item.label.length))).fill(0) + for (let item of list) { + for (let i = 0; i < maxWidths.length; i++) { + maxWidths[i] = Math.max(maxWidths[i], item.label[i].length) + } + } + processedList = list + .map(item => ({ + ...item, + label: item.label + .map((element, idx) => element.padEnd(maxWidths[idx])) + .join("\t") + })) + } else { + processedList = list.map(item => ({ ...item, label: item.label.join("\t") })) + } + return processedList +} + +export function formatPath(format: PathFormatting, pathToFormat: string): string { + if (format === "hidden") { + return "" + } else if (format === "full") { + return pathToFormat + } else if (format === "short") { + const segments = pathToFormat.split(path.sep) + if (segments.length < 2) { + return pathToFormat + } + const shortenedInit = segments + .slice(0, segments.length - 2) + .filter(seg => seg.length > 0) + .map(seg => seg[0]) + return [...shortenedInit, segments[segments.length - 1]].join(path.sep) + } else { + const segments = pathToFormat.split(path.sep) + return segments[segments.length - 1] ?? "" + } +} diff --git a/sources_non_forked/coc.nvim/src/list/history.ts b/sources_non_forked/coc.nvim/src/list/history.ts new file mode 100644 index 00000000..8986aef7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/history.ts @@ -0,0 +1,84 @@ +'use strict' +import DB from '../model/db' +import { fuzzyMatch, getCharCodes } from '../util/fuzzy' +import workspace from '../workspace' +import Prompt from './prompt' +const logger = require('../util/logger')('list-history') + +export default class InputHistory { + private db: DB + private index = -1 + private loaded: string[] = [] + private current: string[] = [] + private historyInput: string + private key: string + + constructor( + private prompt: Prompt, + private name: string + ) { + this.db = workspace.createDatabase(`list-${name}-history`) + this.key = Buffer.from(workspace.cwd).toString('base64') + } + + public filter(): void { + let { input } = this.prompt + if (input == this.curr) return + this.historyInput = '' + let codes = getCharCodes(input) + this.current = this.loaded.filter(s => fuzzyMatch(codes, s)) + this.index = -1 + } + + public get curr(): string | null { + return this.index == -1 ? null : this.current[this.index] + } + + public load(input: string): void { + let { db } = this + input = input || '' + let arr = db.fetch(this.key) + if (!arr || !Array.isArray(arr)) { + this.loaded = [] + } else { + this.loaded = arr + } + this.index = -1 + this.current = this.loaded.filter(s => s.startsWith(input)) + } + + public add(): void { + let { loaded, db, prompt } = this + let { input } = prompt + if (!input || input.length < 2 || input == this.historyInput) return + let idx = loaded.indexOf(input) + if (idx != -1) loaded.splice(idx, 1) + loaded.push(input) + if (loaded.length > 200) { + loaded = loaded.slice(-200) + } + db.push(this.key, loaded) + } + + public previous(): void { + let { current, index } = this + if (!current || !current.length) return + if (index <= 0) { + this.index = current.length - 1 + } else { + this.index = index - 1 + } + this.historyInput = this.prompt.input = current[this.index] || '' + } + + public next(): void { + let { current, index } = this + if (!current || !current.length) return + if (index == current.length - 1) { + this.index = 0 + } else { + this.index = index + 1 + } + this.historyInput = this.prompt.input = current[this.index] || '' + } +} diff --git a/sources_non_forked/coc.nvim/src/list/manager.ts b/sources_non_forked/coc.nvim/src/list/manager.ts new file mode 100644 index 00000000..b5b9c0cf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/manager.ts @@ -0,0 +1,523 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationTokenSource, Disposable } from 'vscode-languageserver-protocol' +import events from '../events' +import extensions from '../extensions' +import { IList, ListItem, ListOptions, ListTask, Matcher } from '../types' +import { disposeAll } from '../util' +import workspace from '../workspace' +import window from '../window' +import ListConfiguration from './configuration' +import Mappings from './mappings' +import Prompt from './prompt' +import ListSession from './session' +import CommandsList from './source/commands' +import DiagnosticsList from './source/diagnostics' +import ExtensionList from './source/extensions' +import FolderList from './source/folders' +import LinksList from './source/links' +import ListsList from './source/lists' +import LocationList from './source/location' +import OutlineList from './source/outline' +import ServicesList from './source/services' +import SourcesList from './source/sources' +import SymbolsList from './source/symbols' +import stripAnsi from 'strip-ansi' +const logger = require('../util/logger')('list-manager') + +const mouseKeys = ['', '', '', '<2-LeftMouse>'] + +export class ListManager implements Disposable { + public prompt: Prompt + public config: ListConfiguration + public mappings: Mappings + private nvim: Neovim + private plugTs = 0 + private sessionsMap: Map = new Map() + private lastSession: ListSession | undefined + private disposables: Disposable[] = [] + private listMap: Map = new Map() + + public init(nvim: Neovim): void { + this.nvim = nvim + this.config = new ListConfiguration() + this.prompt = new Prompt(nvim, this.config) + this.mappings = new Mappings(this, nvim, this.config) + let signText = this.config.get('selectedSignText', '*') + nvim.command(`sign define CocSelected text=${signText} texthl=CocSelectedText linehl=CocSelectedLine`, true) + events.on('InputChar', this.onInputChar, this, this.disposables) + let debounced = debounce(async () => { + let session = await this.getCurrentSession() + if (session) this.prompt.drawPrompt() + }, 100) + events.on('FocusGained', debounced, null, this.disposables) + events.on('WinEnter', winid => { + let session = this.getSessionByWinid(winid) + if (session) this.prompt.start(session.listOptions) + }, null, this.disposables) + let timer: NodeJS.Timer + events.on('WinLeave', winid => { + if (timer) clearTimeout(timer) + let session = this.getSessionByWinid(winid) + if (session) { + setTimeout(() => { + this.prompt.cancel() + }, workspace.isVim ? 50 : 0) + } + }, null, this.disposables) + this.disposables.push({ + dispose: () => { + debounced.clear() + } + }) + // filter history on input + this.prompt.onDidChangeInput(() => { + let { session } = this + if (!session) return + session.onInputChange() + session.history.filter() + }) + this.registerList(new LinksList(nvim)) + this.registerList(new LocationList(nvim)) + this.registerList(new SymbolsList(nvim)) + this.registerList(new OutlineList(nvim)) + this.registerList(new CommandsList(nvim)) + this.registerList(new ExtensionList(nvim)) + this.registerList(new DiagnosticsList(nvim, this)) + this.registerList(new SourcesList(nvim)) + this.registerList(new ServicesList(nvim)) + this.registerList(new ListsList(nvim, this.listMap)) + this.registerList(new FolderList(nvim)) + } + + public async start(args: string[]): Promise { + let res = this.parseArgs(args) + if (!res) return + let { name } = res.list + let curr = this.sessionsMap.get(name) + if (curr) curr.dispose() + this.prompt.start(res.options) + let session = new ListSession(this.nvim, this.prompt, res.list, res.options, res.listArgs, this.config) + this.sessionsMap.set(name, session) + this.lastSession = session + try { + await session.start(args) + } catch (e) { + this.nvim.call('coc#prompt#stop_prompt', ['list'], true) + let msg = e instanceof Error ? e.message : e.toString() + window.showMessage(`Error on "CocList ${name}": ${msg}`, 'error') + logger.error(e) + } + } + + private getSessionByWinid(winid: number): ListSession | null { + for (let session of this.sessionsMap.values()) { + if (session && session.winid == winid) { + this.lastSession = session + return session + } + } + return null + } + + private async getCurrentSession(): Promise { + let { id } = await this.nvim.window + for (let session of this.sessionsMap.values()) { + if (session && session.winid == id) { + this.lastSession = session + return session + } + } + return null + } + + public async resume(name?: string): Promise { + if (!name) { + await this.session?.resume() + } else { + let session = this.sessionsMap.get(name) + if (!session) { + window.showMessage(`Can't find exists ${name} list`) + return + } + await session.resume() + } + } + + public async doAction(name?: string): Promise { + let lastSession = this.lastSession + if (!lastSession) return + await lastSession.doAction(name) + } + + public async first(name?: string): Promise { + let s = this.getSession(name) + if (s) await s.first() + } + + public async last(name?: string): Promise { + let s = this.getSession(name) + if (s) await s.last() + } + + public async previous(name?: string): Promise { + let s = this.getSession(name) + if (s) await s.previous() + } + + public async next(name?: string): Promise { + let s = this.getSession(name) + if (s) await s.next() + } + + public getSession(name?: string): ListSession { + if (!name) return this.session + return this.sessionsMap.get(name) + } + + public async cancel(close = true): Promise { + this.prompt.cancel() + if (!close) return + if (this.session) await this.session.hide() + } + + /** + * Clear all list sessions + */ + public reset(): void { + this.prompt.cancel() + this.lastSession = undefined + for (let session of this.sessionsMap.values()) { + session.dispose() + } + this.sessionsMap.clear() + this.nvim.call('coc#prompt#stop_prompt', ['list'], true) + } + + public async switchMatcher(): Promise { + await this.session?.switchMatcher() + } + + public async togglePreview(): Promise { + let { nvim } = this + let winid = await nvim.call('coc#list#get_preview', [0]) + if (winid != -1) { + await nvim.call('coc#window#close', [winid]) + await nvim.command('redraw') + } else { + await this.doAction('preview') + } + } + + public async chooseAction(): Promise { + let { lastSession } = this + if (lastSession) await lastSession.chooseAction() + } + + public parseArgs(args: string[]): { list: IList; options: ListOptions; listArgs: string[] } | null { + let options: string[] = [] + let interactive = false + let autoPreview = false + let numberSelect = false + let noQuit = false + let first = false + let reverse = false + let name: string + let input = '' + let matcher: Matcher = 'fuzzy' + let position = 'bottom' + let listArgs: string[] = [] + let listOptions: string[] = [] + for (let arg of args) { + if (!name && arg.startsWith('-')) { + listOptions.push(arg) + } else if (!name) { + if (!/^\w+$/.test(arg)) { + window.showMessage(`Invalid list option: "${arg}"`, 'error') + return null + } + name = arg + } else { + listArgs.push(arg) + } + } + name = name || 'lists' + let config = workspace.getConfiguration(`list.source.${name}`) + if (!listOptions.length && !listArgs.length) listOptions = config.get('defaultOptions', []) + if (!listArgs.length) listArgs = config.get('defaultArgs', []) + for (let opt of listOptions) { + if (opt.startsWith('--input')) { + input = opt.slice(8) + } else if (opt == '--number-select' || opt == '-N') { + numberSelect = true + } else if (opt == '--auto-preview' || opt == '-A') { + autoPreview = true + } else if (opt == '--regex' || opt == '-R') { + matcher = 'regex' + } else if (opt == '--strict' || opt == '-S') { + matcher = 'strict' + } else if (opt == '--interactive' || opt == '-I') { + interactive = true + } else if (opt == '--top') { + position = 'top' + } else if (opt == '--tab') { + position = 'tab' + } else if (opt == '--ignore-case' || opt == '--normal' || opt == '--no-sort') { + options.push(opt.slice(2)) + } else if (opt == '--first') { + first = true + } else if (opt == '--reverse') { + reverse = true + } else if (opt == '--no-quit') { + noQuit = true + } else { + window.showMessage(`Invalid option "${opt}" of list`, 'error') + return null + } + } + let list = this.listMap.get(name) + if (!list) { + window.showMessage(`List ${name} not found`, 'error') + return null + } + if (interactive && !list.interactive) { + window.showMessage(`Interactive mode of "${name}" list not supported`, 'error') + return null + } + return { + list, + listArgs, + options: { + numberSelect, + autoPreview, + reverse, + noQuit, + first, + input, + interactive, + matcher, + position, + ignorecase: options.includes('ignore-case') ? true : false, + mode: !options.includes('normal') ? 'insert' : 'normal', + sort: !options.includes('no-sort') ? true : false + }, + } + } + + private async onInputChar(session: string, ch: string, charmod: number): Promise { + if (session != 'list') return + let { mode } = this.prompt + let now = Date.now() + if (ch == '' || (this.plugTs && now - this.plugTs < 20)) { + this.plugTs = now + return + } + if (!ch) return + if (ch == '') { + await this.cancel() + return + } + if (mode == 'insert') { + await this.onInsertInput(ch, charmod) + } else { + await this.onNormalInput(ch, charmod) + } + } + + public async onInsertInput(ch: string, charmod?: number): Promise { + let { session } = this + if (!session) return + if (mouseKeys.includes(ch)) { + await this.onMouseEvent(ch) + return + } + let n = await session.doNumberSelect(ch) + if (n) return + let done = await this.mappings.doInsertKeymap(ch) + if (done || charmod) return + if (ch.startsWith('<') && ch.endsWith('>')) { + await this.feedkeys(ch, false) + return + } + for (let s of ch) { + let code = s.codePointAt(0) + if (code == 65533) return + // exclude control character + if (code < 32 || code >= 127 && code <= 159) return + await this.prompt.acceptCharacter(s) + } + } + + public async onNormalInput(ch: string, _charmod?: number): Promise { + if (mouseKeys.includes(ch)) { + await this.onMouseEvent(ch) + return + } + let used = await this.mappings.doNormalKeymap(ch) + if (!used) await this.feedkeys(ch) + } + + private onMouseEvent(key): Promise { + if (this.session) return this.session.onMouseEvent(key) + } + + public async feedkeys(key: string, remap = true): Promise { + let { nvim } = this + key = key.startsWith('<') && key.endsWith('>') ? `\\${key}` : key + await nvim.call('coc#prompt#stop_prompt', ['list']) + await nvim.call('eval', [`feedkeys("${key}", "${remap ? 'i' : 'in'}")`]) + this.prompt.start() + } + + public async command(command: string): Promise { + let { nvim } = this + await nvim.call('coc#prompt#stop_prompt', ['list']) + await nvim.command(command) + this.prompt.start() + } + + public async normal(command: string, bang = true): Promise { + let { nvim } = this + await nvim.call('coc#prompt#stop_prompt', ['list']) + await nvim.command(`normal${bang ? '!' : ''} ${command}`) + this.prompt.start() + } + + public async call(fname: string): Promise { + if (this.session) return await this.session.call(fname) + } + + public get session(): ListSession | undefined { + return this.lastSession + } + + public registerList(list: IList): Disposable { + let { name } = list + let exists = this.listMap.get(name) + if (this.listMap.has(name)) { + if (exists) { + if (typeof exists.dispose == 'function') { + exists.dispose() + } + this.listMap.delete(name) + } + window.showMessage(`list "${name}" recreated.`) + } + this.listMap.set(name, list) + extensions.addSchemeProperty(`list.source.${name}.defaultAction`, { + type: 'string', + default: null, + description: `Default action of "${name}" list.` + }) + extensions.addSchemeProperty(`list.source.${name}.defaultOptions`, { + type: 'array', + default: list.interactive ? ['--interactive'] : [], + description: `Default list options of "${name}" list, only used when both list option and argument are empty.`, + uniqueItems: true, + items: { + type: 'string', + enum: ['--top', '--normal', '--no-sort', '--input', '--tab', + '--strict', '--regex', '--ignore-case', '--number-select', + '--interactive', '--auto-preview', '--first', '--no-quit'] + } + }) + extensions.addSchemeProperty(`list.source.${name}.defaultArgs`, { + type: 'array', + default: [], + description: `Default argument list of "${name}" list, only used when list argument is empty.`, + uniqueItems: true, + items: { type: 'string' } + }) + return Disposable.create(() => { + if (typeof list.dispose == 'function') { + list.dispose() + } + this.listMap.delete(name) + }) + } + + public get names(): string[] { + return Array.from(this.listMap.keys()) + } + + public get descriptions(): { [name: string]: string } { + let d = {} + for (let name of this.listMap.keys()) { + let list = this.listMap.get(name) + d[name] = list.description + } + return d + } + + /** + * Get items of {name} list, not work with interactive list. + * + * @param {string} name + * @returns {Promise} + */ + public async loadItems(name: string): Promise { + let args = [name] + let res = this.parseArgs(args) + if (!res) return + let { list, options, listArgs } = res + let source = new CancellationTokenSource() + let token = source.token + let arr = await this.nvim.eval('[win_getid(),bufnr("%")]') + let items = await list.loadItems({ + options, + args: listArgs, + input: '', + cwd: workspace.cwd, + window: this.nvim.createWindow(arr[0]), + buffer: this.nvim.createBuffer(arr[1]), + listWindow: null + }, token) + if (!items || Array.isArray(items)) { + return items + } + let task = items as ListTask + let newItems = await new Promise((resolve, reject) => { + let items = [] + task.on('data', item => { + item.label = stripAnsi(item.label) + items.push(item) + }) + task.on('end', () => { + resolve(items) + }) + task.on('error', msg => { + reject(msg) + }) + }) + return newItems + } + + public toggleMode(): void { + let lastSession = this.lastSession + if (lastSession) lastSession.toggleMode() + } + + public get isActivated(): boolean { + return this.session?.winid != null + } + + public stop(): void { + let lastSession = this.lastSession + if (lastSession) lastSession.stop() + } + + public dispose(): void { + for (let session of this.sessionsMap.values()) { + session.dispose() + } + this.sessionsMap.clear() + if (this.config) { + this.config.dispose() + } + this.lastSession = undefined + disposeAll(this.disposables) + } +} + +export default new ListManager() diff --git a/sources_non_forked/coc.nvim/src/list/mappings.ts b/sources_non_forked/coc.nvim/src/list/mappings.ts new file mode 100644 index 00000000..c09a5151 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/mappings.ts @@ -0,0 +1,313 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { ListMode } from '../types' +import window from '../window' +import ListConfiguration, { validKeys } from './configuration' +import { ListManager } from './manager' +const logger = require('../util/logger')('list-mappings') + +export default class Mappings { + private insertMappings: Map void | Promise> = new Map() + private normalMappings: Map void | Promise> = new Map() + private userInsertMappings: Map = new Map() + private userNormalMappings: Map = new Map() + private actions: Map void | Promise> = new Map() + + constructor(private manager: ListManager, + private nvim: Neovim, + private config: ListConfiguration) { + let { prompt } = manager + this.addAction('do:switch', async () => { + await manager.switchMatcher() + }) + this.addAction('do:selectall', async () => { + await manager.session?.ui.selectAll() + }) + this.addAction('do:help', async () => { + await manager.session?.showHelp() + }) + this.addAction('do:refresh', async () => { + await manager.session?.reloadItems() + }) + this.addAction('do:exit', async () => { + await manager.cancel() + }) + this.addAction('do:stop', () => { + manager.stop() + }) + this.addAction('do:cancel', async () => { + await manager.cancel(false) + }) + this.addAction('do:toggle', async () => { + await manager.session?.ui.toggleSelection() + }) + this.addAction('do:jumpback', () => { + manager.session?.jumpBack() + }) + this.addAction('do:previous', async () => { + await manager.normal('k') + }) + this.addAction('do:next', async () => { + await manager.normal('j') + }) + this.addAction('do:defaultaction', async () => { + await manager.doAction() + }) + this.addAction('do:chooseaction', async () => { + await manager.chooseAction() + }) + this.addAction('do:togglemode', () => { + manager.toggleMode() + }) + this.addAction('do:previewtoggle', async () => { + await manager.togglePreview() + }) + this.addAction('do:previewup', () => { + this.scrollPreview('up') + }) + this.addAction('do:previewdown', () => { + this.scrollPreview('down') + }) + this.addAction('do:command', async () => { + await manager.cancel(false) + await nvim.eval('feedkeys(":")') + }) + this.addAction('prompt:previous', () => { + manager.session?.history.previous() + }) + this.addAction('prompt:next', () => { + manager.session?.history.next() + }) + this.addAction('prompt:start', () => { + prompt.moveToStart() + }) + this.addAction('prompt:end', () => { + prompt.moveToEnd() + }) + this.addAction('prompt:left', () => { + prompt.moveLeft() + }) + this.addAction('prompt:right', () => { + prompt.moveRight() + }) + this.addAction('prompt:deleteforward', () => { + prompt.onBackspace() + }) + this.addAction('prompt:deletebackward', () => { + prompt.removeNext() + }) + this.addAction('prompt:removetail', () => { + prompt.removeTail() + }) + this.addAction('prompt:removeahead', () => { + prompt.removeAhead() + }) + this.addAction('prompt:removeword', () => { + prompt.removeWord() + }) + this.addAction('prompt:insertregister', () => { + prompt.insertRegister() + }) + this.addAction('prompt:paste', async () => { + await prompt.paste() + }) + this.addAction('eval', async expr => { + await prompt.eval(expr) + }) + this.addAction('command', async expr => { + await manager.command(expr) + }) + this.addAction('action', async expr => { + await manager.doAction(expr) + }) + this.addAction('feedkeys', async expr => { + await manager.feedkeys(expr) + }) + this.addAction('normal', async expr => { + await manager.normal(expr, false) + }) + this.addAction('normal!', async expr => { + await manager.normal(expr, true) + }) + this.addAction('call', async expr => { + await manager.call(expr) + }) + this.addAction('expr', async expr => { + let name = await manager.call(expr) + if (name) await manager.doAction(name) + }) + + this.addKeyMapping('insert', '', 'do:switch') + this.addKeyMapping('insert', '', 'prompt:next') + this.addKeyMapping('insert', '', 'prompt:previous') + this.addKeyMapping('insert', '', 'prompt:paste') + this.addKeyMapping('insert', ['', ''], 'do:defaultaction') + this.addKeyMapping('insert', ['', '', '\t'], 'do:chooseaction') + this.addKeyMapping('insert', '', 'do:togglemode') + this.addKeyMapping('insert', '', 'do:stop') + this.addKeyMapping('insert', '', 'do:refresh') + this.addKeyMapping('insert', '', 'prompt:left') + this.addKeyMapping('insert', '', 'prompt:right') + this.addKeyMapping('insert', ['', ''], 'prompt:end') + this.addKeyMapping('insert', ['', ''], 'prompt:start') + this.addKeyMapping('insert', ['', '', ''], 'prompt:deleteforward') + this.addKeyMapping('insert', '', 'prompt:removeword') + this.addKeyMapping('insert', '', 'prompt:removeahead') + this.addKeyMapping('insert', '', 'prompt:insertregister') + // normal + this.addKeyMapping('normal', 't', 'action:tabe') + this.addKeyMapping('normal', 's', 'action:split') + this.addKeyMapping('normal', 'd', 'action:drop') + this.addKeyMapping('normal', ['', '', '\r'], 'do:defaultaction') + this.addKeyMapping('normal', '', 'do:selectall') + this.addKeyMapping('normal', ' ', 'do:toggle') + this.addKeyMapping('normal', 'p', 'do:previewtoggle') + this.addKeyMapping('normal', ['', '\t', ''], 'do:chooseaction') + this.addKeyMapping('normal', '', 'do:stop') + this.addKeyMapping('normal', '', 'do:refresh') + this.addKeyMapping('normal', '', 'do:jumpback') + this.addKeyMapping('normal', '', 'do:previewdown') + this.addKeyMapping('normal', '', 'do:previewup') + this.addKeyMapping('normal', ['i', 'I', 'o', 'O', 'a', 'A'], 'do:togglemode') + this.addKeyMapping('normal', '?', 'do:help') + this.addKeyMapping('normal', ':', 'do:command') + this.createMappings() + config.on('change', () => { + this.createMappings() + }) + } + + private createMappings(): void { + let insertMappings = this.config.get('insertMappings', {}) + this.userInsertMappings = this.fixUserMappings(insertMappings, 'list.insertMappings') + let normalMappings = this.config.get('normalMappings', {}) + this.userNormalMappings = this.fixUserMappings(normalMappings, 'list.normalMappings') + } + + public hasUserMapping(mode: ListMode, key: string): boolean { + let map = mode == 'insert' ? this.userInsertMappings : this.userNormalMappings + return map.has(key) + } + + public isValidAction(action: string): boolean { + if (this.actions.has(action)) return true + let [key, expr] = action.split(':', 2) + if (!expr || !this.actions.has(key)) return false + return true + } + + private fixUserMappings(mappings: { [key: string]: string }, entry: string): Map { + let res: Map = new Map() + for (let [key, value] of Object.entries(mappings)) { + if (!this.isValidAction(value)) { + window.showMessage(`Invalid configuration - unable to support action "${value}" in "${entry}"`, 'warning') + continue + } + if (key.length == 1) { + res.set(key, value) + } else if (key.startsWith('<') && key.endsWith('>')) { + if (key.toLowerCase() == '') { + res.set(' ', value) + } else if (key.toLowerCase() == '') { + res.set('', value) + } else if (validKeys.includes(key)) { + res.set(key, value) + } else { + let find = false + for (let i = 0; i < validKeys.length; i++) { + if (validKeys[i].toLowerCase() == key.toLowerCase()) { + find = true + res.set(validKeys[i], value) + break + } + } + if (!find) window.showMessage(`Invalid configuration - unable to recognize "${key}" in "${entry}"`, 'warning') + } + } else { + window.showMessage(`Invalid configuration - unable to recognize key "${key}" in "${entry}"`, 'warning') + } + } + return res + } + + public async doInsertKeymap(key: string): Promise { + let nextKey = this.config.nextKey + let previousKey = this.config.previousKey + if (key == nextKey) { + this.manager?.session.ui.moveDown() + return true + } + if (key == previousKey) { + this.manager?.session.ui.moveUp() + return true + } + let expr = this.userInsertMappings.get(key) + if (expr) { + let fn = this.getAction(expr) + await Promise.resolve(fn()) + return true + } + if (this.insertMappings.has(key)) { + let fn = this.insertMappings.get(key) + await Promise.resolve(fn()) + return true + } + return false + } + + public async doNormalKeymap(key: string): Promise { + let expr = this.userNormalMappings.get(key) + if (expr) { + let fn = this.getAction(expr) + await Promise.resolve(fn()) + return true + } + if (this.normalMappings.has(key)) { + let fn = this.normalMappings.get(key) + await Promise.resolve(fn()) + return true + } + return false + } + + private addKeyMapping(mode: ListMode, key: string | string[], action: string): void { + let mappings = mode == 'insert' ? this.insertMappings : this.normalMappings + let fn = this.getAction(action) + if (Array.isArray(key)) { + for (let k of key) { + mappings.set(k, fn) + } + } else { + mappings.set(key, fn) + } + } + + private addAction(key: string, fn: (expr?: string) => void | Promise): void { + this.actions.set(key, fn) + } + + public getAction(action: string): () => void | Promise { + if (this.actions.has(action)) return () => { + return this.doAction(action) + } + let [key, expr] = action.split(':', 2) + if (!expr || !this.actions.has(key)) throw new Error(`Invalid action ${action}`) + return () => { + return this.doAction(key, expr) + } + } + + public async doAction(key: string, expr?: string): Promise { + let fn = this.actions.get(key) + if (!fn) throw new Error(`Action ${key} doesn't exist`) + await Promise.resolve(fn(expr)) + } + + private scrollPreview(dir: 'up' | 'down'): void { + let { nvim } = this + nvim.pauseNotification() + nvim.call('coc#list#scroll_preview', [dir], true) + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/prompt.ts b/sources_non_forked/coc.nvim/src/list/prompt.ts new file mode 100644 index 00000000..3df7147a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/prompt.ts @@ -0,0 +1,215 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Emitter, Event } from 'vscode-languageserver-protocol' +import { ListMode, ListOptions, Matcher } from '../types' +import ListConfiguration from './configuration' +const logger = require('../util/logger')('list-prompt') + +export default class Prompt { + private cusorIndex = 0 + private _input = '' + private _matcher: Matcher | '' + private _mode: ListMode = 'insert' + private interactive = false + private requestInput = false + + private _onDidChangeInput = new Emitter() + public readonly onDidChangeInput: Event = this._onDidChangeInput.event + + constructor(private nvim: Neovim, private config: ListConfiguration) { + } + + public get input(): string { + return this._input + } + + public set input(str: string) { + if (this._input == str) return + this.cusorIndex = str.length + this._input = str + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public get mode(): ListMode { + return this._mode + } + + public set mode(val: ListMode) { + if (val == this._mode) return + this._mode = val + this.drawPrompt() + } + + public set matcher(val: Matcher) { + this._matcher = val + this.drawPrompt() + } + + public start(opts?: ListOptions): void { + if (opts) { + this.interactive = opts.interactive + this.cusorIndex = opts.input.length + this._input = opts.input + this._mode = opts.mode + this._matcher = opts.interactive ? '' : opts.matcher + } + this.nvim.call('coc#prompt#start_prompt', ['list'], true) + this.drawPrompt() + } + + public cancel(): void { + let { nvim } = this + nvim.call('coc#prompt#stop_prompt', ['list'], true) + } + + public reset(): void { + this._input = '' + this.cusorIndex = 0 + } + + public drawPrompt(): void { + let indicator = this.config.get('indicator', '>') + let { cusorIndex, interactive, input, _matcher } = this + let cmds = ['echo ""'] + if (this.mode == 'insert') { + if (interactive) { + cmds.push(`echohl MoreMsg | echon 'INTERACTIVE ' | echohl None`) + } else if (_matcher) { + cmds.push(`echohl MoreMsg | echon '${_matcher.toUpperCase()} ' | echohl None`) + } + cmds.push(`echohl Special | echon '${indicator} ' | echohl None`) + if (cusorIndex == input.length) { + cmds.push(`echon '${input.replace(/'/g, "''")}'`) + cmds.push(`echohl Cursor | echon ' ' | echohl None`) + } else { + let pre = input.slice(0, cusorIndex) + if (pre) cmds.push(`echon '${pre.replace(/'/g, "''")}'`) + cmds.push(`echohl Cursor | echon '${input[cusorIndex].replace(/'/, "''")}' | echohl None`) + let post = input.slice(cusorIndex + 1) + cmds.push(`echon '${post.replace(/'/g, "''")}'`) + } + } else { + cmds.push(`echohl MoreMsg | echo "" | echohl None`) + } + cmds.push('redraw') + let cmd = cmds.join('|') + this.nvim.command(cmd, true) + } + + public moveLeft(): void { + if (this.cusorIndex == 0) return + this.cusorIndex = this.cusorIndex - 1 + this.drawPrompt() + } + + public moveRight(): void { + if (this.cusorIndex == this._input.length) return + this.cusorIndex = this.cusorIndex + 1 + this.drawPrompt() + } + + public moveToEnd(): void { + if (this.cusorIndex == this._input.length) return + this.cusorIndex = this._input.length + this.drawPrompt() + } + + public moveToStart(): void { + if (this.cusorIndex == 0) return + this.cusorIndex = 0 + this.drawPrompt() + } + + public onBackspace(): void { + let { cusorIndex, input } = this + if (cusorIndex == 0) return + let pre = input.slice(0, cusorIndex) + let post = input.slice(cusorIndex) + this.cusorIndex = cusorIndex - 1 + this._input = `${pre.slice(0, pre.length - 1)}${post}` + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public removeNext(): void { + let { cusorIndex, input } = this + if (cusorIndex == input.length - 1) return + let pre = input.slice(0, cusorIndex) + let post = input.slice(cusorIndex + 1) + this._input = `${pre}${post}` + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public removeWord(): void { + let { cusorIndex, input } = this + if (cusorIndex == 0) return + let pre = input.slice(0, cusorIndex) + let post = input.slice(cusorIndex) + let remain = pre.replace(/[\w$]+([^\w$]+)?$/, '') + this.cusorIndex = cusorIndex - (pre.length - remain.length) + this._input = `${remain}${post}` + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public removeTail(): void { + let { cusorIndex, input } = this + if (cusorIndex == input.length) return + let pre = input.slice(0, cusorIndex) + this._input = pre + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public removeAhead(): void { + let { cusorIndex, input } = this + if (cusorIndex == 0) return + let post = input.slice(cusorIndex) + this.cusorIndex = 0 + this._input = post + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } + + public async acceptCharacter(ch: string): Promise { + if (this.requestInput) { + this.requestInput = false + if (/^[0-9a-z"%#*+/:\-.]$/.test(ch)) { + let text = await this.nvim.call('getreg', ch) as string + text = text.replace(/\n/g, ' ') + this.addText(text) + } + } else { + this.addText(ch) + } + } + + public insertRegister(): void { + this.requestInput = true + } + + public async paste(): Promise { + let text = await this.nvim.eval('@*') as string + text = text.replace(/\n/g, '') + if (!text) return + this.addText(text) + } + + public async eval(expression: string): Promise { + let text = await this.nvim.call('eval', [expression]) as string + text = text.replace(/\n/g, '') + this.addText(text) + } + + private addText(text: string): void { + let { cusorIndex, input } = this + this.cusorIndex = cusorIndex + text.length + let pre = input.slice(0, cusorIndex) + let post = input.slice(cusorIndex) + this._input = `${pre}${text}${post}` + this.drawPrompt() + this._onDidChangeInput.fire(this._input) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/session.ts b/sources_non_forked/coc.nvim/src/list/session.ts new file mode 100644 index 00000000..70f8d57c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/session.ts @@ -0,0 +1,582 @@ +'use strict' +import { Buffer, Neovim, Window } from '@chemzqm/neovim' +import debounce from 'debounce' +import { Disposable } from 'vscode-languageserver-protocol' +import extensions from '../extensions' +import Highlighter from '../model/highligher' +import { IList, ListAction, ListContext, ListItem, ListMode, ListOptions, Matcher } from '../types' +import { disposeAll, wait } from '../util' +import window from '../window' +import workspace from '../workspace' +import ListConfiguration from './configuration' +import InputHistory from './history' +import Prompt from './prompt' +import UI from './ui' +import Worker, { getItemHighlights } from './worker' +const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] +const logger = require('../util/logger')('list-session') + +/** + * Activated list session with UI and worker + */ +export default class ListSession { + public readonly history: InputHistory + public readonly ui: UI + public readonly worker: Worker + private cwd: string + private loadingFrame = '' + private timer: NodeJS.Timer + private hidden = false + private disposables: Disposable[] = [] + private savedHeight: number + private window: Window + private buffer: Buffer + private interactiveDebounceTime: number + /** + * Original list arguments. + */ + private args: string[] = [] + constructor( + private nvim: Neovim, + private prompt: Prompt, + private list: IList, + public readonly listOptions: ListOptions, + private listArgs: string[] = [], + private config: ListConfiguration + ) { + this.ui = new UI(nvim, list.name, listOptions, config) + this.history = new InputHistory(prompt, list.name) + this.worker = new Worker(nvim, list, prompt, listOptions, { + interactiveDebounceTime: config.get('interactiveDebounceTime', 100), + extendedSearchMode: config.get('extendedSearchMode', true) + }) + this.interactiveDebounceTime = config.get('interactiveDebounceTime', 100) + let debouncedChangeLine = debounce(async () => { + let [previewing, currwin, lnum] = await nvim.eval('[coc#list#has_preview(),win_getid(),line(".")]') as [number, number, number] + if (previewing && currwin == this.winid) { + let idx = this.ui.lnumToIndex(lnum) + await this.doPreview(idx) + } + }, 50) + this.disposables.push({ + dispose: () => { + debouncedChangeLine.clear() + } + }) + this.ui.onDidChangeLine(debouncedChangeLine, null, this.disposables) + this.ui.onDidChangeLine(this.resolveItem, this, this.disposables) + this.ui.onDidLineChange(this.resolveItem, this, this.disposables) + let debounced = debounce(async () => { + this.updateStatus() + let { autoPreview } = this.listOptions + if (!autoPreview) { + let [previewing, mode] = await nvim.eval('[coc#list#has_preview(),mode()]') as [number, string] + if (!previewing || mode != 'n') return + } + await this.doAction('preview') + }, 50) + this.disposables.push({ + dispose: () => { + debounced.clear() + } + }) + this.ui.onDidLineChange(debounced, null, this.disposables) + this.ui.onDidOpen(async () => { + if (typeof this.list.doHighlight == 'function') { + this.list.doHighlight() + } + if (workspace.isVim) this.prompt.drawPrompt() + if (this.listOptions.first) { + await this.doAction() + } + }, null, this.disposables) + this.ui.onDidClose(async () => { + await this.hide() + }, null, this.disposables) + this.ui.onDidDoubleClick(async () => { + await this.doAction() + }, null, this.disposables) + this.worker.onDidChangeItems(async ({ items, reload, append, finished }) => { + if (this.hidden) return + if (append) { + await this.ui.appendItems(items) + } else { + let height = this.config.get('height', 10) + if (finished && !listOptions.interactive && listOptions.input.length == 0) { + height = Math.min(items.length, height) + } + await this.ui.drawItems(items, Math.max(1, height), reload) + } + }, null, this.disposables) + let start = 0 + let timer: NodeJS.Timeout + let interval: NodeJS.Timeout + this.disposables.push(Disposable.create(() => { + if (timer) clearTimeout(timer) + if (interval) clearInterval(interval) + })) + this.worker.onDidChangeLoading(loading => { + if (this.hidden) return + if (timer) clearTimeout(timer) + if (loading) { + start = Date.now() + interval = setInterval(() => { + let idx = Math.floor((Date.now() - start) % 1000 / 100) + this.loadingFrame = frames[idx] + this.updateStatus() + }, 100) + } else { + timer = setTimeout(() => { + this.loadingFrame = '' + if (interval) clearInterval(interval) + interval = null + this.updateStatus() + }, Math.max(0, 200 - (Date.now() - start))) + } + }, null, this.disposables) + } + + public async start(args: string[]): Promise { + this.args = args + this.cwd = workspace.cwd + this.hidden = false + let { listOptions, listArgs } = this + let res = await this.nvim.eval('[win_getid(),bufnr("%"),winheight("%")]') + this.listArgs = listArgs + this.history.load(listOptions.input || '') + this.window = this.nvim.createWindow(res[0]) + this.buffer = this.nvim.createBuffer(res[1]) + this.savedHeight = res[2] + await this.worker.loadItems(this.context) + } + + public async reloadItems(): Promise { + if (!this.ui.winid) return + await this.worker.loadItems(this.context, true) + } + + public async call(fname: string): Promise { + await this.nvim.call('coc#prompt#stop_prompt', ['list']) + let targets = await this.ui.getItems() + let context = { + name: this.name, + args: this.listArgs, + input: this.prompt.input, + winid: this.window?.id, + bufnr: this.buffer?.id, + targets + } + let res = await this.nvim.call(fname, [context]) + this.prompt.start() + return res + } + + public async chooseAction(): Promise { + let { nvim, defaultAction } = this + let { actions } = this.list + let names: string[] = actions.map(o => o.name) + let idx = names.indexOf(defaultAction.name) + if (idx != -1) { + names.splice(idx, 1) + names.unshift(defaultAction.name) + } + let shortcuts: Set = new Set() + let choices: string[] = [] + let invalids: string[] = [] + let menuAction = workspace.env.dialog && this.config.get('menuAction', false) + for (let name of names) { + let i = 0 + for (let ch of name) { + if (!shortcuts.has(ch)) { + shortcuts.add(ch) + choices.push(`${name.slice(0, i)}&${name.slice(i)}`) + break + } + i++ + } + if (i == name.length) { + invalids.push(name) + } + } + if (invalids.length && !menuAction) { + names = names.filter(s => !invalids.includes(s)) + } + let n: number + if (menuAction) { + nvim.call('coc#prompt#stop_prompt', ['list'], true) + n = await window.showMenuPicker(names, { title: 'Choose action', shortcuts: true }) + n = n + 1 + if (workspace.isVim) await wait(10) + this.prompt.start() + } else { + await nvim.call('coc#prompt#stop_prompt', ['list']) + n = await nvim.call('confirm', ['Choose action:', choices.join('\n')]) as number + await wait(10) + this.prompt.start() + } + if (n) await this.doAction(names[n - 1]) + } + + public async doAction(name?: string): Promise { + let { list } = this + let action: ListAction + if (name != null) { + action = list.actions.find(o => o.name == name) + if (!action) { + void window.showErrorMessage(`Action ${name} not found`) + return + } + } else { + action = this.defaultAction + } + let items: ListItem[] + if (name == 'preview') { + let item = await this.ui.item + items = item ? [item] : [] + } else { + items = await this.ui.getItems() + } + if (items.length) await this.doItemAction(items, action) + } + + private async doPreview(index: number): Promise { + let item = this.ui.getItem(index) + let action = this.list.actions.find(o => o.name == 'preview') + if (!item || !action) return + await this.doItemAction([item], action) + } + + public async first(): Promise { + await this.doDefaultAction(0) + } + + public async last(): Promise { + await this.doDefaultAction(this.ui.length - 1) + } + + public async previous(): Promise { + await this.doDefaultAction(this.ui.index - 1) + } + + public async next(): Promise { + await this.doDefaultAction(this.ui.index + 1) + } + + private async doDefaultAction(index: number): Promise { + let { ui } = this + let item = ui.getItem(index) + if (!item) return + ui.index = index + await this.doItemAction([item], this.defaultAction) + await ui.echoMessage(item) + } + + /** + * list name + */ + public get name(): string { + return this.list.name + } + + /** + * Window id used by list. + * + * @returns {number | undefined} + */ + public get winid(): number | undefined { + return this.ui.winid + } + + public get length(): number { + return this.ui.length + } + + public get defaultAction(): ListAction { + let { defaultAction, actions, name } = this.list + let config = workspace.getConfiguration(`list.source.${name}`) + let action: ListAction + if (config.defaultAction) action = actions.find(o => o.name == config.defaultAction) + if (!action) action = actions.find(o => o.name == defaultAction) + if (!action) action = actions[0] + if (!action) throw new Error(`default action "${defaultAction}" not found`) + return action + } + + public async hide(notify = false): Promise { + if (this.hidden) return + let { nvim, timer, window } = this + let { winid, tabnr } = this.ui + if (timer) clearTimeout(timer) + this.worker.stop() + this.history.add() + this.ui.reset() + this.hidden = true + let { isVim } = workspace + nvim.pauseNotification() + if (!isVim) nvim.call('coc#prompt#stop_prompt', ['list'], true) + if (tabnr) nvim.call('coc#list#close_preview', [tabnr], true) + if (window) nvim.call('win_gotoid', [window.id], true) + if (winid) nvim.call('coc#window#close', [winid], true) + if (window && this.savedHeight && this.listOptions.position !== 'tab') { + nvim.call('coc#window#set_height', [window.id, this.savedHeight], true) + } + if (notify) return nvim.resumeNotification(false, true) + await nvim.resumeNotification(false) + if (isVim) { + // otherwise we could receive for new list. + await wait(10) + nvim.call('feedkeys', ['\x1b', 'int'], true) + nvim.command('redraw', true) + } + } + + public toggleMode(): void { + let mode: ListMode = this.prompt.mode == 'normal' ? 'insert' : 'normal' + this.prompt.mode = mode + this.listOptions.mode = mode + this.updateStatus() + } + + public stop(): void { + this.worker.stop() + } + + private async resolveItem(): Promise { + let index = this.ui.index + let item = this.ui.getItem(index) + if (!item || item.resolved) return + let { list } = this + if (typeof list.resolveItem == 'function') { + let label = item.label + let resolved = await Promise.resolve(list.resolveItem(item)) + if (resolved && index == this.ui.index) { + let highlights = getItemHighlights(this.prompt.input, resolved) + this.ui.updateItem(Object.assign({ highlights }, resolved), index, label != resolved.label) + } + } + } + + public async showHelp(): Promise { + await this.hide() + let { list, nvim } = this + if (!list) return + nvim.pauseNotification() + nvim.command(`tabe +setl\\ previewwindow [LIST HELP]`, true) + nvim.command('setl nobuflisted noswapfile buftype=nofile bufhidden=wipe', true) + await nvim.resumeNotification() + let hasOptions = list.options && list.options.length + let buf = await nvim.buffer + let highligher = new Highlighter() + highligher.addLine('NAME', 'Label') + highligher.addLine(` ${list.name} - ${list.description || ''}\n`) + highligher.addLine('SYNOPSIS', 'Label') + highligher.addLine(` :CocList [LIST OPTIONS] ${list.name}${hasOptions ? ' [ARGUMENTS]' : ''}\n`) + if (list.detail) { + highligher.addLine('DESCRIPTION', 'Label') + let lines = list.detail.split('\n').map(s => ' ' + s) + highligher.addLine(lines.join('\n') + '\n') + } + if (hasOptions) { + highligher.addLine('ARGUMENTS', 'Label') + highligher.addLine('') + for (let opt of list.options) { + highligher.addLine(opt.name, 'Special') + highligher.addLine(` ${opt.description}`) + highligher.addLine('') + } + highligher.addLine('') + } + let config = workspace.getConfiguration(`list.source.${list.name}`) + if (Object.keys(config).length) { + highligher.addLine('CONFIGURATIONS', 'Label') + highligher.addLine('') + let props = {} + extensions.all.forEach(extension => { + let { packageJSON } = extension + let { contributes } = packageJSON + if (!contributes) return + let { configuration } = contributes + if (configuration) { + let { properties } = configuration + if (properties) { + for (let key of Object.keys(properties)) { + props[key] = properties[key] + } + } + } + }) + for (let key of Object.keys(config)) { + let val = config[key] + let name = `list.source.${list.name}.${key}` + let description = props[name] && props[name].description ? props[name].description : key + highligher.addLine(` "${name}"`, 'MoreMsg') + highligher.addText(` - ${description}, current value: `) + highligher.addText(JSON.stringify(val), 'Special') + } + highligher.addLine('') + } + highligher.addLine('ACTIONS', 'Label') + highligher.addLine(` ${list.actions.map(o => o.name).join(', ')}`) + highligher.addLine('') + highligher.addLine(`see ':h coc-list-options' for available list options.`, 'Comment') + nvim.pauseNotification() + highligher.render(buf, 0, -1) + nvim.command('setl nomod', true) + nvim.command('setl nomodifiable', true) + nvim.command('normal! gg', true) + nvim.command('nnoremap q :bd!', true) + await nvim.resumeNotification() + } + + public async switchMatcher(): Promise { + let { matcher, interactive } = this.listOptions + if (interactive) return + const list: Matcher[] = ['fuzzy', 'strict', 'regex'] + let idx = list.indexOf(matcher) + 1 + if (idx >= list.length) idx = 0 + this.listOptions.matcher = list[idx] + this.prompt.matcher = list[idx] + await this.worker.drawItems() + } + + private updateStatus(): void { + let { ui, list, nvim } = this + if (!ui.bufnr) return + let buf = nvim.createBuffer(ui.bufnr) + let status = { + mode: this.prompt.mode.toUpperCase(), + args: this.args.join(' '), + name: list.name, + cwd: this.cwd, + loading: this.loadingFrame, + total: this.worker.length + } + buf.setVar('list_status', status, true) + nvim.command('redraws', true) + } + + public get context(): ListContext { + let { winid } = this.ui + return { + options: this.listOptions, + args: this.listArgs, + input: this.prompt.input, + cwd: workspace.cwd, + window: this.window, + buffer: this.buffer, + listWindow: winid ? this.nvim.createWindow(winid) : undefined + } + } + + public onMouseEvent(key): Promise { + switch (key) { + case '': + return this.ui.onMouse('mouseDown') + case '': + return this.ui.onMouse('mouseDrag') + case '': + return this.ui.onMouse('mouseUp') + case '<2-LeftMouse>': + return this.ui.onMouse('doubleClick') + } + } + + public async doNumberSelect(ch: string): Promise { + if (!this.listOptions.numberSelect) return false + let code = ch.charCodeAt(0) + if (code >= 48 && code <= 57) { + let n = Number(ch) + if (n == 0) n = 10 + if (this.ui.length >= n) { + this.nvim.pauseNotification() + this.ui.setCursor(n) + await this.nvim.resumeNotification() + await this.doAction() + return true + } + } + return false + } + + public jumpBack(): void { + let { window, nvim } = this + if (window) { + nvim.pauseNotification() + nvim.call('coc#prompt#stop_prompt', ['list'], true) + this.nvim.call('win_gotoid', [window.id], true) + nvim.resumeNotification(false, true) + } + } + + public async resume(): Promise { + if (this.winid) await this.hide() + let res = await this.nvim.eval('[win_getid(),bufnr("%"),winheight("%")]') + this.hidden = false + this.window = this.nvim.createWindow(res[0]) + this.buffer = this.nvim.createBuffer(res[1]) + this.savedHeight = res[2] + this.prompt.start() + await this.ui.resume() + if (this.listOptions.autoPreview) { + await this.doAction('preview') + } + } + + private async doItemAction(items: ListItem[], action: ListAction): Promise { + let { noQuit, position } = this.listOptions + let { nvim } = this + let persistAction = action.persist === true || action.name == 'preview' + if (position === 'tab' && action.tabPersist) persistAction = true + let persist = this.winid && (persistAction || noQuit) + try { + if (persist) { + if (!persistAction) { + nvim.pauseNotification() + nvim.call('coc#prompt#stop_prompt', ['list'], true) + nvim.call('win_gotoid', [this.context.window.id], true) + await nvim.resumeNotification() + } + } else { + await this.hide() + } + if (action.multiple) { + await Promise.resolve(action.execute(items, this.context)) + } else if (action.parallel) { + await Promise.all(items.map(item => Promise.resolve(action.execute(item, this.context)))) + } else { + for (let item of items) { + await Promise.resolve(action.execute(item, this.context)) + } + } + if (persist) this.ui.restoreWindow() + if (action.reload && persist) { + await this.reloadItems() + } else if (persist) { + this.nvim.command('redraw', true) + } + } catch (e) { + this.nvim.echoError(e) + } + } + + public onInputChange(): void { + if (this.timer) clearTimeout(this.timer) + this.listOptions.input = this.prompt.input + // reload or filter items + if (this.listOptions.interactive) { + this.worker.stop() + this.timer = setTimeout(async () => { + await this.worker.loadItems(this.context) + }, this.interactiveDebounceTime) + } else { + void this.worker.drawItems() + } + } + + public dispose(): void { + void this.hide(true) + disposeAll(this.disposables) + this.worker.dispose() + this.ui.dispose() + } +} diff --git a/sources_non_forked/coc.nvim/src/list/source/commands.ts b/sources_non_forked/coc.nvim/src/list/source/commands.ts new file mode 100644 index 00000000..85e5c7c7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/commands.ts @@ -0,0 +1,56 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import commandManager from '../../commands' +import Mru from '../../model/mru' +import { ListContext, ListItem } from '../../types' +import workspace from '../../workspace' +import BasicList from '../basic' +import { formatListItems, UnformattedListItem } from '../formatting' + +export default class CommandsList extends BasicList { + public defaultAction = 'run' + public description = 'registered commands of coc.nvim' + public readonly name = 'commands' + private mru: Mru + + constructor(nvim: Neovim) { + super(nvim) + this.mru = workspace.createMru('commands') + this.addAction('run', async item => { + await commandManager.fireCommand(item.data.cmd) + }) + this.addAction('append', async item => { + let { cmd } = item.data + await nvim.feedKeys(`:CocCommand ${cmd} `, 'n', false) + }) + } + + public async loadItems(_context: ListContext): Promise { + let items: UnformattedListItem[] = [] + let mruList = await this.mru.load() + let { commandList, onCommandList, titles } = commandManager + let ids = commandList.map(c => c.id).concat(onCommandList) + for (const id of [...new Set(ids)]) { + items.push({ + label: [id, ...(titles.get(id) ? [titles.get(id)] : [])], + filterText: id, + data: { cmd: id, score: score(mruList, id) } + }) + } + items.sort((a, b) => b.data.score - a.data.score) + return formatListItems(this.alignColumns, items) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocCommandsTitle /\\t.*$/ contained containedin=CocCommandsLine', true) + nvim.command('highlight default link CocCommandsTitle Comment', true) + nvim.resumeNotification(false, true) + } +} + +function score(list: string[], key: string): number { + let idx = list.indexOf(key) + return idx == -1 ? -1 : list.length - idx +} diff --git a/sources_non_forked/coc.nvim/src/list/source/diagnostics.ts b/sources_non_forked/coc.nvim/src/list/source/diagnostics.ts new file mode 100644 index 00000000..cfff8e10 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/diagnostics.ts @@ -0,0 +1,59 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import diagnosticManager from '../../diagnostic/manager' +import { ListContext, ListItem } from '../../types' +import { isParentFolder } from '../../util/fs' +import { formatListItems, formatPath, PathFormatting, UnformattedListItem } from '../formatting' +import { ListManager } from '../manager' +import LocationList from './location' +const logger = require('../../util/logger')('list-symbols') + +export default class DiagnosticsList extends LocationList { + public readonly defaultAction = 'open' + public readonly description = 'diagnostics of current workspace' + public name = 'diagnostics' + public constructor(nvim: Neovim, manager: ListManager) { + super(nvim) + diagnosticManager.onDidRefresh(async () => { + let session = manager.getSession('diagnostics') + if (session) await session.reloadItems() + }, null, this.disposables) + } + + public async loadItems(context: ListContext): Promise { + let list = await diagnosticManager.getDiagnosticList() + let { cwd } = context + const config = this.getConfig() + const shouldIncludeCode = config.get('includeCode', true) + const pathFormat = config.get('pathFormat', "full") + const unformatted: UnformattedListItem[] = list.map(item => { + const file = isParentFolder(cwd, item.file) ? path.relative(cwd, item.file) : item.file + const formattedPath = formatPath(pathFormat, file) + const formattedPosition = pathFormat !== "hidden" ? [`${formattedPath}:${item.lnum}`] : [] + const code = shouldIncludeCode ? [`[${item.source}${item.code ? '' : ']'}`, item.code ? `${item.code}]` : ''] : [] + return { + label: [...formattedPosition, ...code, item.severity, item.message], + location: item.location, + } + }) + return formatListItems(this.alignColumns, unformatted) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocDiagnosticsFile /\\v^\\s*\\S+/ contained containedin=CocDiagnosticsLine', true) + nvim.command('syntax match CocDiagnosticsError /\\tError\\s*\\t/ contained containedin=CocDiagnosticsLine', true) + nvim.command('syntax match CocDiagnosticsWarning /\\tWarning\\s*\\t/ contained containedin=CocDiagnosticsLine', true) + nvim.command('syntax match CocDiagnosticsInfo /\\tInformation\\s*\\t/ contained containedin=CocDiagnosticsLine', true) + nvim.command('syntax match CocDiagnosticsHint /\\tHint\\s*\\t/ contained containedin=CocDiagnosticsLine', true) + nvim.command('highlight default link CocDiagnosticsFile Comment', true) + nvim.command('highlight default link CocDiagnosticsError CocErrorSign', true) + nvim.command('highlight default link CocDiagnosticsWarning CocWarningSign', true) + nvim.command('highlight default link CocDiagnosticsInfo CocInfoSign', true) + nvim.command('highlight default link CocDiagnosticsHint CocHintSign', true) + nvim.resumeNotification(false, true) + } +} + diff --git a/sources_non_forked/coc.nvim/src/list/source/extensions.ts b/sources_non_forked/coc.nvim/src/list/source/extensions.ts new file mode 100644 index 00000000..6739007a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/extensions.ts @@ -0,0 +1,179 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { URI } from 'vscode-uri' +import extensions from '../../extensions' +import { ListContext, ListItem } from '../../types' +import { wait } from '../../util' +import workspace from '../../workspace' +import window from '../../window' +import BasicList from '../basic' +import { formatListItems, UnformattedListItem } from '../formatting' +const logger = require('../../util/logger')('list-extensions') + +export default class ExtensionList extends BasicList { + public defaultAction = 'toggle' + public description = 'manage coc extensions' + public name = 'extensions' + + constructor(nvim: Neovim) { + super(nvim) + this.addAction('toggle', async item => { + let { id, state } = item.data + if (state == 'disabled') return + if (state == 'activated') { + await extensions.deactivate(id) + } else { + await extensions.activate(id) + } + await wait(100) + }, { persist: true, reload: true, parallel: true }) + + this.addAction('configuration', async item => { + let { root } = item.data + let jsonFile = path.join(root, 'package.json') + if (fs.existsSync(jsonFile)) { + let lines = fs.readFileSync(jsonFile, 'utf8').split(/\r?\n/) + let idx = lines.findIndex(s => s.includes('"contributes"')) + await workspace.jumpTo(URI.file(jsonFile).toString(), { line: idx == -1 ? 0 : idx, character: 0 }) + } + }) + + this.addAction('open', async item => { + let { root } = item.data + if (workspace.env.isiTerm) { + nvim.call('coc#ui#iterm_open', [root], true) + } else { + nvim.call('coc#ui#open_url', [root], true) + } + }) + + this.addAction('disable', async item => { + let { id, state } = item.data + if (state !== 'disabled') await extensions.toggleExtension(id) + }, { persist: true, reload: true, parallel: true }) + + this.addAction('enable', async item => { + let { id, state } = item.data + if (state == 'disabled') await extensions.toggleExtension(id) + }, { persist: true, reload: true, parallel: true }) + + this.addAction('lock', async item => { + let { id } = item.data + await extensions.lockExtension(id) + }, { persist: true, reload: true }) + + this.addAction('help', async item => { + let { root } = item.data + let files = await fs.readdir(root) + let file = files.find(f => /^readme/i.test(f)) + if (file) await workspace.callAsync('coc#util#jump', ['edit', path.join(root, file)]) + }) + + this.addAction('reload', async item => { + let { id } = item.data + await extensions.reloadExtension(id) + }, { persist: true, reload: true }) + + this.addAction('fix', async item => { + let { root, isLocal } = item.data + let { npm } = extensions + if (isLocal) { + window.showMessage(`Can't fix for local extension.`, 'warning') + return + } + if (!npm) return + let folder = path.join(root, 'node_modules') + if (fs.existsSync(folder)) { + fs.removeSync(folder) + } + let terminal = await window.createTerminal({ + cwd: root + }) + let shown = await terminal.show(false) + if (!shown) return + workspace.nvim.command(`startinsert`, true) + terminal.sendText(`${npm} install --production --ignore-scripts --no-lockfile`, true) + }) + + this.addMultipleAction('uninstall', async items => { + let ids = [] + for (let item of items) { + if (item.data.isLocal) continue + ids.push(item.data.id) + } + extensions.uninstallExtension(ids).catch(e => { + logger.error(e) + }) + }) + } + + public async loadItems(_context: ListContext): Promise { + let items: UnformattedListItem[] = [] + let list = await extensions.getExtensionStates() + let lockedList = await extensions.getLockedList() + for (let stat of list) { + let prefix = '+' + if (stat.state == 'disabled') { + prefix = '-' + } else if (stat.state == 'activated') { + prefix = '*' + } else if (stat.state == 'unknown') { + prefix = '?' + } + let root = await this.nvim.call('resolve', stat.root) + let locked = lockedList.includes(stat.id) + items.push({ + label: [`${prefix} ${stat.id}${locked ? ' ' : ''}`, ...(stat.isLocal ? ['[RTP]'] : []), stat.version, root.replace(os.homedir(), '~')], + filterText: stat.id, + data: { + id: stat.id, + root, + state: stat.state, + isLocal: stat.isLocal, + priority: getPriority(stat.state) + } + }) + } + items.sort((a, b) => { + if (a.data.priority != b.data.priority) { + return b.data.priority - a.data.priority + } + return b.data.id - a.data.id ? 1 : -1 + }) + return formatListItems(this.alignColumns, items) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocExtensionsActivited /\\v^\\*/ contained containedin=CocExtensionsLine', true) + nvim.command('syntax match CocExtensionsLoaded /\\v^\\+/ contained containedin=CocExtensionsLine', true) + nvim.command('syntax match CocExtensionsDisabled /\\v^-/ contained containedin=CocExtensionsLine', true) + nvim.command('syntax match CocExtensionsName /\\v%3c\\S+/ contained containedin=CocExtensionsLine', true) + nvim.command('syntax match CocExtensionsRoot /\\v\\t[^\\t]*$/ contained containedin=CocExtensionsLine', true) + nvim.command('syntax match CocExtensionsLocal /\\v\\[RTP\\]/ contained containedin=CocExtensionsLine', true) + nvim.command('highlight default link CocExtensionsActivited Special', true) + nvim.command('highlight default link CocExtensionsLoaded Normal', true) + nvim.command('highlight default link CocExtensionsDisabled Comment', true) + nvim.command('highlight default link CocExtensionsName String', true) + nvim.command('highlight default link CocExtensionsLocal MoreMsg', true) + nvim.command('highlight default link CocExtensionsRoot Comment', true) + nvim.resumeNotification(false, true) + } +} + +function getPriority(stat: string): number { + switch (stat) { + case 'unknown': + return 2 + case 'activated': + return 1 + case 'disabled': + return -1 + default: + return 0 + } +} diff --git a/sources_non_forked/coc.nvim/src/list/source/folders.ts b/sources_non_forked/coc.nvim/src/list/source/folders.ts new file mode 100644 index 00000000..580c3bcf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/folders.ts @@ -0,0 +1,50 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { URI } from 'vscode-uri' +import fs from 'fs-extra' +import { ListContext, ListItem } from '../../types' +import { statAsync } from '../../util/fs' +import workspace from '../../workspace' +import window from '../../window' +import BasicList from '../basic' + +export default class FoldList extends BasicList { + public defaultAction = 'edit' + public description = 'list of current workspace folders' + public name = 'folders' + + constructor(nvim: Neovim) { + super(nvim) + + this.addAction('edit', async item => { + let newPath = await nvim.call('input', ['Folder: ', item.label, 'dir']) + let stat = await statAsync(newPath) + if (!stat || !stat.isDirectory()) { + window.showMessage(`invalid path: ${newPath}`, 'error') + return + } + workspace.workspaceFolderControl.renameWorkspaceFolder(item.label, newPath) + }) + + this.addAction('delete', async item => { + workspace.workspaceFolderControl.removeWorkspaceFolder(item.label) + }, { reload: true, persist: true }) + + this.addAction('newfile', async (item, context) => { + let file = await window.requestInput('File name', item.label + '/') + if (!file) return + let dir = path.dirname(file) + let stat = await statAsync(dir) + if (!stat || !stat.isDirectory()) { + fs.mkdirpSync(dir) + } + await workspace.createFile(file, { overwrite: false, ignoreIfExists: true }) + await this.jumpTo(URI.file(file).toString(), null, context) + }) + } + + public async loadItems(_context: ListContext): Promise { + return workspace.folderPaths.map(p => ({ label: p })) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/source/links.ts b/sources_non_forked/coc.nvim/src/list/source/links.ts new file mode 100644 index 00000000..ea1da910 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/links.ts @@ -0,0 +1,77 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import languages from '../../languages' +import workspace from '../../workspace' +import path from 'path' +import { ListContext, ListItem } from '../../types' +import BasicList from '../basic' +import { DocumentLink, Location } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import { isParentFolder } from '../../util/fs' +import { CancellationToken } from 'vscode-languageserver-protocol' + +export default class LinksList extends BasicList { + public defaultAction = 'open' + public description = 'links of current buffer' + public name = 'links' + + constructor(nvim: Neovim) { + super(nvim) + + this.addAction('open', async item => { + let { target } = item.data + let uri = URI.parse(target) + if (uri.scheme.startsWith('http')) { + await nvim.call('coc#ui#open_url', target) + } else { + await workspace.jumpTo(target) + } + }) + + this.addAction('jump', async item => { + let { location } = item.data + await workspace.jumpTo(location.uri, location.range.start) + }) + } + + public async loadItems(context: ListContext, token: CancellationToken): Promise { + let buf = await context.window.buffer + let doc = workspace.getDocument(buf.id) + if (!doc) return null + let items: ListItem[] = [] + let links = await languages.getDocumentLinks(doc.textDocument, token) + if (token.isCancellationRequested) return null + if (links == null) throw new Error('Links provider not found.') + let res: DocumentLink[] = [] + for (let link of links) { + if (link.target) { + items.push({ + label: formatUri(link.target), + data: { + target: link.target, + location: Location.create(doc.uri, link.range) + } + }) + } else { + link = await languages.resolveDocumentLink(link, token) + if (link.target) { + items.push({ + label: formatUri(link.target), + data: { + target: link.target, + location: Location.create(doc.uri, link.range) + } + }) + } + res.push(link) + } + } + return items + } +} + +function formatUri(uri: string): string { + if (!uri.startsWith('file:')) return uri + let filepath = URI.parse(uri).fsPath + return isParentFolder(workspace.cwd, filepath) ? path.relative(workspace.cwd, filepath) : filepath +} diff --git a/sources_non_forked/coc.nvim/src/list/source/lists.ts b/sources_non_forked/coc.nvim/src/list/source/lists.ts new file mode 100644 index 00000000..1e416967 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/lists.ts @@ -0,0 +1,54 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { IList, ListContext, ListItem } from '../../types' +import BasicList from '../basic' +import Mru from '../../model/mru' +import { formatListItems, UnformattedListItem } from '../formatting' + +export default class ListsList extends BasicList { + public readonly name = 'lists' + public readonly defaultAction = 'open' + public readonly description = 'registered lists of coc.nvim' + private mru: Mru = new Mru('lists') + + constructor(nvim: Neovim, private readonly listMap: Map) { + super(nvim) + + this.addAction('open', async item => { + let { name } = item.data + await this.mru.add(name) + nvim.command(`CocList ${name}`, true) + }) + } + + public async loadItems(_context: ListContext): Promise { + let items: UnformattedListItem[] = [] + let mruList = await this.mru.load() + for (let list of this.listMap.values()) { + if (list.name == 'lists') continue + items.push({ + label: [list.name, ...(list.description ? [list.description] : [])], + data: { + name: list.name, + interactive: list.interactive, + score: score(mruList, list.name) + } + }) + } + items.sort((a, b) => b.data.score - a.data.score) + return formatListItems(this.alignColumns, items) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocListsDesc /\\t.*$/ contained containedin=CocListsLine', true) + nvim.command('highlight default link CocListsDesc Comment', true) + nvim.resumeNotification(false, true) + } +} + +function score(list: string[], key: string): number { + let idx = list.indexOf(key) + return idx == -1 ? -1 : list.length - idx +} diff --git a/sources_non_forked/coc.nvim/src/list/source/location.ts b/sources_non_forked/coc.nvim/src/list/source/location.ts new file mode 100644 index 00000000..b968bd6c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/location.ts @@ -0,0 +1,93 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Location, Range } from 'vscode-languageserver-types' +import path from 'path' +import { ListContext, ListItem, QuickfixItem, AnsiHighlight } from '../../types' +import BasicList from '../basic' +import workspace from '../../workspace' +import commands from '../../commands' +import { URI } from 'vscode-uri' +import { isParentFolder } from '../../util/fs' +import { CancellationToken } from 'vscode-languageserver-protocol' +import { byteLength } from '../../util/string' +const logger = require('../../util/logger')('list-location') + +export default class LocationList extends BasicList { + public defaultAction = 'open' + public description = 'show locations saved by g:coc_jump_locations variable' + public name = 'location' + + constructor(nvim: Neovim) { + super(nvim) + this.createAction({ + name: 'refactor', + multiple: true, + execute: async (items: ListItem[]) => { + let locations = items.map(o => o.location) + await commands.executeCommand('workspace.refactor', locations) + } + }) + this.addLocationActions() + } + + public async loadItems(context: ListContext, token: CancellationToken): Promise { + // filename, lnum, col, text, type + let locs = await this.nvim.getVar('coc_jump_locations') as QuickfixItem[] + if (token.isCancellationRequested) return [] + locs = locs || [] + locs.forEach(loc => { + if (!loc.uri) { + let fullpath = path.isAbsolute(loc.filename) ? loc.filename : path.join(context.cwd, loc.filename) + loc.uri = URI.file(fullpath).toString() + } + if (!loc.bufnr && workspace.getDocument(loc.uri) != null) { + loc.bufnr = workspace.getDocument(loc.uri).bufnr + } + if (!loc.range) { + let { lnum, col } = loc + loc.range = Range.create(lnum - 1, col - 1, lnum - 1, col - 1) + } else { + loc.lnum = loc.lnum || loc.range.start.line + 1 + loc.col = loc.col || loc.range.start.character + 1 + } + }) + let bufnr = context.buffer.id + let ignoreFilepath = locs.every(o => o.bufnr && bufnr && o.bufnr == bufnr) + let items: ListItem[] = locs.map(loc => { + let filename = ignoreFilepath ? '' : loc.filename + let filterText = `${filename}${loc.text.trim()}` + if (path.isAbsolute(filename)) { + filename = isParentFolder(context.cwd, filename) ? path.relative(context.cwd, filename) : filename + } + let pre = `${filename} |${loc.type ? loc.type + ' ' : ''}${loc.lnum} col ${loc.col}| ` + let highlight: AnsiHighlight + if (loc.range && loc.range.start.line == loc.range.end.line) { + let start = byteLength(pre) + byteLength(loc.text.slice(0, loc.range.start.character)) + let end = byteLength(pre) + byteLength(loc.text.slice(0, loc.range.end.character)) + highlight = { hlGroup: 'Search', span: [start, end] } + } + let label = pre + loc.text + return { + label, + location: Location.create(loc.uri, loc.range), + filterText, + ansiHighlights: highlight ? [highlight] : undefined + } as ListItem + }) + return items + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocLocationName /\\v^[^|]+/ contained containedin=CocLocationLine', true) + nvim.command('syntax match CocLocationPosition /\\v\\|\\w*\\s?\\d+\\scol\\s\\d+\\|/ contained containedin=CocLocationLine', true) + nvim.command('syntax match CocLocationError /Error/ contained containedin=CocLocationPosition', true) + nvim.command('syntax match CocLocationWarning /Warning/ contained containedin=CocLocationPosition', true) + nvim.command('highlight default link CocLocationName Directory', true) + nvim.command('highlight default link CocLocationPosition LineNr', true) + nvim.command('highlight default link CocLocationError Error', true) + nvim.command('highlight default link CocLocationWarning WarningMsg', true) + nvim.resumeNotification(false, true) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/source/outline.ts b/sources_non_forked/coc.nvim/src/list/source/outline.ts new file mode 100644 index 00000000..28e58097 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/outline.ts @@ -0,0 +1,161 @@ +'use strict' +import path from 'path' +import { DocumentSymbol, Location, Range, SymbolInformation } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import which from 'which' +import languages from '../../languages' +import Document from '../../model/document' +import { ListContext, ListItem, ListArgument } from '../../types' +import { runCommand } from '../../util' +import { writeFile } from '../../util/fs' +import workspace from '../../workspace' +import LocationList from './location' +import { getSymbolKind } from '../../util/convert' +import { CancellationToken } from 'vscode-languageserver-protocol' +import { formatListItems, UnformattedListItem } from '../formatting' +const logger = require('../../util/logger')('list-symbols') + +function getFilterText(s: DocumentSymbol | SymbolInformation, kind: string | null): string { + return `${s.name}${kind ? ` ${kind}` : ''}` +} + +export default class Outline extends LocationList { + public readonly description = 'symbols of current document' + public name = 'outline' + public options: ListArgument[] = [{ + name: '-k, -kind KIND', + hasValue: true, + description: 'filter symbol by kind', + }] + + public async loadItems(context: ListContext, token: CancellationToken): Promise { + let buf = await context.window.buffer + let document = workspace.getDocument(buf.id) + if (!document) return null + let config = this.getConfig() + let ctagsFilestypes = config.get('ctagsFilestypes', []) + let symbols: DocumentSymbol[] | SymbolInformation[] | null + let args = this.parseArguments(context.args) + if (!ctagsFilestypes.includes(document.filetype)) { + symbols = await languages.getDocumentSymbol(document.textDocument, token) + } + if (token.isCancellationRequested) return [] + if (!symbols) return await this.loadCtagsSymbols(document) + if (symbols.length == 0) return [] + let filterKind = args.kind ? (args.kind as string).toLowerCase() : null + let items: UnformattedListItem[] = [] + let isSymbols = !symbols[0].hasOwnProperty('location') + if (isSymbols) { + // eslint-disable-next-line no-inner-declarations + function addSymbols(symbols: DocumentSymbol[], level = 0): void { + symbols.sort(sortSymbols) + for (let s of symbols) { + let kind = getSymbolKind(s.kind) + let location = Location.create(document.uri, s.selectionRange) + items.push({ + label: [`${'| '.repeat(level)}${s.name}`, `[${kind}]`, `${s.range.start.line + 1}`], + filterText: getFilterText(s, args.kind == '' ? kind : null), + location, + data: { kind } + }) + if (s.children && s.children.length) { + addSymbols(s.children, level + 1) + } + } + } + addSymbols(symbols as DocumentSymbol[]) + if (filterKind) { + items = items.filter(o => o.data.kind.toLowerCase().indexOf(filterKind) == 0) + } + } else { + (symbols as SymbolInformation[]).sort((a, b) => { + let sa = a.location.range.start + let sb = b.location.range.start + let d = sa.line - sb.line + return d == 0 ? sa.character - sb.character : d + }) + for (let s of symbols as SymbolInformation[]) { + let kind = getSymbolKind(s.kind) + if (s.name.endsWith(') callback')) continue + if (filterKind && !kind.toLowerCase().startsWith(filterKind)) { + continue + } + if (s.location.uri === undefined) { + s.location.uri = document.uri + } + items.push({ + label: [s.name, `[${kind}]`, `${s.location.range.start.line + 1}`], + filterText: getFilterText(s, args.kind == '' ? kind : null), + location: s.location + }) + } + } + return formatListItems(this.alignColumns, items) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocOutlineName /\\v\\s?[^\\t]+\\s/ contained containedin=CocOutlineLine', true) + nvim.command('syntax match CocOutlineIndentLine /\\v\\|/ contained containedin=CocOutlineLine,CocOutlineName', true) + nvim.command('syntax match CocOutlineKind /\\[\\w\\+\\]/ contained containedin=CocOutlineLine', true) + nvim.command('syntax match CocOutlineLine /\\d\\+$/ contained containedin=CocOutlineLine', true) + nvim.command('highlight default link CocOutlineName Normal', true) + nvim.command('highlight default link CocOutlineIndentLine Comment', true) + nvim.command('highlight default link CocOutlineKind Typedef', true) + nvim.command('highlight default link CocOutlineLine Comment', true) + nvim.resumeNotification(false, true) + } + + public async loadCtagsSymbols(document: Document): Promise { + if (!which.sync('ctags', { nothrow: true })) { + return [] + } + let uri = URI.parse(document.uri) + let extname = path.extname(uri.fsPath) + let content = '' + let tempname = await this.nvim.call('tempname') + let filepath = `${tempname}.${extname}` + let escaped = await this.nvim.call('fnameescape', filepath) + await writeFile(escaped, document.getDocumentContent()) + try { + content = await runCommand(`ctags -f - --excmd=number --language-force=${document.filetype} ${escaped}`) + } catch (e) { + // noop + } + if (!content.trim().length) { + content = await runCommand(`ctags -f - --excmd=number ${escaped}`) + } + content = content.trim() + if (!content) return [] + let lines = content.split(/\r?\n/) + let items: ListItem[] = [] + for (let line of lines) { + let parts = line.split('\t') + if (parts.length < 4) continue + let lnum = Number(parts[2].replace(/;"$/, '')) + let text = document.getline(lnum - 1) + if (!text) continue + let idx = text.indexOf(parts[0]) + let start = idx == -1 ? 0 : idx + let range: Range = Range.create(lnum - 1, start, lnum - 1, start + parts[0].length) + items.push({ + label: `${parts[0]} [${parts[3]}] ${lnum}`, + filterText: parts[0], + location: Location.create(document.uri, range), + data: { line: lnum } + }) + } + items.sort((a, b) => a.data.line - b.data.line) + return items + } +} + +function sortSymbols(a: DocumentSymbol, b: DocumentSymbol): number { + let ra = a.selectionRange + let rb = b.selectionRange + if (ra.start.line != rb.start.line) { + return ra.start.line - rb.start.line + } + return ra.start.character - rb.start.character +} diff --git a/sources_non_forked/coc.nvim/src/list/source/services.ts b/sources_non_forked/coc.nvim/src/list/source/services.ts new file mode 100644 index 00000000..e327c7c2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/services.ts @@ -0,0 +1,49 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import services from '../../services' +import { ListContext, ListItem } from '../../types' +import BasicList from '../basic' +import { wait } from '../../util' +import { formatListItems } from '../formatting' + +export default class ServicesList extends BasicList { + public defaultAction = 'toggle' + public description = 'registered services of coc.nvim' + public name = 'services' + + constructor(nvim: Neovim) { + super(nvim) + + this.addAction('toggle', async item => { + let { id } = item.data + await services.toggle(id) + await wait(100) + }, { persist: true, reload: true }) + } + + public async loadItems(_context: ListContext): Promise { + let stats = services.getServiceStats() + stats.sort((a, b) => a.id > b.id ? -1 : 1) + return formatListItems(this.alignColumns, stats.map(stat => { + let prefix = stat.state == 'running' ? '*' : ' ' + return { + label: [prefix, stat.id, `[${stat.state}]`, stat.languageIds.join(', ')], + data: { id: stat.id } + } + })) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocServicesPrefix /\\v^./ contained containedin=CocServicesLine', true) + nvim.command('syntax match CocServicesName /\\v%3c\\S+/ contained containedin=CocServicesLine', true) + nvim.command('syntax match CocServicesStat /\\v\\t\\[\\w+\\]/ contained containedin=CocServicesLine', true) + nvim.command('syntax match CocServicesLanguages /\\v(\\])@<=.*$/ contained containedin=CocServicesLine', true) + nvim.command('highlight default link CocServicesPrefix Special', true) + nvim.command('highlight default link CocServicesName Type', true) + nvim.command('highlight default link CocServicesStat Statement', true) + nvim.command('highlight default link CocServicesLanguages Comment', true) + nvim.resumeNotification(false, true) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/source/sources.ts b/sources_non_forked/coc.nvim/src/list/source/sources.ts new file mode 100644 index 00000000..27febf0f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/sources.ts @@ -0,0 +1,77 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Location, Range } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import sources from '../../sources' +import { ListContext, ListItem } from '../../types' +import BasicList from '../basic' +const logger = require('../../util/logger')('list-sources') + +export default class SourcesList extends BasicList { + public readonly defaultAction = 'toggle' + public readonly description = 'registered completion sources' + public readonly name = 'sources' + + constructor(nvim: Neovim) { + super(nvim) + + this.addAction('toggle', async item => { + let { name } = item.data + sources.toggleSource(name) + }, { persist: true, reload: true }) + + this.addAction('refresh', async item => { + let { name } = item.data + await sources.refresh(name) + }, { persist: true, reload: true }) + + this.addAction('open', async (item, context) => { + let { location } = item + if (location) await this.jumpTo(location, null, context) + }) + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async loadItems(context: ListContext): Promise { + let stats = sources.sourceStats() + stats.sort((a, b) => { + if (a.type != b.type) return a.type < b.type ? 1 : -1 + return a.name > b.name ? -1 : 1 + }) + return stats.map(stat => { + let prefix = stat.disabled ? ' ' : '*' + let location: Location + if (stat.filepath) { + location = Location.create(URI.file(stat.filepath).toString(), Range.create(0, 0, 0, 0)) + } + return { + label: `${prefix} ${fixWidth(stat.name, 22)} ${fixWidth('[' + stat.shortcut + ']', 10)} ${fixWidth(stat.triggerCharacters.join(''), 10)} ${fixWidth(stat.priority.toString(), 3)} ${stat.filetypes.join(',')}`, + location, + data: { name: stat.name } + } + }) + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocSourcesPrefix /\\v^./ contained containedin=CocSourcesLine', true) + nvim.command('syntax match CocSourcesName /\\v%3c\\S+/ contained containedin=CocSourcesLine', true) + nvim.command('syntax match CocSourcesType /\\v%25v.*%36v/ contained containedin=CocSourcesLine', true) + nvim.command('syntax match CocSourcesPriority /\\v%46v.*%50v/ contained containedin=CocSourcesLine', true) + nvim.command('syntax match CocSourcesFileTypes /\\v\\S+$/ contained containedin=CocSourcesLine', true) + nvim.command('highlight default link CocSourcesPrefix Special', true) + nvim.command('highlight default link CocSourcesName Type', true) + nvim.command('highlight default link CocSourcesPriority Number', true) + nvim.command('highlight default link CocSourcesFileTypes Comment', true) + nvim.command('highlight default link CocSourcesType Statement', true) + nvim.resumeNotification(false, true) + } +} + +function fixWidth(str: string, width: number): string { + if (str.length > width) { + return str.slice(0, width - 1) + '.' + } + return str + ' '.repeat(width - str.length) +} diff --git a/sources_non_forked/coc.nvim/src/list/source/symbols.ts b/sources_non_forked/coc.nvim/src/list/source/symbols.ts new file mode 100644 index 00000000..faa2b2a3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/source/symbols.ts @@ -0,0 +1,103 @@ +'use strict' +import path from 'path' +import minimatch from 'minimatch' +import { URI } from 'vscode-uri' +import languages from '../../languages' +import { ListContext, ListItem } from '../../types' +import workspace from '../../workspace' +import LocationList from './location' +import { getSymbolKind } from '../../util/convert' +import { isParentFolder } from '../../util/fs' +import { score } from '../../util/fzy' +import { CancellationToken, CancellationTokenSource } from 'vscode-languageserver-protocol' +import { formatListItems, UnformattedListItem } from '../formatting' +const logger = require('../../util/logger')('list-symbols') + +export default class Symbols extends LocationList { + public readonly interactive = true + public readonly description = 'search workspace symbols' + public readonly detail = 'Symbols list is provided by server, it works on interactive mode only.' + private cwd: string + public name = 'symbols' + public options = [{ + name: '-k, -kind KIND', + description: 'Filter symbols by kind.', + hasValue: true + }] + + public async loadItems(context: ListContext, token: CancellationToken): Promise { + let { input } = context + this.cwd = context.cwd + let args = this.parseArguments(context.args) + let filterKind = args.kind ? (args.kind as string).toLowerCase() : '' + if (!context.options.interactive) { + throw new Error('Symbols only works on interactive mode') + } + let symbols = await languages.getWorkspaceSymbols(input, token) + if (!symbols) { + throw new Error('No workspace symbols provider registered') + } + let config = this.getConfig() + let excludes = config.get('excludes', []) + let items: UnformattedListItem[] = [] + for (let s of symbols) { + let kind = getSymbolKind(s.kind) + if (filterKind && kind.toLowerCase() != filterKind) { + continue + } + let file = URI.parse(s.location.uri).fsPath + if (isParentFolder(workspace.cwd, file)) { + file = path.relative(workspace.cwd, file) + } + if (excludes.some(p => minimatch(file, p))) { + continue + } + items.push({ + label: [s.name, `[${kind}]`, file], + filterText: `${s.name}`, + location: s.location, + data: { original: s, kind: s.kind, file, score: score(input, s.name) } + }) + } + items.sort((a, b) => { + if (a.data.score != b.data.score) { + return b.data.score - a.data.score + } + if (a.data.kind != b.data.kind) { + return a.data.kind - b.data.kind + } + return a.data.file.length - b.data.file.length + }) + return formatListItems(this.alignColumns, items) + } + + public async resolveItem(item: ListItem): Promise { + let s = item.data.original + if (!s) return null + let tokenSource = new CancellationTokenSource() + let resolved = await languages.resolveWorkspaceSymbol(s, tokenSource.token) + if (!resolved) return null + let kind = getSymbolKind(resolved.kind) + let file = URI.parse(resolved.location.uri).fsPath + if (isParentFolder(this.cwd, file)) { + file = path.relative(this.cwd, file) + } + return { + label: `${s.name}\t[${kind}]\t${file}`, + filterText: `${s.name}`, + location: s.location + } + } + + public doHighlight(): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command('syntax match CocSymbolsName /\\v^\\s*\\S+/ contained containedin=CocSymbolsLine', true) + nvim.command('syntax match CocSymbolsKind /\\[\\w\\+\\]\\s*\\t/ contained containedin=CocSymbolsLine', true) + nvim.command('syntax match CocSymbolsFile /\\S\\+$/ contained containedin=CocSymbolsLine', true) + nvim.command('highlight default link CocSymbolsName Normal', true) + nvim.command('highlight default link CocSymbolsKind Typedef', true) + nvim.command('highlight default link CocSymbolsFile Comment', true) + nvim.resumeNotification(false, true) + } +} diff --git a/sources_non_forked/coc.nvim/src/list/ui.ts b/sources_non_forked/coc.nvim/src/list/ui.ts new file mode 100644 index 00000000..a6f5a0a7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/ui.ts @@ -0,0 +1,512 @@ +'use strict' +import { Buffer, Neovim, Window } from '@chemzqm/neovim' +import debounce from 'debounce' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { HighlightItem, ListItem, ListItemWithHighlights, ListOptions } from '../types' +import { disposeAll } from '../util' +import { Mutex } from '../util/mutex' +import workspace from '../workspace' +import ListConfiguration from './configuration' +const logger = require('../util/logger')('list-ui') + +export type MouseEvent = 'mouseDown' | 'mouseDrag' | 'mouseUp' | 'doubleClick' + +export interface MousePosition { + winid: number + lnum: number + col: number + current: boolean +} + +export interface HighlightGroup { + hlGroup: string + priority: number + pos: [number, number, number] +} + +export default class ListUI { + private window: Window + private height: number + public tabnr: number + private newTab = false + private reversed = false + private buffer: Buffer + private currIndex = 0 + private items: ListItemWithHighlights[] = [] + private disposables: Disposable[] = [] + private signOffset: number + private selected: Set = new Set() + private mouseDown: MousePosition + private mutex: Mutex = new Mutex() + private _onDidChangeLine = new Emitter() + private _onDidOpen = new Emitter() + private _onDidClose = new Emitter() + private _onDidLineChange = new Emitter() + private _onDoubleClick = new Emitter() + public readonly onDidChangeLine: Event = this._onDidChangeLine.event + public readonly onDidLineChange: Event = this._onDidLineChange.event + public readonly onDidOpen: Event = this._onDidOpen.event + public readonly onDidClose: Event = this._onDidClose.event + public readonly onDidDoubleClick: Event = this._onDoubleClick.event + + constructor( + private nvim: Neovim, + private name: string, + private listOptions: ListOptions, + private config: ListConfiguration + ) { + this.signOffset = config.get('signOffset') + this.newTab = listOptions.position == 'tab' + this.reversed = listOptions.reverse === true + events.on('BufWinLeave', async bufnr => { + if (bufnr != this.bufnr || this.window == null) return + this.window = null + this._onDidClose.fire(bufnr) + }, null, this.disposables) + events.on('CursorMoved', async (bufnr, cursor) => { + if (bufnr != this.bufnr) return + let idx = this.lnumToIndex(cursor[0]) + this.onLineChange(idx) + }, null, this.disposables) + let debounced = debounce(async bufnr => { + if (bufnr != this.bufnr) return + let [winid, start, end] = await nvim.eval('[win_getid(),line("w0"),line("w$")]') as number[] + if (end < 300 || winid != this.winid) return + let h = end - start + 1 + let s = this.lnumToIndex(start) + let e = this.lnumToIndex(start + h * 2) + nvim.pauseNotification() + this.doHighlight(s, e) + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + }, global.hasOwnProperty('__TEST__') ? 20 : 100) + this.disposables.push({ + dispose: () => { + debounced.clear() + } + }) + events.on('CursorMoved', debounced, null, this.disposables) + } + + public lnumToIndex(lnum: number): number { + let { reversed, length } = this + if (!reversed) return lnum - 1 + return Math.max(0, length - lnum) + } + + public indexToLnum(index: number): number { + let { reversed, length } = this + if (!reversed) return Math.min(index + 1, length) + return Math.max(Math.min(length, length - index), 1) + } + + public get bufnr(): number | undefined { + return this.buffer?.id + } + + public get winid(): number | undefined { + return this.window?.id + } + private get limitLines(): number { + return this.config.get('limitLines', Infinity) + } + + private onLineChange(index: number): void { + if (this.currIndex == index) return + this.currIndex = index + this._onDidChangeLine.fire(index) + } + + public set index(n: number) { + if (n < 0 || n >= this.items.length) return + let { nvim } = this + let lnum = this.indexToLnum(n) + nvim.pauseNotification() + this.setCursor(lnum) + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + + public get index(): number { + return this.currIndex + } + + public getItem(index: number): ListItem | undefined { + return this.items[index] + } + + public get item(): Promise { + let { window } = this + if (!window) return Promise.resolve(null) + return window.cursor.then(cursor => { + this.currIndex = this.lnumToIndex(cursor[0]) + return this.items[this.currIndex] + }) + } + + public async echoMessage(item: ListItem): Promise { + let { items } = this + let idx = items.indexOf(item) + let msg = `[${idx + 1}/${items.length}] ${item.label || ''}` + this.nvim.callTimer('coc#ui#echo_lines', [[msg]], true) + } + + public updateItem(item: ListItemWithHighlights, index: number, labelChanged: boolean): void { + if (!this.buffer || index >= this.length) return + let prev = this.items[index] + Object.assign(prev, item, { resolved: true }) + if (!labelChanged) return + let { nvim } = this + let lnum = this.indexToLnum(index) + nvim.pauseNotification() + this.buffer.setOption('modifiable', true, true) + nvim.call('setbufline', [this.bufnr, lnum, prev.label], true) + this.doHighlight(index, index + 1) + this.buffer.setOption('modifiable', false, true) + nvim.resumeNotification(true, true) + } + + public async getItems(): Promise { + if (this.length == 0 || !this.window) return [] + let mode = await this.nvim.call('mode') + if (mode == 'v' || mode == 'V') { + let [start, end] = await this.getSelectedRange() + let res: ListItem[] = [] + for (let i = start; i <= end; i++) { + let idx = this.lnumToIndex(i) + let item = this.items[idx] + if (item) res.push(item) + } + return res + } + let { selectedItems } = this + if (selectedItems.length) return selectedItems + let item = await this.item + return item == null ? [] : [item] + } + + public async onMouse(event: MouseEvent): Promise { + let { nvim, window } = this + if (!window) return + let [winid, lnum, col] = await nvim.eval(`[v:mouse_winid,v:mouse_lnum,v:mouse_col]`) as [number, number, number] + if (event == 'mouseDown') { + this.mouseDown = { winid, lnum, col, current: winid == window.id } + return + } + let current = winid == window.id + if (current && event == 'doubleClick') { + this.setCursor(lnum) + this._onDoubleClick.fire() + } + if (current && event == 'mouseDrag') { + if (!this.mouseDown) return + await this.selectLines(this.mouseDown.lnum, lnum) + } else if (current && event == 'mouseUp') { + if (!this.mouseDown) return + if (this.mouseDown.lnum == lnum) { + this.setCursor(lnum) + nvim.command('redraw', true) + } else { + await this.selectLines(this.mouseDown.lnum, lnum) + } + } else if (!current && event == 'mouseUp') { + nvim.pauseNotification() + nvim.call('win_gotoid', winid, true) + nvim.call('cursor', [lnum, col], true) + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + } + + public async resume(): Promise { + let { items, selected, nvim } = this + await this.drawItems(items, this.height, true) + if (!selected.size || !this.buffer) return + nvim.pauseNotification() + for (let lnum of selected) { + this.buffer?.placeSign({ lnum, id: this.signOffset + lnum, name: 'CocSelected', group: 'coc-list' }) + } + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + + public async toggleSelection(): Promise { + let { nvim, reversed } = this + await nvim.call('win_gotoid', [this.winid]) + let lnum = await nvim.call('line', '.') + let mode = await nvim.call('mode') + if (mode == 'v' || mode == 'V') { + let [start, end] = await this.getSelectedRange() + let reverse = start > end + if (reverse) [start, end] = [end, start] + for (let i = start; i <= end; i++) { + this.toggleLine(i) + } + this.setCursor(end) + nvim.command('redraw', true) + await nvim.resumeNotification() + return + } + nvim.pauseNotification() + this.toggleLine(lnum) + this.setCursor(reversed ? lnum - 1 : lnum + 1) + nvim.command('redraw', true) + await nvim.resumeNotification() + } + + private toggleLine(lnum: number): void { + let { selected, buffer, signOffset } = this + let exists = selected.has(lnum) + if (!exists) { + selected.add(lnum) + buffer.placeSign({ lnum, id: signOffset + lnum, name: 'CocSelected', group: 'coc-list' }) + } else { + selected.delete(lnum) + buffer.unplaceSign({ id: signOffset + lnum, group: 'coc-list' }) + } + } + + public async selectLines(start: number, end: number): Promise { + let { nvim, signOffset, buffer, length } = this + this.clearSelection() + let { selected } = this + nvim.pauseNotification() + let reverse = start > end + if (reverse) [start, end] = [end, start] + for (let i = start; i <= end; i++) { + if (i > length) break + selected.add(i) + buffer.placeSign({ lnum: i, id: signOffset + i, name: 'CocSelected', group: 'coc-list' }) + } + this.setCursor(end) + nvim.command('redraw', true) + await nvim.resumeNotification() + } + + public async selectAll(): Promise { + let { length } = this + if (length > 0) await this.selectLines(1, length) + } + + public clearSelection(): void { + let { selected, buffer } = this + if (selected.size > 0) { + buffer?.unplaceSign({ group: 'coc-list' }) + this.selected.clear() + } + } + + public get ready(): Promise { + if (this.window) return Promise.resolve() + return new Promise(resolve => { + let disposable = this.onDidLineChange(() => { + disposable.dispose() + resolve() + }) + }) + } + + public async drawItems(items: ListItem[], height: number, reload = false): Promise { + const { nvim, name, listOptions } = this + await this.mutex.use(async () => { + this.items = items.length > this.limitLines ? items.slice(0, this.limitLines) : items + if (!this.window) { + let { position, numberSelect } = listOptions + let [bufnr, winid, tabnr] = await nvim.call('coc#list#create', [position, height, name, numberSelect]) + this.tabnr = tabnr + this.height = height + this.buffer = nvim.createBuffer(bufnr) + let win = this.window = nvim.createWindow(winid) + let statusSegments = this.config.get('statusLineSegments') + if (statusSegments) win.setOption('statusline', statusSegments.join(" "), true) + this._onDidOpen.fire(this.bufnr) + } + const lines: string[] = [] + let selectIndex = 0 + this.items.forEach((item, idx) => { + lines.push(item.label) + if (!reload && selectIndex == 0 && item.preselect) selectIndex = idx + }) + let newIndex = reload ? this.currIndex : selectIndex + this.setLines(lines, 0, newIndex) + this._onDidLineChange.fire() + }) + } + + public async appendItems(items: ListItem[]): Promise { + if (!this.window || items.length === 0) return + await this.mutex.use(async () => { + let curr = this.items.length + let remain = this.limitLines - curr + if (remain > 0) { + let append = remain < items.length ? items.slice(0, remain) : items + this.items = this.items.concat(append) + this.setLines(append.map(item => item.label), append.length, this.currIndex) + } + }) + } + + private setLines(lines: string[], append: number, index: number): void { + let { nvim, buffer, window, reversed, newTab } = this + if (!buffer || !window) return + nvim.pauseNotification() + if (!append) { + nvim.call('coc#compat#clear_matches', [window.id], true) + if (!lines.length) { + lines = ['No results, press ? on normal mode to get help.'] + nvim.call('coc#compat#matchaddpos', ['Comment', [[1]], 99, window.id], true) + } + } + buffer.setOption('modifiable', true, true) + if (reversed) { + let replacement = lines.reverse() + if (append) { + nvim.call('coc#compat#prepend_lines', [buffer.id, replacement], true) + } else { + buffer.setLines(replacement, { start: 0, end: -1, strictIndexing: false }, true) + } + } else { + buffer.setLines(lines, { start: append ? -1 : 0, end: -1, strictIndexing: false }, true) + } + buffer.setOption('modifiable', false, true) + if (reversed && !newTab) { + let maxHeight = this.config.get('height', 10) + nvim.call('coc#window#set_height', [window.id, Math.max(Math.min(maxHeight, this.length), 1)], true) + } + if (index > this.items.length - 1) index = 0 + if (index == 0) { + if (append == 0) { + this.doHighlight(0, 299) + } else { + let s = this.length - append - 1 + if (s < 300) this.doHighlight(s, Math.min(299, this.length - 1)) + } + } else { + let height = newTab ? workspace.env.lines : this.height + this.doHighlight(Math.max(0, index - height), Math.min(index + height + 1, this.length - 1)) + } + if (!append) { + this.currIndex = index + let lnum = this.indexToLnum(index) + window.setCursor([lnum, 0], true) + nvim.call('coc#list#select', [buffer.id, lnum], true) + } + if (reversed) nvim.command('normal! zb', true) + nvim.command('redraws', true) + nvim.resumeNotification(true, true) + } + + public restoreWindow(): void { + if (this.newTab) return + let { winid, height } = this + if (winid && height) { + this.nvim.call('coc#window#set_height', [winid, height], true) + } + } + + public get length(): number { + return this.items.length + } + + public get selectedItems(): ListItem[] { + let { selected, items } = this + let res: ListItem[] = [] + for (let i of selected) { + let idx = this.lnumToIndex(i) + if (items[i - 1]) res.push(items[idx]) + } + return res + } + + private doHighlight(start: number, end: number): void { + let { items, reversed, length, buffer } = this + if (!buffer) return + const highlightItems: HighlightItem[] = [] + const iterate = (i: number): void => { + let lnum = this.indexToLnum(i) - 1 + let { ansiHighlights, highlights } = items[i] + if (ansiHighlights) { + for (let hi of ansiHighlights) { + let { span, hlGroup } = hi + highlightItems.push({ hlGroup, lnum, colStart: span[0], colEnd: span[1] }) + } + } + if (highlights && Array.isArray(highlights.spans)) { + let { spans, hlGroup } = highlights + for (let span of spans) { + hlGroup = hlGroup ?? 'CocListSearch' + highlightItems.push({ hlGroup, lnum, colStart: span[0], colEnd: span[1] }) + } + } + } + if (reversed) { + for (let i = Math.min(end, length - 1); i >= start; i--) { + iterate(i) + } + } else { + for (let i = start; i <= Math.min(end, length - 1); i++) { + iterate(i) + } + } + start = this.indexToLnum(start) - 1 + end = this.indexToLnum(end) - 1 + if (start > end) { + [start, end] = [end, start] + } + if (highlightItems.length == 0) return + buffer.updateHighlights('list', highlightItems, { start, end: end + 1, priority: 99 }) + } + + public setCursor(lnum: number, col = 0): void { + let { items } = this + let max = items.length == 0 ? 1 : items.length + if (lnum > max) return + // change index since CursorMoved event not fired (seems bug of neovim)! + let idx = this.lnumToIndex(lnum) + this.onLineChange(idx) + this.window?.setCursor([lnum, col], true) + this.nvim.call('coc#list#select', [this.bufnr, lnum], true) + } + + public moveUp(): void { + let { index, reversed } = this + this.index = reversed ? index + 1 : index - 1 + } + + public moveDown(): void { + let { index, reversed } = this + this.index = reversed ? index - 1 : index + 1 + } + + private async getSelectedRange(): Promise<[number, number]> { + let { nvim } = this + await nvim.call('coc#prompt#stop_prompt', ['list']) + await nvim.eval('feedkeys("\\", "in")') + let [, start] = await nvim.call('getpos', "'<") + let [, end] = await nvim.call('getpos', "'>") + this.nvim.call('coc#prompt#start_prompt', ['list'], true) + return [start, end] + } + + public reset(): void { + if (this.window) { + this.window = null + this.buffer = null + this.tabnr = undefined + } + } + + public dispose(): void { + disposeAll(this.disposables) + this.nvim.call('coc#window#close', [this.winid || -1], true) + this.window = null + this.buffer = null + this.items = [] + this._onDidChangeLine.dispose() + this._onDidOpen.dispose() + this._onDidClose.dispose() + this._onDidLineChange.dispose() + this._onDoubleClick.dispose() + } +} diff --git a/sources_non_forked/coc.nvim/src/list/worker.ts b/sources_non_forked/coc.nvim/src/list/worker.ts new file mode 100644 index 00000000..5eaad76a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/list/worker.ts @@ -0,0 +1,420 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, CancellationTokenSource, Emitter, Event } from 'vscode-languageserver-protocol' +import { IList, ListContext, ListHighlights, ListItem, ListItemsEvent, ListItemWithHighlights, ListOptions, ListTask } from '../types' +import { parseAnsiHighlights } from '../util/ansiparse' +import { filter } from '../util/async' +import { patchLine } from '../util/diff' +import { hasMatch, positions, score } from '../util/fzy' +import { Mutex } from '../util/mutex' +import { getMatchResult } from '../util/score' +import { byteIndex, byteLength } from '../util/string' +import Prompt from './prompt' +const logger = require('../util/logger')('list-worker') +const controlCode = '\x1b' + +export interface WorkerConfiguration { + interactiveDebounceTime: number + extendedSearchMode: boolean +} + +export interface FilterOption { + append?: boolean + reload?: boolean +} + +export type OnFilter = (arr: ListItemWithHighlights[], finished: boolean, sort?: boolean) => void + +// perform loading task +export default class Worker { + private _loading = false + private _finished = false + private mutex: Mutex = new Mutex() + private filteredCount: number + private totalItems: ListItem[] = [] + private tokenSource: CancellationTokenSource + private filterTokenSource: CancellationTokenSource + private _onDidChangeItems = new Emitter() + private _onDidChangeLoading = new Emitter() + public readonly onDidChangeItems: Event = this._onDidChangeItems.event + public readonly onDidChangeLoading: Event = this._onDidChangeLoading.event + + constructor( + private nvim: Neovim, + private list: IList, + private prompt: Prompt, + private listOptions: ListOptions, + private config: WorkerConfiguration + ) { + } + + private set loading(loading: boolean) { + if (this._loading == loading) return + this._loading = loading + this._onDidChangeLoading.fire(loading) + } + + public get isLoading(): boolean { + return this._loading + } + + public async loadItems(context: ListContext, reload = false): Promise { + this.cancelFilter() + this.filteredCount = 0 + this._finished = false + let { list, listOptions } = this + this.loading = true + let { interactive } = listOptions + this.tokenSource = new CancellationTokenSource() + let token = this.tokenSource.token + let items = await list.loadItems(context, token) + if (token.isCancellationRequested) return + items = items ?? [] + if (Array.isArray(items)) { + this.tokenSource = null + this.totalItems = items + this.loading = false + this._finished = true + let filtered: ListItemWithHighlights[] + if (!interactive) { + let tokenSource = this.filterTokenSource = new CancellationTokenSource() + await this.mutex.use(async () => { + let token = tokenSource.token + if (token.isCancellationRequested) return + await this.filterItems(items as ListItem[], { reload }, token) + }) + } else { + filtered = this.convertToHighlightItems(items) + this._onDidChangeItems.fire({ + items: filtered, + reload, + finished: true + }) + } + } else { + let task = items as ListTask + let totalItems = this.totalItems = [] + let taken = 0 + let currInput = context.input + let filtering = false + this.filterTokenSource = new CancellationTokenSource() + let _onData = async (finished?: boolean) => { + filtering = true + await this.mutex.use(async () => { + let inputChanged = this.input != currInput + if (inputChanged) { + currInput = this.input + taken = this.filteredCount ?? 0 + } + if (taken >= totalItems.length) return + let append = taken > 0 + let remain = totalItems.slice(taken) + taken = totalItems.length + if (!interactive) { + let tokenSource = this.filterTokenSource + if (tokenSource && !tokenSource.token.isCancellationRequested) { + await this.filterItems(remain, { append, reload }, tokenSource.token) + } + } else { + let items = this.convertToHighlightItems(remain) + this._onDidChangeItems.fire({ items, append, reload, finished }) + } + }) + filtering = false + } + let promise: Promise = Promise.resolve() + let interval = setInterval(() => { + if (filtering) return + promise = _onData() + }, 50) + task.on('data', item => { + if (token.isCancellationRequested) return + totalItems.push(item) + }) + let onEnd = () => { + if (task == null) return + this.tokenSource = null + task = null + this.loading = false + this._finished = true + disposable.dispose() + clearInterval(interval) + promise.then(() => { + if (token.isCancellationRequested) return + if (totalItems.length == 0) { + this._onDidChangeItems.fire({ items: [], append: false, reload, finished: true }) + return + } + return _onData(true) + }).catch(e => { + logger.error('Error on filter', e) + }) + } + let disposable = token.onCancellationRequested(() => { + task?.dispose() + onEnd() + }) + task.on('error', async (error: Error | string) => { + if (task == null) return + task = null + this.tokenSource = null + this.loading = false + disposable.dispose() + clearInterval(interval) + this.nvim.call('coc#prompt#stop_prompt', ['list'], true) + this.nvim.echoError(`Task error: ${error.toString()}`) + logger.error('Task error:', error) + }) + task.on('end', onEnd) + } + } + + /* + * Draw all items with filter if necessary + */ + public async drawItems(): Promise { + let { totalItems } = this + if (totalItems.length === 0) return + this.cancelFilter() + let tokenSource = this.filterTokenSource = new CancellationTokenSource() + let token = tokenSource.token + await this.mutex.use(async () => { + if (token.isCancellationRequested) return + let { totalItems } = this + this.filteredCount = totalItems.length + await this.filterItems(totalItems, {}, tokenSource.token) + }) + } + + public cancelFilter(): void { + if (this.filterTokenSource) { + this.filterTokenSource.cancel() + this.filterTokenSource = null + } + } + + public stop(): void { + this.cancelFilter() + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource = null + } + this.loading = false + } + + public get length(): number { + return this.totalItems.length + } + + private get input(): string { + return this.prompt.input + } + + /** + * Add highlights for interactive list + */ + private convertToHighlightItems(items: ListItem[]): ListItemWithHighlights[] { + let input = this.input ?? '' + let res = items.map(item => { + this.convertItemLabel(item) + let highlights = input.length > 0 ? getItemHighlights(input, item) : undefined + return Object.assign({}, item, { highlights }) + }) + return res + } + + private async filterItemsByInclude(inputs: string[], items: ListItem[], token: CancellationToken, onFilter: OnFilter): Promise { + let { ignorecase } = this.listOptions + if (ignorecase) inputs = inputs.map(s => s.toLowerCase()) + await filter(items, item => { + this.convertItemLabel(item) + let spans: [number, number][] = [] + let filterLabel = getFilterLabel(item) + let match = true + for (let input of inputs) { + let idx = ignorecase ? filterLabel.toLowerCase().indexOf(input) : filterLabel.indexOf(input) + if (idx == -1) { + match = false + break + } + spans.push([byteIndex(filterLabel, idx), byteIndex(filterLabel, idx + byteLength(input))]) + } + if (!match) return false + return { highlights: { spans } } + }, onFilter, token) + } + + private async filterItemsByRegex(inputs: string[], items: ListItem[], token: CancellationToken, onFilter: OnFilter): Promise { + let { ignorecase } = this.listOptions + let flags = ignorecase ? 'iu' : 'u' + let regexes = inputs.reduce((p, c) => { + try { + p.push(new RegExp(c, flags)) + } catch (e) {} + return p + }, []) + await filter(items, item => { + this.convertItemLabel(item) + let spans: [number, number][] = [] + let filterLabel = getFilterLabel(item) + let match = true + for (let regex of regexes) { + let ms = filterLabel.match(regex) + if (ms == null) { + match = false + break + } + spans.push([byteIndex(filterLabel, ms.index), byteIndex(filterLabel, ms.index + byteLength(ms[0]))]) + } + if (!match) return false + return { highlights: { spans } } + }, onFilter, token) + } + + private async filterItemsByFuzzyMatch(inputs: string[], items: ListItem[], token: CancellationToken, onFilter: OnFilter): Promise { + let { sort } = this.listOptions + let idx = 0 + await filter(items, item => { + this.convertItemLabel(item) + let filterText = item.filterText || item.label + let matchScore = 0 + let matches: number[] = [] + let filterLabel = getFilterLabel(item) + let match = true + for (let input of inputs) { + if (!hasMatch(input, filterText)) { + match = false + break + } + matches.push(...positions(input, filterLabel)) + if (sort) matchScore += score(input, filterText) + } + idx = idx + 1 + if (!match) return false + return { + sortText: typeof item.sortText === 'string' ? item.sortText : String.fromCharCode(idx), + score: matchScore, + highlights: getHighlights(filterLabel, matches) + } + }, (items, done) => { + onFilter(items, done, sort) + }, token) + } + + private async filterItems(arr: ListItem[], opts: FilterOption, token: CancellationToken): Promise { + let { input } = this + if (input.length === 0) { + let items = arr.map(item => { + return this.convertItemLabel(item) + }) + this._onDidChangeItems.fire({ items, finished: this._finished, ...opts }) + return + } + let inputs = this.config.extendedSearchMode ? parseInput(input) : [input] + let called = false + const onFilter = (items: ListItemWithHighlights[], finished: boolean, sort?: boolean) => { + finished = finished && this._finished + if (token.isCancellationRequested || (!finished && items.length == 0)) return + if (sort) { + items.sort((a, b) => { + if (a.score != b.score) return b.score - a.score + if (a.sortText > b.sortText) return 1 + return -1 + }) + } + let append = opts.append === true || called + called = true + this._onDidChangeItems.fire({ items, append, reload: opts.reload, finished }) + } + switch (this.listOptions.matcher) { + case 'strict': + await this.filterItemsByInclude(inputs, arr, token, onFilter) + break + case 'regex': + await this.filterItemsByRegex(inputs, arr, token, onFilter) + break + default: + await this.filterItemsByFuzzyMatch(inputs, arr, token, onFilter) + } + } + + // set correct label, add ansi highlights + private convertItemLabel(item: ListItem): ListItem { + let { label, converted } = item + if (converted) return item + if (label.includes('\n')) { + label = item.label = label.replace(/\r?\n/g, ' ') + } + if (label.includes(controlCode)) { + let { line, highlights } = parseAnsiHighlights(label) + item.label = line + if (!Array.isArray(item.ansiHighlights)) item.ansiHighlights = highlights + } + item.converted = true + return item + } + + public dispose(): void { + this.stop() + } +} + +function getFilterLabel(item: ListItem): string { + return item.filterText != null ? patchLine(item.filterText, item.label) : item.label +} + +/** + * `a\ b` => [`a b`] + * `a b` => ['a', 'b'] + */ +export function parseInput(input: string): string[] { + let res: string[] = [] + let startIdx = 0 + let currIdx = 0 + let prev = '' + for (; currIdx < input.length; currIdx++) { + let ch = input[currIdx] + if (ch.charCodeAt(0) === 32) { + // find space + if (prev && prev != '\\' && startIdx != currIdx) { + res.push(input.slice(startIdx, currIdx)) + startIdx = currIdx + 1 + } + } else { + } + prev = ch + } + if (startIdx != input.length) { + res.push(input.slice(startIdx, input.length)) + } + return res.map(s => s.replace(/\\\s/g, ' ').trim()).filter(s => s.length > 0) +} + +export function getHighlights(text: string, matches?: number[]): ListHighlights { + let spans: [number, number][] = [] + if (matches && matches.length) { + let start = matches.shift() + let next = matches.shift() + let curr = start + while (next) { + if (next == curr + 1) { + curr = next + next = matches.shift() + continue + } + spans.push([byteIndex(text, start), byteIndex(text, curr) + 1]) + start = next + curr = start + next = matches.shift() + } + spans.push([byteIndex(text, start), byteIndex(text, curr) + 1]) + } + return { spans } +} + +export function getItemHighlights(input: string, item: ListItem): ListHighlights { + let filterLabel = getFilterLabel(item) + let res = getMatchResult(filterLabel, input) + if (!res?.score) return { spans: [] } + return getHighlights(filterLabel, res.matches) +} diff --git a/sources_non_forked/coc.nvim/src/main.ts b/sources_non_forked/coc.nvim/src/main.ts new file mode 100755 index 00000000..ed9458ba --- /dev/null +++ b/sources_non_forked/coc.nvim/src/main.ts @@ -0,0 +1,26 @@ +'use strict' +Object.defineProperty(console, 'log', { + value() { + if (logger) logger.info(...arguments) + } +}) +import './util/extensions' +import attach from './attach' +const logger = require('./util/logger')('server') + +attach({ reader: process.stdin, writer: process.stdout }) + +process.on('uncaughtException', function(err) { + let msg = 'Uncaught exception: ' + err.message + console.error(msg) + logger.error('uncaughtException', err.stack) +}) + +process.on('unhandledRejection', function(reason, p) { + if (reason instanceof Error) { + console.error('UnhandledRejection: ' + reason.message + '\n' + reason.stack) + } else { + console.error('UnhandledRejection: ' + reason) + } + logger.error('unhandledRejection ', p, reason) +}) diff --git a/sources_non_forked/coc.nvim/src/markdown/index.ts b/sources_non_forked/coc.nvim/src/markdown/index.ts new file mode 100644 index 00000000..c1b1ee71 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/markdown/index.ts @@ -0,0 +1,201 @@ +'use strict' +import { marked } from 'marked' +import Renderer from './renderer' +import { parseAnsiHighlights } from '../util/ansiparse' +import { byteLength } from '../util/string' +import stripAnsi from 'strip-ansi' +import { HighlightItem, Documentation } from '../types' +export const diagnosticFiletypes = ['Error', 'Warning', 'Info', 'Hint'] +const logger = require('../util/logger')('markdown-index') + +export interface MarkdownParseOptions { + excludeImages?: boolean +} + +export interface CodeBlock { + /** + * Must have filetype or hlgroup + */ + filetype?: string + hlGroup?: string + startLine: number // 0 based + endLine: number +} + +export interface DocumentInfo { + lines: string[] + highlights: HighlightItem[] + codes: CodeBlock[] +} + +export function parseDocuments(docs: Documentation[], opts: MarkdownParseOptions = {}): DocumentInfo { + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let codes: CodeBlock[] = [] + let idx = 0 + for (let doc of docs) { + let currline = lines.length + let { content, filetype } = doc + let hls = doc.highlights + if (filetype == 'markdown') { + let info = parseMarkdown(content, opts) + codes.push(...info.codes.map(o => { + o.startLine = o.startLine + currline + o.endLine = o.endLine + currline + return o + })) + highlights.push(...info.highlights.map(o => { + o.lnum = o.lnum + currline + return o + })) + lines.push(...info.lines) + } else { + let parts = content.trim().split(/\r?\n/) + if (diagnosticFiletypes.includes(doc.filetype)) { + codes.push({ hlGroup: `Coc${filetype}Float`, startLine: currline, endLine: currline + parts.length }) + } else { + codes.push({ filetype: doc.filetype, startLine: currline, endLine: currline + parts.length }) + } + lines.push(...parts) + } + if (Array.isArray(hls)) { + highlights.push(...hls.map(o => { + return Object.assign({}, o, { lnum: o.lnum + currline }) + })) + } + if (Array.isArray(doc.active)) { + let arr = getHighlightItems(content, currline, doc.active) + if (arr.length) highlights.push(...arr) + } + if (idx != docs.length - 1) { + lines.push('─') // separate line + } + idx = idx + 1 + } + return { lines, highlights, codes } +} + +/** + * Get 'CocUnderline' highlights from offset range + */ +export function getHighlightItems(content: string, currline: number, active: [number, number]): HighlightItem[] { + let res: HighlightItem[] = [] + let [start, end] = active + let lines = content.split(/\r?\n/) + let used = 0 + let inRange = false + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + if (!inRange) { + if (used + line.length > start) { + inRange = true + let colStart = byteLength(line.slice(0, start - used)) + if (used + line.length > end) { + let colEnd = byteLength(line.slice(0, end - used)) + inRange = false + res.push({ colStart, colEnd, lnum: i + currline, hlGroup: 'CocUnderline' }) + break + } else { + let colEnd = byteLength(line) + res.push({ colStart, colEnd, lnum: i + currline, hlGroup: 'CocUnderline' }) + } + } + } else { + if (used + line.length > end) { + let colEnd = byteLength(line.slice(0, end - used)) + res.push({ colStart: 0, colEnd, lnum: i + currline, hlGroup: 'CocUnderline' }) + inRange = false + break + } else { + let colEnd = byteLength(line) + res.push({ colStart: 0, colEnd, lnum: i + currline, hlGroup: 'CocUnderline' }) + } + } + used = used + line.length + 1 + } + return res +} + +/** + * Parse markdown for lines, highlights & codes + */ +export function parseMarkdown(content: string, opts: MarkdownParseOptions): DocumentInfo { + marked.setOptions({ + renderer: new Renderer(), + gfm: true, + breaks: true + }) + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let codes: CodeBlock[] = [] + let currline = 0 + let inCodeBlock = false + let filetype: string + let startLnum = 0 + let parsed = marked(content) + let links = Renderer.getLinks() + if (links.length) { + parsed = parsed + '\n\n' + links.join('\n') + } + parsed = parsed.replace(/\s*$/, '') + let parsedLines = parsed.split(/\n/) + for (let i = 0; i < parsedLines.length; i++) { + let line = parsedLines[i] + if (!line.length) { + let pre = lines[lines.length - 1] + if (pre) { + lines.push(line) + currline++ + } + continue + } + if (opts.excludeImages && line.indexOf('![') !== -1) { + line = line.replace(/\s*!\[.*?\]\(.*?\)/g, '') + if (!stripAnsi(line).trim().length) continue + } + if (/\s*```\s*([A-Za-z0-9_,]+)?$/.test(line)) { + if (!inCodeBlock) { + let pre = parsedLines[i - 1] + if (pre && /^\s*```\s*/.test(pre)) { + lines.push('') + currline++ + } + inCodeBlock = true + filetype = line.replace(/^\s*```\s*/, '') + if (filetype == 'js') filetype = 'javascript' + if (filetype == 'ts') filetype = 'typescript' + if (filetype == 'bash') filetype = 'sh' + startLnum = currline + } else { + inCodeBlock = false + codes.push({ + filetype, + startLine: startLnum, + endLine: currline + }) + } + continue + } + if (inCodeBlock) { + // no parse + lines.push(line) + currline++ + continue + } + let res = parseAnsiHighlights(line, true) + if (res.highlights) { + for (let hi of res.highlights) { + let { hlGroup, span } = hi + highlights.push({ + hlGroup, + lnum: currline, + colStart: span[0], + colEnd: span[1] + }) + } + } + lines.push(res.line) + currline++ + } + return { lines, highlights, codes } +} diff --git a/sources_non_forked/coc.nvim/src/markdown/renderer.ts b/sources_non_forked/coc.nvim/src/markdown/renderer.ts new file mode 100644 index 00000000..1ca87dad --- /dev/null +++ b/sources_non_forked/coc.nvim/src/markdown/renderer.ts @@ -0,0 +1,359 @@ +'use strict' +/** + * Renderer for convert markdown to terminal string + */ +import Table from 'cli-table' +import * as styles from './styles' +const logger = require('../util/logger')('markdown-renderer') +let TABLE_CELL_SPLIT = '^*||*^' +let TABLE_ROW_WRAP = '*|*|*|*' +let TABLE_ROW_WRAP_REGEXP = new RegExp(escapeRegExp(TABLE_ROW_WRAP), 'g') +let COLON_REPLACER = '*#COLON|*' +let COLON_REPLACER_REGEXP = new RegExp(escapeRegExp(COLON_REPLACER), 'g') + +// HARD_RETURN holds a character sequence used to indicate text has a +// hard (no-reflowing) line break. Previously \r and \r\n were turned +// into \n in marked's lexer- preprocessing step. So \r is safe to use +// to indicate a hard (non-reflowed) return. +let HARD_RETURN = '\r' + +function identity(str: string): string { + return str +} + +function cleanUpHtml(input: string): string { + return styles.gray(input.replace(/(<([^>]+)>)/ig, '')) +} + +let defaultOptions = { + code: identity, + blockquote: identity, + html: cleanUpHtml, + heading: styles.magenta, + firstHeading: styles.magenta, + hr: identity, + listitem: identity, + list, + table: identity, + paragraph: identity, + strong: styles.bold, + em: styles.italic, + codespan: styles.yellow, + del: styles.strikethrough, + link: styles.underline, + href: styles.underline, + text: identity, + unescape: true, + emoji: false, + width: 80, + showSectionPrefix: true, + tab: 2, + tableOptions: {} +} + +function fixHardReturn(text, reflow) { + return reflow ? text.replace(HARD_RETURN, /\n/g) : text +} + +function indentLines(indent, text) { + return text.replace(/(^|\n)(.+)/g, '$1' + indent + '$2') +} + +function identify(indent, text) { + if (!text) return text + return indent + text.split('\n').join('\n' + indent) +} + +let BULLET_POINT_REGEX = '\\*' +let NUMBERED_POINT_REGEX = '\\d+\\.' +let POINT_REGEX = '(?:' + [BULLET_POINT_REGEX, NUMBERED_POINT_REGEX].join('|') + ')' + +// Prevents nested lists from joining their parent list's last line +function fixNestedLists(body, indent) { + let regex = new RegExp( + '' + + '(\\S(?: | )?)' + // Last char of current point, plus one or two spaces + // to allow trailing spaces + '((?:' + + indent + + ')+)' + // Indentation of sub point + '(' + + POINT_REGEX + + '(?:.*)+)$', + 'gm' + ) // Body of subpoint + return body.replace(regex, '$1\n' + indent + '$2$3') +} + +let isPointedLine = function(line, indent) { + return line.match('^(?:' + indent + ')*' + POINT_REGEX) +} + +function toSpaces(str) { + return ' '.repeat(str.length) +} + +let BULLET_POINT = '* ' +function bulletPointLine(indent, line) { + return isPointedLine(line, indent) ? line : toSpaces(BULLET_POINT) + line +} + +function bulletPointLines(lines, indent) { + let transform = bulletPointLine.bind(null, indent) + return lines + .split('\n') + .filter(identity) + .map(transform) + .join('\n') +} + +let numberedPoint = function(n) { + return n + '. ' +} +function numberedLine(indent, line, num) { + return isPointedLine(line, indent) + ? { + num: num + 1, + line: line.replace(BULLET_POINT, numberedPoint(num + 1)) + } + : { + num, + line: toSpaces(numberedPoint(num)) + line + } +} + +function numberedLines(lines, indent) { + let transform = numberedLine.bind(null, indent) + let num = 0 + return lines + .split('\n') + .filter(identity) + .map(line => { + const numbered = transform(line, num) + num = numbered.num + + return numbered.line + }) + .join('\n') +} + +function list(body, ordered, indent) { + body = body.trim() + body = ordered ? numberedLines(body, indent) : bulletPointLines(body, indent) + return body +} + +function section(text) { + return text + '\n\n' +} + +function undoColon(str) { + return str.replace(COLON_REPLACER_REGEXP, ':') +} + +function generateTableRow(text, escape = null) { + if (!text) return [] + escape = escape || identity + let lines = escape(text).split('\n') + + let data = [] + lines.forEach(function(line) { + if (!line) return + let parsed = line + .replace(TABLE_ROW_WRAP_REGEXP, '') + .split(TABLE_CELL_SPLIT) + + data.push(parsed.splice(0, parsed.length - 1)) + }) + return data +} + +function escapeRegExp(str) { + // eslint-disable-next-line no-useless-escape + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&') +} + +function unescapeEntities(html) { + return html + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, "'") +} + +const links: Map = new Map() + +export interface RendererOptions { + sanitize?: boolean +} + +class Renderer { + private o: any + private tab: any + private tableSettings: any + // private emoji: any + private unescape: any + private transform: any + constructor(public options: RendererOptions = {}, public highlightOptions: any = {}) { + this.o = Object.assign({}, defaultOptions, options) + this.tab = ' ' + this.tableSettings = this.o.tableOptions + // this.emoji = identity + this.unescape = this.o.unescape ? unescapeEntities : identity + this.highlightOptions = highlightOptions || {} + this.transform = this.compose(undoColon, this.unescape) + } + + public text(t: string): string { + return this.o.text(t) + } + + public code(code: string, lang: string, _escaped: boolean): string { + return '``` ' + lang + '\n' + code + '\n```\n' + } + + public blockquote(quote: string): string { + return section(this.o.blockquote(identify(this.tab, quote.trim()))) + } + + public html(html: string): string { + return this.o.html(html) + } + + public heading(text: string, level: number, _raw: any): string { + text = this.transform(text) + let prefix = this.o.showSectionPrefix + ? new Array(level + 1).join('#') + ' ' + : '' + text = prefix + text + return section( + level === 1 ? this.o.firstHeading(text) : this.o.heading(text) + ) + } + + public hr(): string { + // NOTE: the '─' character is conveniently translated into a window-wide + // horizontal rule by coc.nvim/autoload/coc/float.vim. Using this character + // causes the horizontal rule to appear like a proper hr separator. In case + // the user isn't benefiting from a floating window, we provide three + // characters so that the hr doesn't deviate too significantly from + // Markdown's normal '-'. + return `───\n` + } + + public list(body, ordered): string { + body = this.o.list(body, ordered, this.tab) + return section(fixNestedLists(indentLines(this.tab, body), this.tab)) + } + + public listitem(text: string): string { + let transform = this.compose(this.o.listitem, this.transform) + let isNested = text.indexOf('\n') !== -1 + if (isNested) text = text.trim() + // Use BULLET_POINT as a marker for ordered or unordered list item + return '\n' + BULLET_POINT + transform(text) + } + + public checkbox(checked): string { + return '[' + (checked ? 'X' : ' ') + '] ' + } + + public paragraph(text: string): string { + let transform = this.compose(this.o.paragraph, this.transform) + text = transform(text) + return section(text) + } + + public table(header, body): string { + let table = new Table( + Object.assign( + {}, + { + head: generateTableRow(header)[0] + }, + this.tableSettings + ) + ) + generateTableRow(body, this.transform).forEach(function(row) { + table.push(row) + }) + return section(this.o.table(table.toString())) + } + + public tablerow(content: string): string { + return TABLE_ROW_WRAP + content + TABLE_ROW_WRAP + '\n' + } + + public tablecell(content, _flags): string { + return content + TABLE_CELL_SPLIT + } + + public strong(text: string): string { + return this.o.strong(text) + } + + public em(text: string): string { + text = fixHardReturn(text, this.o.reflowText) + return this.o.em(text) + } + + public codespan(text: string): string { + text = fixHardReturn(text, this.o.reflowText) + return this.o.codespan(text.replace(/:/g, COLON_REPLACER)) + } + + public br(): string { + return '\n' + } + + public del(text: string): string { + return this.o.del(text) + } + + public link(href, title, text): string { + let prot: string + try { + prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, '') + .toLowerCase() + } catch (e) { + return '' + } + if (prot.startsWith('javascript:')) { + return '' + } + if (text && href && text != href) { + links.set(text, href) + } + if (text && text != href) return styles.blue(text) + let out = this.o.href(href) + return this.o.link(out) + } + + public image(href, title, text): string { + let out = '![' + text + if (title) out += ' – ' + title + return out + '](' + href + ')' + } + + public compose(...funcs: Function[]): any { + return (...args: any[]) => { + for (let i = funcs.length; i-- > 0;) { + args = [funcs[i].apply(this, args)] + } + return args[0] + } + } + + public static getLinks(): string[] { + let res = [] + for (let [text, href] of links.entries()) { + res.push(`${styles.blue(text)}: ${href}`) + } + links.clear() + return res + } +} + +export default Renderer diff --git a/sources_non_forked/coc.nvim/src/markdown/styles.ts b/sources_non_forked/coc.nvim/src/markdown/styles.ts new file mode 100644 index 00000000..c5ab28e2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/markdown/styles.ts @@ -0,0 +1,38 @@ +'use strict' +import style from 'ansi-styles' + +export function gray(str: string): string { + return `${style.gray.open}${str}${style.gray.close}` +} + +export function magenta(str: string): string { + return `${style.magenta.open}${str}${style.magenta.close}` +} + +export function bold(str: string): string { + return `${style.bold.open}${str}${style.bold.close}` +} + +export function underline(str: string): string { + return `${style.underline.open}${str}${style.underline.close}` +} + +export function strikethrough(str: string): string { + return `${style.strikethrough.open}${str}${style.strikethrough.close}` +} + +export function italic(str: string): string { + return `${style.italic.open}${str}${style.italic.close}` +} + +export function yellow(str: string): string { + return `${style.yellow.open}${str}${style.yellow.close}` +} + +export function green(str: string): string { + return `${style.green.open}${str}${style.green.close}` +} + +export function blue(str: string): string { + return `${style.blue.open}${str}${style.blue.close}` +} diff --git a/sources_non_forked/coc.nvim/src/model/bufferSync.ts b/sources_non_forked/coc.nvim/src/model/bufferSync.ts new file mode 100644 index 00000000..5b0d3c28 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/bufferSync.ts @@ -0,0 +1,94 @@ +'use strict' +import { Disposable } from 'vscode-languageserver-protocol' +import type Documents from '../core/documents' +import events from '../events' +import { DidChangeTextDocumentParams } from '../types' +import { disposeAll } from '../util' +import type Document from './document' + +export interface SyncItem extends Disposable { + onChange?(e: DidChangeTextDocumentParams): void + onTextChange?(): void +} + +/** + * Buffer sync support, document is always attached and not command line buffer. + */ +export default class BufferSync { + private disposables: Disposable[] = [] + private itemsMap: Map = new Map() + constructor(private _create: (doc: Document) => T | undefined, documents: Documents) { + let { disposables } = this + for (let doc of documents.documents) { + this.create(doc) + } + documents.onDidOpenTextDocument(e => { + this.create(documents.getDocument(e.bufnr)) + }, null, disposables) + documents.onDidChangeDocument(e => { + this.onChange(e) + }, null, disposables) + documents.onDidCloseDocument(e => { + this.delete(e.bufnr) + }, null, disposables) + events.on('LinesChanged', bufnr => { + let o = this.itemsMap.get(bufnr) + if (o && typeof o.item.onTextChange == 'function') { + o.item.onTextChange() + } + }, null, disposables) + } + + public get items(): Iterable { + return Array.from(this.itemsMap.values()).map(x => x.item) + } + + public getItem(bufnr: number | string): T | undefined { + if (typeof bufnr === 'number') { + return this.itemsMap.get(bufnr)?.item + } + let o = Array.from(this.itemsMap.values()).find(v => { + return v.uri == bufnr + }) + return o ? o.item : undefined + } + + private create(doc: Document): void { + if (!doc) return + let o = this.itemsMap.get(doc.bufnr) + if (o) o.item.dispose() + let item = this._create(doc) + if (item) this.itemsMap.set(doc.bufnr, { uri: doc.uri, item }) + } + + private onChange(e: DidChangeTextDocumentParams): void { + let o = this.itemsMap.get(e.bufnr) + if (o && typeof o.item.onChange == 'function') { + o.item.onChange(e) + } + } + + private delete(bufnr: number): void { + let o = this.itemsMap.get(bufnr) + if (o) { + o.item.dispose() + this.itemsMap.delete(bufnr) + } + } + + public reset(): void { + for (let o of this.itemsMap.values()) { + o.item.dispose() + } + this.itemsMap.clear() + } + + public dispose(): void { + disposeAll(this.disposables) + for (let o of this.itemsMap.values()) { + o.item.dispose() + } + this._create = undefined + this.itemsMap.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/model/chars.ts b/sources_non_forked/coc.nvim/src/model/chars.ts new file mode 100644 index 00000000..0f38ec90 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/chars.ts @@ -0,0 +1,189 @@ +'use strict' +import { Position, CancellationToken } from 'vscode-languageserver-protocol' +import { waitImmediate } from '../util' +import { TextDocument } from 'vscode-languageserver-textdocument' +const logger = require('../util/logger')('model-chars') + +export class Range { + public start: number + public end: number + constructor(start: number, end?: number) { + this.start = start + this.end = end ? end : start + } + + public static fromKeywordOption(keywordOption: string): Range[] { + let parts = keywordOption.split(',') + let ranges: Range[] = [] + ranges.push(new Range(65, 90)) + ranges.push(new Range(97, 122)) + for (let part of parts) { + if (part == '@') { + ranges.push(new Range(256, 65535)) + } else if (part == '@-@') { + ranges.push(new Range(64)) + } else if (/^\d+-\d+$/.test(part)) { + let ms = part.match(/^(\d+)-(\d+)$/) + ranges.push(new Range(Number(ms[1]), Number(ms[2]))) + } else if (/^\d+$/.test(part)) { + ranges.push(new Range(Number(part))) + } else { + let c = part.charCodeAt(0) + if (!ranges.some(o => o.contains(c))) { + ranges.push(new Range(c)) + } + } + } + return ranges + } + + public contains(c: number): boolean { + return c >= this.start && c <= this.end + } +} + +export class Chars { + public ranges: Range[] = [] + constructor(keywordOption?: string) { + if (keywordOption) this.ranges = Range.fromKeywordOption(keywordOption) + } + + public addKeyword(ch: string): void { + let c = ch.charCodeAt(0) + let { ranges } = this + if (!ranges.some(o => o.contains(c))) { + ranges.push(new Range(c)) + } + } + + public clone(): Chars { + let chars = new Chars() + chars.ranges = this.ranges.slice() + return chars + } + + public setKeywordOption(keywordOption: string): void { + this.ranges = Range.fromKeywordOption(keywordOption) + } + + public async matchLines(lines: ReadonlyArray, min = 2, token?: CancellationToken): Promise | undefined> { + let res: Set = new Set() + let ts = Date.now() + for (let line of lines) { + if (line.length === 0) continue + let str = '' + if (Date.now() - ts > 15) { + await waitImmediate() + ts = Date.now() + } + for (let codePoint of line) { + if (token && token.isCancellationRequested) return undefined + let code = codePoint.codePointAt(0) + let isKeyword = this.isKeywordCode(code) + if (isKeyword) { + str = str + codePoint + } else { + if (str.length > 0) { + if (str.length >= min && str.length < 48) res.add(str) + str = '' + } + } + } + if (str.length >= min && str.length < 48) res.add(str) + } + return res + } + + public isKeywordCode(code: number): boolean { + if (code > 255) return true + if (code < 33) return false + return this.ranges.some(r => r.contains(code)) + } + + public isKeywordChar(ch: string): boolean { + let { ranges } = this + if (/\s/.test(ch)) return false + let c = ch.charCodeAt(0) + if (c < 33) return false + return ranges.some(r => r.contains(c)) + } + + public isKeyword(word: string): boolean { + for (let i = 0, l = word.length; i < l; i++) { + if (!this.isKeywordChar(word[i])) return false + } + return true + } + + public getLocalifyBonus(sp: Position, ep: Position, lines: ReadonlyArray, max = 10 * 1024): Map { + let res: Map = new Map() + let startLine = Math.max(0, sp.line - 50) + let endLine = Math.min(lines.length, sp.line + 50) + let content = lines.slice(startLine, endLine).join('\n') + // limit content to parse + if (content.length > max) { + let len = content.length + let finished = false + while (endLine > sp.line + 1) { + let length = lines[endLine - 1].length + if (len - length < max) { + finished = true + break + } + endLine = endLine - 1 + len -= length + } + if (!finished) { + while (startLine <= sp.line) { + let length = lines[startLine].length + if (len - length < max) { + break + } + len -= length + startLine += 1 + } + } + content = lines.slice(startLine, endLine).join('\n') + } + sp = Position.create(sp.line - startLine, sp.character) + ep = Position.create(ep.line - startLine, ep.character) + let doc = TextDocument.create('', '', 1, content) + let headCount = doc.offsetAt(sp) + let len = content.length + let tailCount = len - doc.offsetAt(ep) + let start = 0 + let preKeyword = false + for (let i = 0; i < headCount; i++) { + let iskeyword = this.isKeyword(content[i]) + if (!preKeyword && iskeyword) { + start = i + } else if (preKeyword && !iskeyword) { + if (i - start > 1) { + let str = content.substring(start, i) + res.set(str, i / headCount) + } + } + preKeyword = iskeyword + } + start = len - tailCount + preKeyword = false + for (let i = start; i < content.length; i++) { + let iskeyword = this.isKeyword(content[i]) + if (!preKeyword && iskeyword) { + start = i + } else if (preKeyword && (!iskeyword || i == len - 1)) { + if (i - start > 1) { + let end = i == len - 1 ? i + 1 : i + let str = content.substring(start, end) + let score = res.get(str) || 0 + let n = len - i + (end - start) + if (n !== tailCount) { + res.set(str, Math.max(score, n / tailCount)) + } + } + } + preKeyword = iskeyword + } + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/model/db.ts b/sources_non_forked/coc.nvim/src/model/db.ts new file mode 100644 index 00000000..bc55393c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/db.ts @@ -0,0 +1,134 @@ +'use strict' +import fs from 'fs-extra' +import path from 'path' + +export default class DB { + constructor(public readonly filepath: string) { + } + + /** + * Get data by key. + * + * @param {string} key unique key allows dot notation. + * @returns {any} + */ + public fetch(key: string): any { + let obj = this.load() + if (!key) return obj + let parts = key.split('.') + for (let part of parts) { + if (typeof obj[part] == 'undefined') { + return undefined + } + obj = obj[part] + } + return obj + } + + /** + * Check if key exists + * + * @param {string} key unique key allows dot notation. + */ + public exists(key: string): boolean { + let obj = this.load() + let parts = key.split('.') + for (let part of parts) { + if (typeof obj[part] == 'undefined') { + return false + } + obj = obj[part] + } + return true + } + + /** + * Delete data by key + * + * @param {string} key unique key allows dot notation. + */ + public delete(key: string): void { + let obj = this.load() + let origin = obj + let parts = key.split('.') + let len = parts.length + for (let i = 0; i < len; i++) { + if (typeof obj[parts[i]] == 'undefined') { + break + } + if (i == len - 1) { + delete obj[parts[i]] + fs.writeFileSync(this.filepath, JSON.stringify(origin, null, 2), 'utf8') + break + } + obj = obj[parts[i]] + } + } + + /** + * Save data with key + * + * @param {string} key unique string that allows dot notation. + * @param {number|null|boolean|string|{[index} data saved data. + */ + public push(key: string, data: number | null | boolean | string | { [index: string]: any }): void { + let origin = this.load() || {} + let obj = origin + let parts = key.split('.') + let len = parts.length + if (obj == null) { + let dir = path.dirname(this.filepath) + fs.mkdirpSync(dir) + obj = origin + } + for (let i = 0; i < len; i++) { + let key = parts[i] + if (i == len - 1) { + obj[key] = data + fs.writeFileSync(this.filepath, JSON.stringify(origin, null, 2)) + break + } + if (typeof obj[key] == 'undefined') { + obj[key] = {} + obj = obj[key] + } else { + obj = obj[key] + } + } + } + + private load(): any { + let dir = path.dirname(this.filepath) + let stat = fs.statSync(dir) + if (!stat || !stat.isDirectory()) { + fs.mkdirpSync(dir) + fs.writeFileSync(this.filepath, '{}', 'utf8') + return {} + } + try { + let content = fs.readFileSync(this.filepath, 'utf8') + return JSON.parse(content.trim()) + } catch (e) { + fs.writeFileSync(this.filepath, '{}', 'utf8') + return {} + } + } + + /** + * Empty db file. + */ + public clear(): void { + let stat = fs.statSync(this.filepath) + if (!stat || !stat.isFile()) return + fs.writeFileSync(this.filepath, '{}', 'utf8') + } + + /** + * Remove db file. + */ + public destroy(): void { + if (fs.existsSync(this.filepath)) { + fs.unlinkSync(this.filepath) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/dialog.ts b/sources_non_forked/coc.nvim/src/model/dialog.ts new file mode 100644 index 00000000..19df0832 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/dialog.ts @@ -0,0 +1,123 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { HighlightItem } from '../types' +import { disposeAll } from '../util' +const logger = require('../util/logger')('model-dialog') + +export interface DialogButton { + /** + * Used by callback, should >= 0 + */ + index: number + text: string + /** + * Not shown when true + */ + disabled?: boolean +} + +export interface DialogPreferences { + rounded?: boolean + maxWidth?: number + maxHeight?: number + floatHighlight?: string + floatBorderHighlight?: string + pickerButtons?: boolean + pickerButtonShortcut?: boolean + confirmKey?: string + shortcutHighlight?: string +} + +export interface DialogConfig { + content: string + /** + * Optional title text. + */ + title?: string + /** + * show close button, default to true when not specified. + */ + close?: boolean + /** + * highlight group for dialog window, default to `"dialog.floatHighlight"` or 'CocFloating' + */ + highlight?: string + /** + * highlight items of content. + */ + highlights?: ReadonlyArray + /** + * highlight groups for border, default to `"dialog.borderhighlight"` or 'CocFloating' + */ + borderhighlight?: string + /** + * Buttons as bottom of dialog. + */ + buttons?: DialogButton[] + /** + * index is -1 for window close without button click + */ + callback?: (index: number) => void +} + +export default class Dialog { + private disposables: Disposable[] = [] + private bufnr: number + private readonly _onDidClose = new Emitter() + public readonly onDidClose: Event = this._onDidClose.event + constructor(private nvim: Neovim, private config: DialogConfig) { + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + this.dispose() + if (config.callback) config.callback(-1) + } + }, null, this.disposables) + events.on('FloatBtnClick', (bufnr, idx) => { + if (bufnr == this.bufnr) { + this.dispose() + let btns = config?.buttons.filter(o => o.disabled != true) + if (config.callback) config.callback(btns[idx].index) + } + }, null, this.disposables) + } + + private get lines(): string[] { + return [...this.config.content.split(/\r?\n/)] + } + + public async show(preferences: DialogPreferences): Promise { + let { nvim } = this + let { title, close, highlights, buttons } = this.config + let borderhighlight = this.config.borderhighlight || preferences.floatBorderHighlight + let highlight = this.config.highlight || preferences.floatHighlight + let opts: any = { maxwidth: preferences.maxWidth || 80, } + if (title) opts.title = title + if (close || typeof close === 'undefined') opts.close = 1 + if (preferences.maxHeight) opts.maxHeight = preferences.maxHeight + if (preferences.maxWidth) opts.maxWidth = preferences.maxWidth + if (highlight) opts.highlight = highlight + if (highlights) opts.highlights = highlights + if (borderhighlight) opts.borderhighlight = [borderhighlight] + if (buttons) opts.buttons = buttons.filter(o => !o.disabled).map(o => o.text) + if (preferences.rounded) opts.rounded = 1 + if (Array.isArray(opts.buttons)) opts.getchar = 1 + let res = await nvim.call('coc#dialog#create_dialog', [this.lines, opts]) + if (!res) throw new Error('Unable to open dialog window.') + this.bufnr = res[1] + nvim.command('redraw', true) + } + + public get winid(): Promise { + if (!this.bufnr) return Promise.resolve(null) + return this.nvim.call('bufwinid', [this.bufnr]) + } + + public dispose(): void { + this._onDidClose.fire() + this.bufnr = undefined + disposeAll(this.disposables) + this.disposables = [] + } +} diff --git a/sources_non_forked/coc.nvim/src/model/document.ts b/sources_non_forked/coc.nvim/src/model/document.ts new file mode 100644 index 00000000..aec57c85 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/document.ts @@ -0,0 +1,731 @@ +'use strict' +import { Buffer, Neovim, VimValue } from '@chemzqm/neovim' +import debounce from 'debounce' +import { CancellationToken, Disposable, Emitter, Event, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events, { InsertChange } from '../events' +import { BufferOption, DidChangeTextDocumentParams, HighlightItem, HighlightItemOption, TextDocumentContentChange } from '../types' +import { diffLines, getTextEdit } from '../util/diff' +import { disposeAll, getUri, wait, waitNextTick } from '../util/index' +import { equals } from '../util/object' +import { comparePosition, emptyRange } from '../util/position' +import { byteIndex, byteLength, byteSlice, characterIndex } from '../util/string' +import { applyEdits, filterSortEdits, getPositionFromEdits, mergeTextEdits, TextChangeItem, toTextChanges } from '../util/textedit' +import { Chars } from './chars' +import { LinesTextDocument } from './textdocument' +const logger = require('../util/logger')('model-document') + +export type LastChangeType = 'insert' | 'change' | 'delete' + +export interface Env { + readonly filetypeMap: { [index: string]: string } + readonly isVim: boolean + readonly isCygwin: boolean +} + +export interface ChangeInfo { + bufnr: number + lnum: number + line: string + changedtick: number +} + +// getText, positionAt, offsetAt +export default class Document { + public buftype: string + public isIgnored = false + public chars: Chars + private eol = true + private _noFetch: boolean + private _disposed = false + private _attached = false + private _previewwindow = false + private _winid = -1 + private _filetype: string + private _bufname: string + private _uri: string + private _indentkeys: string + private _changedtick: number + private variables: { [key: string]: VimValue } + private disposables: Disposable[] = [] + private _textDocument: LinesTextDocument + // real current lines + private lines: ReadonlyArray = [] + public fireContentChanges: Function & { clear(): void } + public fetchContent: Function & { clear(): void } + private _onDocumentChange = new Emitter() + public readonly onDocumentChange: Event = this._onDocumentChange.event + constructor( + public readonly buffer: Buffer, + private env: Env, + private nvim: Neovim, + opts: BufferOption + ) { + this.fireContentChanges = debounce(() => { + this._fireContentChanges() + }, global.__TEST__ ? 20 : 150) + this.fetchContent = debounce(() => { + void this._fetchContent() + }, 100) + this.init(opts) + } + + /** + * Synchronize content + */ + public get content(): string { + return this.syncLines.join('\n') + (this.eol ? '\n' : '') + } + + public get attached(): boolean { + return this._attached + } + + /** + * Synchronized textDocument. + */ + public get textDocument(): LinesTextDocument { + return this._textDocument + } + + private get syncLines(): ReadonlyArray { + return this._textDocument.lines + } + + public get version(): number { + return this._textDocument.version + } + /** + * Buffer number + */ + public get bufnr(): number { + return this.buffer.id + } + + public get bufname(): string { + return this._bufname + } + + public get filetype(): string { + return this._filetype + } + + public get uri(): string { + return this._uri + } + + public get isCommandLine(): boolean { + return this.uri && this.uri.endsWith('%5BCommand%20Line%5D') + } + + public get enabled(): boolean { + return this.getVar('enabled', true) + } + + /** + * LanguageId of TextDocument, main filetype are used for combined filetypes + * with '.' + */ + public get languageId(): string { + let { _filetype } = this + return _filetype.includes('.') ? _filetype.match(/(.*?)\./)[1] : _filetype + } + + /** + * Get current buffer changedtick. + */ + public get changedtick(): number { + return this._changedtick + } + + /** + * Map filetype for languageserver. + */ + public convertFiletype(filetype: string): string { + switch (filetype) { + case 'javascript.jsx': + return 'javascriptreact' + case 'typescript.jsx': + case 'typescript.tsx': + return 'typescriptreact' + case 'tex': + // Vim filetype 'tex' means LaTeX, which has LSP language ID 'latex' + return 'latex' + default: { + let map = this.env.filetypeMap + return String(map[filetype] || filetype) + } + } + } + + /** + * Scheme of document. + */ + public get schema(): string { + return URI.parse(this.uri).scheme + } + + /** + * Line count of current buffer. + */ + public get lineCount(): number { + return this.lines.length + } + + /** + * Window ID when buffer create, could be -1 when no window associated. + */ + public get winid(): number { + return this._winid + } + + public get indentkeys(): string { + return this._indentkeys + } + + /** + * Returns if current document is opended with previewwindow + * + * @deprecated + */ + public get previewwindow(): boolean { + return this._previewwindow + } + + /** + * Initialize document model. + */ + private init(opts: BufferOption): void { + let buftype = this.buftype = opts.buftype + this._indentkeys = opts.indentkeys + this._bufname = opts.bufname + this._previewwindow = !!opts.previewwindow + this._winid = opts.winid + this.variables = opts.variables || {} + this._changedtick = opts.changedtick + this.eol = opts.eol == 1 + this._uri = getUri(opts.fullpath, this.bufnr, buftype, this.env.isCygwin) + if (Array.isArray(opts.lines)) { + this.lines = opts.lines + this._noFetch = true + this._attached = true + this.attach() + } + this._filetype = this.convertFiletype(opts.filetype) + this.setIskeyword(opts.iskeyword) + this.createTextDocument(1, this.lines) + } + + private attach(): void { + if (this.env.isVim) return + let lines = this.lines + this.buffer.attach(true).then(res => { + if (!res) fireDetach(this.bufnr) + }, _e => { + fireDetach(this.bufnr) + }) + this.buffer.listen('lines', (buf: Buffer, tick: number, firstline: number, lastline: number, linedata: string[]) => { + if (buf.id !== this.bufnr || !this._attached || tick == null) return + if (tick > this._changedtick) { + this._changedtick = tick + lines = [...lines.slice(0, firstline), ...linedata, ...(lastline == -1 ? [] : lines.slice(lastline))] + if (lines.length == 0) lines = [''] + this.lines = lines + fireLinesChanged(buf.id) + if (events.pumvisible) return + this.fireContentChanges() + } + }, this.disposables) + this.buffer.listen('detach', () => { + fireDetach(this.bufnr) + }, this.disposables) + } + + /** + * Check if document changed after last synchronize + */ + public get dirty(): boolean { + // if (this.lines === this.syncLines) return false + // return !equals(this.lines, this.syncLines) + return this.lines !== this.syncLines + } + + public get hasChanged(): boolean { + if (!this.dirty) return false + return !equals(this.lines, this.syncLines) + } + + private _fireContentChanges(edit?: TextEdit): void { + if (this.lines === this.syncLines) return + let textDocument = this._textDocument + let changes: TextDocumentContentChange[] = [] + if (!edit) { + let { cursor, insertMode } = events + let pos: Position + // consider cursor position. + if (cursor && cursor.bufnr == this.bufnr) { + let content = this.lines[cursor.lnum - 1] ?? '' + pos = Position.create(cursor.lnum - 1, characterIndex(content, cursor.col - 1)) + } + edit = getTextEdit(textDocument.lines, this.lines, pos, insertMode) + } + let original: string + if (edit) { + original = textDocument.getText(edit.range) + changes.push({ range: edit.range, text: edit.newText, rangeLength: original.length }) + } else { + original = '' + } + let created = this.createTextDocument(this.version + (edit ? 1 : 0), this.lines) + this._onDocumentChange.fire(Object.freeze({ + bufnr: this.bufnr, + original, + originalLines: textDocument.lines, + textDocument: { version: created.version, uri: this.uri }, + contentChanges: changes + })) + } + + public async applyEdits(edits: TextEdit[], joinUndo = false, move: boolean | Position = false): Promise { + if (Array.isArray(arguments[1])) edits = arguments[1] + if (!this._attached || edits.length === 0) return + this._forceSync() + let textDocument = this.textDocument + edits = filterSortEdits(textDocument, edits) + if (edits.length === 0) return + // apply edits to current textDocument + let newLines = applyEdits(textDocument, edits) + if (!newLines) return + let lines = textDocument.lines + let changed = diffLines(lines, newLines, edits[0].range.start.line) + if (changed.start === changed.end && changed.replacement.length == 0) return + // append new lines + let isAppend = changed.start === changed.end && changed.start === lines.length + (this.eol ? 0 : 1) + let original = lines.slice(changed.start, changed.end) + let changes: TextChangeItem[] = [] + // avoid out of range and lines replacement. + if (this.nvim.hasFunction('nvim_buf_set_text') + && edits.length < 200 + && changed.start !== changed.end + && edits[edits.length - 1].range.end.line < lines.length + (this.eol ? 0 : 1) + ) { + changes = toTextChanges(lines, edits) + } + let cursor: [number, number] + let isCurrent = events.bufnr == this.bufnr + let col: number + if (move && isCurrent && !isAppend) { + let pos = Position.is(move) ? move : undefined + if (move === true && this.bufnr === events.cursor?.bufnr) { + let { col, lnum } = events.cursor + pos = Position.create(lnum - 1, characterIndex(this.lines[lnum - 1], col - 1)) + } + if (pos) { + let position = getPositionFromEdits(pos, edits) + if (comparePosition(pos, position) !== 0) { + let content = newLines[position.line] ?? '' + let col = byteIndex(content, position.character) + 1 + cursor = [position.line + 1, col] + } + col = byteIndex(this.lines[pos.line], pos.character) + 1 + } + } + this.nvim.pauseNotification() + if (isCurrent && joinUndo) this.nvim.command('undojoin', true) + if (isAppend) { + this.buffer.setLines(changed.replacement, { start: -1, end: -1 }, true) + } else { + this.nvim.call('coc#ui#set_lines', [ + this.bufnr, + this._changedtick, + original, + changed.replacement, + changed.start, + changed.end, + changes, + cursor, + col + ], true) + } + this.nvim.resumeNotification(isCurrent, true) + let textEdit = edits.length == 1 ? edits[0] : mergeTextEdits(edits, lines, newLines) + await waitNextTick() + this.lines = newLines + fireLinesChanged(this.bufnr) + this.fireContentChanges.clear() + this._fireContentChanges(textEdit) + let range = Range.create(changed.start, 0, changed.start + changed.replacement.length, 0) + return TextEdit.replace(range, original.join('\n') + '\n') + } + + public async changeLines(lines: [number, string][]): Promise { + let filtered: [number, string][] = [] + let newLines = this.lines.slice() + for (let [lnum, text] of lines) { + if (newLines[lnum] != text) { + filtered.push([lnum, text]) + newLines[lnum] = text + } + } + if (!filtered.length) return + this.nvim.call('coc#ui#change_lines', [this.bufnr, filtered], true) + this.nvim.redrawVim() + this.lines = newLines + fireLinesChanged(this.bufnr) + this._forceSync() + } + + public _forceSync(): void { + this.fireContentChanges.clear() + this._fireContentChanges() + } + + public forceSync(): void { + // may cause bugs, prevent extensions use it. + if (global.hasOwnProperty('__TEST__')) { + this._forceSync() + } + } + + /** + * Get offset from lnum & col + */ + public getOffset(lnum: number, col: number): number { + return this.textDocument.offsetAt({ + line: lnum - 1, + character: col + }) + } + + /** + * Check string is word. + */ + public isWord(word: string): boolean { + return this.chars.isKeyword(word) + } + + public async matchWords(token: CancellationToken): Promise | undefined> { + return await this.chars.matchLines(this.textDocument.lines, 2, token) + } + /** + * Current word for replacement + */ + public getWordRangeAtPosition(position: Position, extraChars?: string, current = true): Range | null { + let chars = this.chars.clone() + if (extraChars && extraChars.length) { + for (let ch of extraChars) { + chars.addKeyword(ch) + } + } + let line = this.getline(position.line, current) + let ch = line[position.character] + if (ch == null || !chars.isKeywordChar(ch)) return null + let start = position.character + let end = position.character + 1 + while (start >= 0) { + let ch = line[start - 1] + if (!ch || !chars.isKeywordChar(ch)) break + start = start - 1 + } + while (end <= line.length) { + let ch = line[end] + if (!ch || !chars.isKeywordChar(ch)) break + end = end + 1 + } + return Range.create(position.line, start, position.line, end) + } + + private createTextDocument(version: number, lines: ReadonlyArray): LinesTextDocument { + let { uri, languageId, eol } = this + let textDocument = this._textDocument = new LinesTextDocument(uri, languageId, version, lines, this.bufnr, eol) + return textDocument + } + + /** + * Used by vim for fetch new lines. + */ + private async _fetchContent(sync?: boolean): Promise { + if (!this.env.isVim || !this._attached) return + let { nvim, bufnr, changedtick } = this + let o = await nvim.call('coc#util#get_buf_lines', [bufnr, changedtick]) + this._noFetch = true + if (o) { + this._changedtick = o.changedtick + this.lines = o.lines + fireLinesChanged(this.bufnr) + if (sync) { + this._forceSync() + } else { + this.fireContentChanges() + } + } else if (sync) { + this._forceSync() + } + } + + /** + * Only used on vim8 for set new line with TextChangedP + */ + public changeLine(lnum: number, line: string, changedtick: number): void { + let curr = this.lines[lnum - 1] + if (curr === undefined) return + let newLines = this.lines.slice() + newLines[lnum - 1] = line + this.lines = newLines + fireLinesChanged(this.bufnr) + this._changedtick = changedtick + } + + /** + * Get and synchronize change + */ + public async patchChange(currentLine?: boolean): Promise { + if (!this._attached) return + if (this.env.isVim) { + if (currentLine) { + let change = await this.nvim.call('coc#util#get_changeinfo', []) as ChangeInfo + if (change.bufnr !== this.bufnr) return + if (change.changedtick < this._changedtick) { + this._forceSync() + return + } + let { lnum, line, changedtick } = change + let curr = this.getline(lnum - 1) + this._changedtick = changedtick + if (curr == line) { + this._forceSync() + } else { + let newLines = this.lines.slice() + newLines[lnum - 1] = line + this.lines = newLines + fireLinesChanged(this.bufnr) + this._forceSync() + } + } else { + this.fetchContent.clear() + await this._fetchContent(true) + } + } else { + // changedtick from buffer events could be not latest. #3003 + this._changedtick = await this.buffer.getVar('changedtick') as number + this._forceSync() + } + } + + /** + * Get ranges of word in textDocument. + */ + public getSymbolRanges(word: string): Range[] { + let { version, filetype, uri } = this + let textDocument = new LinesTextDocument(uri, filetype, version, this.lines, this.bufnr, this.eol) + let res: Range[] = [] + let content = textDocument.getText() + let str = '' + for (let i = 0, l = content.length; i < l; i++) { + let ch = content[i] + if ('-' == ch && str.length == 0) { + continue + } + let isKeyword = this.chars.isKeywordChar(ch) + if (isKeyword) { + str = str + ch + } + if (str.length > 0 && !isKeyword && str == word) { + res.push(Range.create(textDocument.positionAt(i - str.length), textDocument.positionAt(i))) + } + if (!isKeyword) { + str = '' + } + } + return res + } + + /** + * Adjust col with new valid character before position. + */ + public fixStartcol(position: Position, valids: string[]): number { + let line = this.getline(position.line) + if (!line) return null + let { character } = position + let start = line.slice(0, character) + let col = byteLength(start) + let { chars } = this + for (let i = start.length - 1; i >= 0; i--) { + let c = start[i] + if (c == ' ') break + if (!chars.isKeywordChar(c) && !valids.includes(c)) { + break + } + col = col - byteLength(c) + } + return col + } + + /** + * Add vim highlight items from highlight group and range. + * Synchronized lines are used for calculate cols. + */ + public addHighlights(items: HighlightItem[], hlGroup: string, range: Range, opts: HighlightItemOption = {}): void { + let { start, end } = range + if (emptyRange(range)) return + for (let line = start.line; line <= end.line; line++) { + const text = this.getline(line, false) + let colStart = line == start.line ? byteIndex(text, start.character) : 0 + let colEnd = line == end.line ? byteIndex(text, end.character) : global.Buffer.byteLength(text) + if (colStart >= colEnd) continue + items.push(Object.assign({ hlGroup, lnum: line, colStart, colEnd }, opts)) + } + } + + /** + * Real current line + */ + public getline(line: number, current = true): string { + if (current) return this.lines[line] || '' + return this.syncLines[line] || '' + } + + /** + * Get lines, zero indexed, end exclude. + */ + public getLines(start?: number, end?: number): string[] { + return this.lines.slice(start ?? 0, end ?? this.lines.length) + } + + /** + * Get current content text. + */ + public getDocumentContent(): string { + let content = this.lines.join('\n') + return this.eol ? content + '\n' : content + } + + /** + * Get variable value by key, defined by `b:coc_{key}` + */ + public getVar(key: string, defaultValue?: T): T { + let val = this.variables[`coc_${key}`] as T + return val === undefined ? defaultValue : val + } + + /** + * Get position from lnum & col + */ + public getPosition(lnum: number, col: number): Position { + let line = this.getline(lnum - 1) + if (!line || col == 0) return { line: lnum - 1, character: 0 } + let pre = byteSlice(line, 0, col - 1) + return { line: lnum - 1, character: pre.length } + } + + /** + * Get end offset from cursor position. + * For normal mode, use offset - 1 when possible + */ + public getEndOffset(lnum: number, col: number, insert: boolean): number { + let total = 0 + let len = this.lines.length + for (let i = lnum - 1; i < len; i++) { + let line = this.lines[i] + let l = line.length + if (i == lnum - 1 && l != 0) { + // current + let buf = global.Buffer.from(line, 'utf8') + let isEnd = buf.byteLength <= col - 1 + if (!isEnd) { + total = total + buf.slice(col - 1, buf.length).toString('utf8').length + if (!insert) total = total - 1 + } + } else { + total = total + l + } + if (!this.eol && i == len - 1) break + total = total + 1 + } + return total + } + + /** + * Recreate document with new filetype. + */ + public setFiletype(filetype: string): void { + this._filetype = this.convertFiletype(filetype) + let lines = this._textDocument.lines + this._textDocument = new LinesTextDocument(this.uri, this.languageId, 1, lines, this.bufnr, this.eol) + } + + /** + * Change iskeyword option of document + */ + public setIskeyword(iskeyword: string): void { + let chars = this.chars = new Chars(iskeyword) + let additional = this.getVar('additional_keywords', []) + if (additional && Array.isArray(additional)) { + for (let ch of additional) { + chars.addKeyword(ch) + } + } + } + + /** + * Detach document. + */ + public detach(): void { + if (this._disposed) return + disposeAll(this.disposables) + this._disposed = true + this._attached = false + this.lines = [] + this.fetchContent.clear() + this.fireContentChanges.clear() + this._onDocumentChange.dispose() + } + + /** + * Get localify bonus map. + */ + public getLocalifyBonus(sp: Position, ep: Position, max?: number): Map { + return this.chars.getLocalifyBonus(sp, ep, this.lines, max) + } + + /** + * Synchronize latest document content + */ + public async synchronize(): Promise { + if (!this.attached) return + let { changedtick } = this + await this.patchChange() + if (changedtick != this.changedtick) { + await wait(50) + } + } + + /** + * Used by vim8 to fetch lines. + */ + public onTextChange(event: string, change?: InsertChange): void { + if (event === 'TextChanged' + || (event === 'TextChangedI' && !change.insertChar) + || !this._noFetch) { + this._noFetch = false + this.fetchContent() + return + } + let { line, changedtick, lnum } = change + if (changedtick === this.changedtick) return + this.changeLine(lnum, line, changedtick) + if (event !== 'TextChangedP') this._forceSync() + } + + public onCursorHold(variables: { [key: string]: VimValue }): void { + this.variables = variables + } +} + +function fireDetach(bufnr: number): void { + void events.fire('BufDetach', [bufnr]) +} + +function fireLinesChanged(bufnr: number): void { + void events.fire('LinesChanged', [bufnr]) +} diff --git a/sources_non_forked/coc.nvim/src/model/download.ts b/sources_non_forked/coc.nvim/src/model/download.ts new file mode 100644 index 00000000..87e03bfd --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/download.ts @@ -0,0 +1,144 @@ +'use strict' +import contentDisposition from 'content-disposition' +import { http, https } from 'follow-redirects' +import fs, { Stats } from 'fs-extra' +import { IncomingMessage } from 'http' +import path from 'path' +import tar from 'tar' +import unzip from 'unzip-stream' +import { v1 as uuidv1 } from 'uuid' +import { CancellationToken } from 'vscode-languageserver-protocol' +import { resolveRequestOptions, FetchOptions } from './fetch' +const logger = require('../util/logger')('model-download') + +export interface DownloadOptions extends Omit { + /** + * Folder that contains downloaded file or extracted files by untar or unzip + */ + dest: string + /** + * Remove the specified number of leading path elements for *untar* only, default to `1`. + */ + strip?: number + /** + * If true, use untar for `.tar.gz` filename + */ + extract?: boolean | 'untar' | 'unzip' + onProgress?: (percent: string) => void +} + +/** + * Download file from url, with optional untar/unzip support. + * + * @param {string} url + * @param {DownloadOptions} options contains dest folder and optional onProgress callback + */ +export default function download(url: string, options: DownloadOptions, token?: CancellationToken): Promise { + let { dest, onProgress, extract } = options + if (!dest || !path.isAbsolute(dest)) { + throw new Error(`Expect absolute file path for dest option.`) + } + let stat: Stats + try { + stat = fs.statSync(dest) + } catch (_e) { + fs.mkdirpSync(dest) + } + if (stat && !stat.isDirectory()) { + throw new Error(`${dest} exists, but not directory!`) + } + let mod = url.startsWith('https') ? https : http + let opts = resolveRequestOptions(url, options) + let extname = path.extname(url) + return new Promise((resolve, reject) => { + if (token) { + let disposable = token.onCancellationRequested(() => { + disposable.dispose() + req.destroy(new Error('request aborted')) + }) + } + let timer: NodeJS.Timer + const req = mod.request(opts, (res: IncomingMessage) => { + if ((res.statusCode >= 200 && res.statusCode < 300) || res.statusCode === 1223) { + let headers = res.headers || {} + let dispositionHeader = headers['content-disposition'] + if (!extname && dispositionHeader) { + let disposition = contentDisposition.parse(dispositionHeader) + if (disposition.parameters?.filename) { + extname = path.extname(disposition.parameters.filename) + } + } + if (extract === true) { + if (extname === '.zip' || headers['content-type'] == 'application/zip') { + extract = 'unzip' + } else if (extname == '.tgz') { + extract = 'untar' + } else { + reject(new Error(`Unable to extract for ${url}`)) + return + } + } + let total = Number(headers['content-length']) + let cur = 0 + if (!isNaN(total)) { + res.on('data', chunk => { + cur += chunk.length + let percent = (cur / total * 100).toFixed(1) + if (onProgress) { + onProgress(percent) + } else { + logger.info(`Download ${url} progress ${percent}%`) + } + }) + } + res.on('error', err => { + reject(new Error(`Unable to connect ${url}: ${err.message}`)) + }) + res.on('data', () => { + if (timer) { + clearTimeout(timer) + timer = undefined + } + }) + res.on('end', () => { + logger.info('Download completed:', url) + }) + let stream: any + if (extract === 'untar') { + stream = res.pipe(tar.x({ strip: options.strip ?? 1, C: dest })) + } else if (extract === 'unzip') { + stream = res.pipe(unzip.Extract({ path: dest })) + } else { + dest = path.join(dest, `${uuidv1()}${extname}`) + stream = res.pipe(fs.createWriteStream(dest)) + } + stream.on('finish', () => { + logger.info(`Downloaded ${url} => ${dest}`) + setTimeout(() => { + resolve(dest) + }, 100) + }) + stream.on('error', reject) + } else { + reject(new Error(`Invalid response from ${url}: ${res.statusCode}`)) + } + }) + req.on('error', e => { + // Possible succeed proxy request with ECONNRESET error on node > 14 + if (opts.agent && e.code == 'ECONNRESET') { + timer = setTimeout(() => { + reject(e) + }, 500) + } else { + reject(e) + } + }) + req.on('timeout', () => { + req.destroy(new Error(`request timeout after ${options.timeout}ms`)) + }) + if (options.timeout) { + req.setTimeout(options.timeout) + } + req.end() + }) +} diff --git a/sources_non_forked/coc.nvim/src/model/editInspect.ts b/sources_non_forked/coc.nvim/src/model/editInspect.ts new file mode 100644 index 00000000..6da7fb79 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/editInspect.ts @@ -0,0 +1,216 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fastDiff from 'fast-diff' +import path from 'path' +import { Disposable } from 'vscode-languageserver-protocol' +import { ChangeAnnotation, CreateFile, DeleteFile, Position, RenameFile, TextDocumentEdit, WorkspaceEdit } from 'vscode-languageserver-types' +import { URI } from 'vscode-uri' +import type Keymaps from '../core/keymaps' +import events from '../events' +import { DocumentChange, LinesChange } from '../types' +import { disposeAll } from '../util' +import { isParentFolder } from '../util/fs' +import { getAnnotationKey, getPositionFromEdits, mergeSort } from '../util/textedit' +import Highlighter from './highligher' +const logger = require('../util/logger')('mdoe-editInspect') + +export type RecoverFunc = () => Promise + +export interface EditState { + edit: WorkspaceEdit + changes: { + [uri: string]: LinesChange + } + recovers: RecoverFunc[] + applied: boolean +} + +export interface ChangedFileItem { + index: number + filepath: string + lnum?: number +} + +let global_id = 0 + +export default class EditInspect { + private disposables: Disposable[] = [] + private bufnr: number + private items: ChangedFileItem[] = [] + private renameMap: Map = new Map() + constructor(private nvim: Neovim, private keymaps: Keymaps) { + events.on('BufUnload', bufnr => { + if (bufnr == this.bufnr) this.dispose() + }, null, this.disposables) + } + + private addFile(filepath: string, highligher: Highlighter, lnum?: number): void { + this.items.push({ + index: highligher.length, + filepath, + lnum + }) + } + + public async show(state: EditState): Promise { + let { nvim } = this + let id = global_id++ + nvim.pauseNotification() + nvim.command(`tabe +setl\\ buftype=nofile CocWorkspaceEdit${id}`, true) + nvim.command(`setl bufhidden=wipe nolist`, true) + nvim.command('setl nobuflisted wrap undolevels=-1 filetype=cocedits noswapfile', true) + await nvim.resumeNotification(true) + let buffer = await nvim.buffer + let cwd = await nvim.call('getcwd') + this.bufnr = buffer.id + const relpath = (uri: string): string => { + let fsPath = URI.parse(uri).fsPath + return isParentFolder(cwd, fsPath, true) ? path.relative(cwd, fsPath) : fsPath + } + const absPath = filepath => { + return path.isAbsolute(filepath) ? filepath : path.join(cwd, filepath) + } + let highligher = new Highlighter() + let map = grouByAnnotation(state.edit.documentChanges ?? [], state.edit.changeAnnotations ?? {}) + for (let [label, changes] of map.entries()) { + if (label) { + highligher.addLine(label, 'MoreMsg') + highligher.addLine('') + } + for (let change of changes) { + if (TextDocumentEdit.is(change)) { + let linesChange = state.changes[change.textDocument.uri] + let fsPath = relpath(change.textDocument.uri) + highligher.addTexts([ + { text: 'Change', hlGroup: 'Title' }, + { text: ' ' }, + { text: fsPath, hlGroup: 'Directory' }, + { text: `:${linesChange.lnum}`, hlGroup: 'LineNr' }, + ]) + this.addFile(fsPath, highligher, linesChange.lnum) + highligher.addLine('') + this.addChangedLines(highligher, linesChange, fsPath, linesChange.lnum) + highligher.addLine('') + } else if (CreateFile.is(change) || DeleteFile.is(change)) { + let title = DeleteFile.is(change) ? 'Delete' : 'Create' + let fsPath = relpath(change.uri) + highligher.addTexts([ + { text: title, hlGroup: 'Title' }, + { text: ' ' }, + { text: fsPath, hlGroup: 'Directory' } + ]) + this.addFile(fsPath, highligher) + highligher.addLine('') + } else if (RenameFile.is(change)) { + let oldPath = relpath(change.oldUri) + let newPath = relpath(change.newUri) + highligher.addTexts([ + { text: 'Rename', hlGroup: 'Title' }, + { text: ' ' }, + { text: oldPath, hlGroup: 'Directory' }, + { text: '->', hlGroup: 'Comment' }, + { text: newPath, hlGroup: 'Directory' } + ]) + this.renameMap.set(oldPath, newPath) + this.addFile(newPath, highligher) + highligher.addLine('') + } + } + } + nvim.pauseNotification() + highligher.render(buffer) + buffer.setOption('modifiable', false, true) + await nvim.resumeNotification(true) + this.disposables.push(this.keymaps.registerLocalKeymap('n', '', async () => { + let lnum = await nvim.call('line', '.') + let col = await nvim.call('col', '.') + let find: ChangedFileItem + for (let i = this.items.length - 1; i >= 0; i--) { + let item = this.items[i] + if (lnum >= item.index) { + find = item + break + } + } + if (!find) return + let uri = URI.file(absPath(find.filepath)).toString() + let filepath = this.renameMap.has(find.filepath) ? this.renameMap.get(find.filepath) : find.filepath + await nvim.call('coc#util#open_file', ['tab drop', absPath(filepath)]) + // need change old lnum to new lnum + if (typeof find.lnum === 'number') { + let changes = state.edit.documentChanges ?? [] + let change = changes.find(o => TextDocumentEdit.is(o) && o.textDocument.uri == uri) as TextDocumentEdit + let lnum = find.lnum + if (change) { + let edits = mergeSort(change.edits, (a, b) => { + let diff = a.range.start.line - b.range.start.line + if (diff === 0) { + return a.range.start.character - b.range.start.character + } + return diff + }) + let pos = getPositionFromEdits(Position.create(lnum - 1, 0), edits) + lnum = pos.line + 1 + } + await nvim.call('cursor', [lnum, col]) + } + nvim.redrawVim() + }, true)) + this.disposables.push(this.keymaps.registerLocalKeymap('n', '', async () => { + nvim.command('bwipeout!', true) + }, true)) + } + + public addChangedLines(highligher: Highlighter, linesChange: LinesChange, fsPath: string, lnum: number): void { + let diffs = fastDiff(linesChange.oldLines.join('\n'), linesChange.newLines.join('\n')) + for (let i = 0; i < diffs.length; i++) { + let diff = diffs[i] + if (diff[0] == fastDiff.EQUAL) { + let text = diff[1] + if (!text.includes('\n')) { + highligher.addText(text) + } else { + let parts = text.split('\n') + highligher.addText(parts[0]) + let curr = lnum + parts.length - 1 + highligher.addLine('') + highligher.addTexts([ + { text: 'Change', hlGroup: 'Title' }, + { text: ' ' }, + { text: fsPath, hlGroup: 'Directory' }, + { text: `:${curr}`, hlGroup: 'LineNr' }, + ]) + this.addFile(fsPath, highligher, curr) + highligher.addLine('') + let last = parts[parts.length - 1] + if (last.length > 0) highligher.addText(last) + } + lnum += text.split('\n').length - 1 + } else if (diff[0] == fastDiff.DELETE) { + lnum += diff[1].split('\n').length - 1 + highligher.addText(diff[1], 'DiffDelete') + } else if (diff[0] == fastDiff.INSERT) { + highligher.addText(diff[1], 'DiffAdd') + } + } + } + + public dispose(): void { + disposeAll(this.disposables) + } +} + +export function grouByAnnotation(changes: DocumentChange[], annotations: { [id: string]: ChangeAnnotation }): Map { + let map: Map = new Map() + for (let change of changes) { + let id = getAnnotationKey(change) ?? null + let key = id ? annotations[id].label ?? null : null + let arr = map.get(key) + if (arr) { + arr.push(change) + } else { + map.set(key, [change]) + } + } + return map +} diff --git a/sources_non_forked/coc.nvim/src/model/fetch.ts b/sources_non_forked/coc.nvim/src/model/fetch.ts new file mode 100644 index 00000000..ca9f7035 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/fetch.ts @@ -0,0 +1,269 @@ +'use strict' +import { http, https } from 'follow-redirects' +import { Readable } from 'stream' +import { parse, UrlWithStringQuery } from 'url' +import fs from 'fs' +import { objectLiteral } from '../util/is' +import workspace from '../workspace' +import { stringify } from 'querystring' +import createHttpProxyAgent, { HttpProxyAgent } from 'http-proxy-agent' +import createHttpsProxyAgent, { HttpsProxyAgent } from 'https-proxy-agent' +import { CancellationToken } from 'vscode-languageserver-protocol' +import decompressResponse from 'decompress-response' +const logger = require('../util/logger')('model-fetch') + +export type ResponseResult = string | Buffer | { [name: string]: any } + +export interface ProxyOptions { + proxyUrl: string + strictSSL?: boolean + proxyAuthorization?: string | null + proxyCA?: string | null +} + +export interface FetchOptions { + /** + * Default to 'GET' + */ + method?: string + /** + * Default no timeout + */ + timeout?: number + /** + * Always return buffer instead of parsed response. + */ + buffer?: boolean + /** + * - 'string' for text response content + * - 'object' for json response content + * - 'buffer' for response not text or json + */ + data?: string | { [key: string]: any } | Buffer + /** + * Plain object added as query of url + */ + query?: { [key: string]: unknown } + headers?: any + /** + * User for http basic auth, should use with password + */ + user?: string + /** + * Password for http basic auth, should use with user + */ + password?: string +} + +function getSystemProxyURI(endpoint: UrlWithStringQuery): string { + let env: string | null + if (endpoint.protocol === 'http:') { + env = process.env.HTTP_PROXY || process.env.http_proxy || null + } else if (endpoint.protocol === 'https:') { + env = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || null + } + let noProxy = process.env.NO_PROXY || process.env.no_proxy + if (noProxy === '*') { + env = null + } else if (noProxy) { + // canonicalize the hostname, so that 'oogle.com' won't match 'google.com' + const hostname = endpoint.hostname.replace(/^\.*/, '.').toLowerCase() + const port = endpoint.port || endpoint.protocol.startsWith('https') ? '443' : '80' + const noProxyList = noProxy.split(',') + for (let i = 0, len = noProxyList.length; i < len; i++) { + let noProxyItem = noProxyList[i].trim().toLowerCase() + // no_proxy can be granular at the port level, which complicates things a bit. + if (noProxyItem.includes(':')) { + let noProxyItemParts = noProxyItem.split(':', 2) + let noProxyHost = noProxyItemParts[0].replace(/^\.*/, '.') + let noProxyPort = noProxyItemParts[1] + if (port === noProxyPort && hostname.endsWith(noProxyHost)) { + env = null + break + } + } else { + noProxyItem = noProxyItem.replace(/^\.*/, '.') + if (hostname.endsWith(noProxyItem)) { + env = null + break + } + } + } + } + return env +} + +export function getAgent(endpoint: UrlWithStringQuery, options: ProxyOptions): HttpsProxyAgent | HttpProxyAgent { + let proxy = options.proxyUrl || getSystemProxyURI(endpoint) + if (proxy) { + const proxyEndpoint = parse(proxy) + if (!/^https?:$/.test(proxyEndpoint.protocol)) { + return null + } + let opts = { + host: proxyEndpoint.hostname, + port: proxyEndpoint.port ? Number(proxyEndpoint.port) : (proxyEndpoint.protocol === 'https' ? '443' : '80'), + auth: proxyEndpoint.auth, + rejectUnauthorized: typeof options.strictSSL === 'boolean' ? options.strictSSL : true + } + logger.info(`Using proxy ${proxy} from ${options.proxyUrl ? 'configuration' : 'system environment'} for ${endpoint.hostname}:`) + return endpoint.protocol === 'http:' ? createHttpProxyAgent(opts) : createHttpsProxyAgent(opts) + } + return null +} + +export function resolveRequestOptions(url: string, options: FetchOptions = {}): any { + let config = workspace.getConfiguration('http') + let { data } = options + let dataType = getDataType(data) + let proxyOptions: ProxyOptions = { + proxyUrl: config.get('proxy', ''), + strictSSL: config.get('proxyStrictSSL', true), + proxyAuthorization: config.get('proxyAuthorization', null), + proxyCA: config.get('proxyCA', null) + } + if (options.query && !url.includes('?')) { + url = `${url}?${stringify(options.query)}` + } + let headers = Object.assign(options.headers || {}, { 'Proxy-Authorization': proxyOptions.proxyAuthorization }) + let endpoint = parse(url) + let agent = getAgent(endpoint, proxyOptions) + let opts: any = { + method: options.method || 'GET', + hostname: endpoint.hostname, + port: endpoint.port ? parseInt(endpoint.port, 10) : (endpoint.protocol === 'https:' ? 443 : 80), + path: endpoint.path, + agent, + rejectUnauthorized: proxyOptions.strictSSL, + maxRedirects: 3, + headers: Object.assign({ + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)', + 'Accept-Encoding': 'gzip, deflate' + }, headers) + } + if (proxyOptions.proxyCA) { + opts.ca = fs.readFileSync(proxyOptions.proxyCA) + } + if (dataType == 'object') { + opts.headers['Content-Type'] = 'application/json' + } else if (dataType == 'string') { + opts.headers['Content-Type'] = 'text/plain' + } + if (options.user && options.password) { + opts.auth = options.user + ':' + options.password + } + if (options.timeout) { + opts.timeout = options.timeout + } + if (options.buffer) opts.buffer = true + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return opts +} + +function request(url: string, data: any, opts: any, token?: CancellationToken): Promise { + let mod = url.startsWith('https:') ? https : http + return new Promise((resolve, reject) => { + if (token) { + let disposable = token.onCancellationRequested(() => { + disposable.dispose() + req.destroy(new Error('request aborted')) + }) + } + let timer: NodeJS.Timer + const req = mod.request(opts, res => { + let readable: Readable = res + if ((res.statusCode >= 200 && res.statusCode < 300) || res.statusCode === 1223) { + let headers = res.headers || {} + let chunks: Buffer[] = [] + let contentType: string = headers['content-type'] || '' + readable = decompressResponse(res) + readable.on('data', chunk => { + chunks.push(chunk) + }) + readable.on('end', () => { + if (timer) clearTimeout(timer) + let buf = Buffer.concat(chunks) + if (!opts.buffer && (contentType.startsWith('application/json') || contentType.startsWith('text/'))) { + let ms = contentType.match(/charset=(\S+)/) + let encoding = ms ? ms[1] : 'utf8' + let rawData = buf.toString(encoding as BufferEncoding) + if (!contentType.includes('application/json')) { + resolve(rawData) + } else { + try { + const parsedData = JSON.parse(rawData) + resolve(parsedData) + } catch (e) { + reject(new Error(`Parse response error: ${e}`)) + } + } + } else { + resolve(buf) + } + }) + readable.on('error', err => { + reject(new Error(`Unable to connect ${url}: ${err.message}`)) + }) + } else { + reject(new Error(`Bad response from ${url}: ${res.statusCode}`)) + } + }) + req.on('error', e => { + // Possible succeed proxy request with ECONNRESET error on node > 14 + if (opts.agent && e.code == 'ECONNRESET') { + timer = setTimeout(() => { + reject(e) + }, 500) + } else { + reject(e) + } + }) + req.on('timeout', () => { + req.destroy(new Error(`Request timeout after ${opts.timeout}ms`)) + }) + if (data) { + if (typeof data === 'string' || Buffer.isBuffer(data)) { + req.write(data) + } else { + req.write(JSON.stringify(data)) + } + } + if (opts.timeout) { + req.setTimeout(opts.timeout) + } + req.end() + }) +} + +function getDataType(data: any): string { + if (data === null) return 'null' + if (data === undefined) return 'undefined' + if (typeof data == 'string') return 'string' + if (Buffer.isBuffer(data)) return 'buffer' + if (Array.isArray(data) || objectLiteral(data)) return 'object' + return 'unknown' +} + +/** + * Send request to server for response, supports: + * + * - Send json data and parse json response. + * - Throw error for failed response statusCode. + * - Timeout support (no timeout by default). + * - Send buffer (as data) and receive data (as response). + * - Proxy support from user configuration & environment. + * - Redirect support, limited to 3. + * - Support of gzip & deflate response content. + */ +export default function fetch(url: string, options: FetchOptions = {}, token?: CancellationToken): Promise { + let opts = resolveRequestOptions(url, options) + return request(url, options.data, opts, token).catch(err => { + logger.error(`Fetch error for ${url}:`, opts, err) + if (opts.agent && opts.agent.proxy) { + let { proxy } = opts.agent + throw new Error(`Request failed using proxy ${proxy.host}: ${err.message}`) + } else { + throw err + } + }) +} diff --git a/sources_non_forked/coc.nvim/src/model/floatFactory.ts b/sources_non_forked/coc.nvim/src/model/floatFactory.ts new file mode 100644 index 00000000..ca7a3767 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/floatFactory.ts @@ -0,0 +1,242 @@ +'use strict' +import { Buffer, Neovim, Window } from '@chemzqm/neovim' +import debounce from 'debounce' +import { Disposable } from 'vscode-languageserver-protocol' +import events, { BufEvents } from '../events' +import { parseDocuments } from '../markdown' +import { Documentation, FloatConfig } from '../types' +import { disposeAll } from '../util' +import { Mutex } from '../util/mutex' +import { equals } from '../util/object' +const isVim = process.env.VIM_NODE_RPC == '1' +const logger = require('../util/logger')('model-float') + +export interface WindowConfig { + width: number + height: number + col: number + row: number + relative: 'cursor' | 'win' | 'editor' + style?: string + cursorline?: number + title?: string + border?: number[] + autohide?: number + close?: number +} + +export interface FloatWinConfig { + maxHeight?: number + maxWidth?: number + preferTop?: boolean + autoHide?: boolean + offsetX?: number + title?: string + border?: number[] + rounded?: boolean + cursorline?: boolean + close?: boolean + highlight?: string + borderhighlight?: string + modes?: string[] + shadow?: boolean + winblend?: number + focusable?: boolean + excludeImages?: boolean +} + +/** + * Float window/popup factory for create float/popup around current cursor. + */ +export default class FloatFactory implements Disposable { + private winid = 0 + private _bufnr = 0 + private closeTs: number + private targetBufnr: number + private mutex: Mutex = new Mutex() + private disposables: Disposable[] = [] + private cursor: [number, number] + private onCursorMoved: Function & { clear(): void } + constructor(private nvim: Neovim) { + this.onCursorMoved = debounce(this._onCursorMoved.bind(this), 100) + } + + private bindEvents(autoHide: boolean, alignTop: boolean): void { + let eventNames: BufEvents[] = ['InsertLeave', 'InsertEnter', 'BufEnter'] + for (let ev of eventNames) { + events.on(ev, bufnr => { + if (bufnr == this._bufnr) return + this.close() + }, null, this.disposables) + } + events.on('MenuPopupChanged', () => { + // avoid intersect with pum + if (events.pumAlignTop == alignTop) { + this.close() + } + }, null, this.disposables) + this.disposables.push(Disposable.create(() => { + this.onCursorMoved.clear() + })) + events.on('CursorMoved', this.onCursorMoved.bind(this, autoHide), this, this.disposables) + events.on('CursorMovedI', this.onCursorMoved.bind(this, autoHide), this, this.disposables) + } + + public unbind(): void { + if (this.disposables.length) { + disposeAll(this.disposables) + this.disposables = [] + } + } + + public _onCursorMoved(autoHide: boolean, bufnr: number, cursor: [number, number]): void { + if (bufnr == this._bufnr) return + if (bufnr == this.targetBufnr && equals(cursor, this.cursor)) { + // cursor not moved + return + } + if (autoHide || bufnr != this.targetBufnr || !events.insertMode) { + this.close() + return + } + } + + /** + * Create float window/popup at cursor position. + * + * @deprecated use show method instead + */ + public async create(docs: Documentation[], _allowSelection = false, offsetX = 0): Promise { + await this.show(docs, { + offsetX + }) + } + + public applyFloatConfig(conf: FloatWinConfig, opts: FloatConfig): FloatWinConfig { + for (let key of Object.keys(opts)) { + if (key == 'border') { + if (opts.border) { + conf.border = [1, 1, 1, 1] + } + continue + } + conf[key] = opts[key] + } + return conf + } + + /** + * Show documentations in float window/popup around cursor. + * Window and buffer are reused when possible. + * Window is closed automatically on change buffer, InsertEnter, CursorMoved and CursorMovedI. + * + * @param docs List of documentations. + * @param config Configuration for floating window/popup. + */ + public async show(docs: Documentation[], config: FloatWinConfig = {}): Promise { + if (docs.length == 0 || docs.every(doc => doc.content.length == 0)) { + this.close() + return + } + let curr = Date.now() + let release = await this.mutex.acquire() + try { + await this.createPopup(docs, config, curr) + release() + } catch (e) { + this.nvim.echoError(e) + release() + } + } + + private async createPopup(docs: Documentation[], opts: FloatWinConfig, timestamp: number): Promise { + docs = docs.filter(o => o.content.trim().length > 0) + let { lines, codes, highlights } = parseDocuments(docs) + let config: any = { + codes, + highlights, + pumAlignTop: events.pumAlignTop, + preferTop: typeof opts.preferTop === 'boolean' ? opts.preferTop : false, + offsetX: opts.offsetX || 0, + title: opts.title || '', + close: opts.close ? 1 : 0, + rounded: opts.rounded ? 1 : 0, + modes: opts.modes || ['n', 'i', 'ic', 's'] + } + if (!isVim) { + if (typeof opts.winblend === 'number') config.winblend = opts.winblend + if (opts.focusable != null) config.focusable = opts.focusable ? 1 : 0 + if (opts.shadow) config.shadow = 1 + } + if (opts.maxHeight) config.maxHeight = opts.maxHeight + if (opts.maxWidth) config.maxWidth = opts.maxWidth + if (opts.border && !opts.border.every(o => o == 0)) { + config.border = opts.border + } + if (opts.title && !config.border) config.border = [1, 1, 1, 1] + if (opts.highlight) config.highlight = opts.highlight + if (opts.borderhighlight) config.borderhighlight = [opts.borderhighlight] + if (opts.cursorline) config.cursorline = 1 + let autoHide = opts.autoHide == false ? false : true + if (autoHide) config.autohide = 1 + this.unbind() + let arr = await this.nvim.call('coc#dialog#create_cursor_float', [this.winid, this._bufnr, lines, config]) + this.nvim.redrawVim() + if (!arr || arr.length == 0 || this.closeTs > timestamp) { + let winid = arr && arr.length > 0 ? arr[2] : this.winid + if (winid) { + this.winid = 0 + this.nvim.call('coc#float#close', [winid], true) + this.nvim.redrawVim() + } + return + } + let [targetBufnr, cursor, winid, bufnr, alignTop] = arr as [number, [number, number], number, number, number] + this.winid = winid + this._bufnr = bufnr + this.targetBufnr = targetBufnr + this.cursor = cursor + this.bindEvents(autoHide, alignTop == 1) + } + + /** + * Close float window + */ + public close(): void { + let { winid, nvim } = this + this.closeTs = Date.now() + this.unbind() + if (winid) { + this.winid = 0 + nvim.call('coc#float#close', [winid], true) + nvim.redrawVim() + } + } + + public checkRetrigger(bufnr: number): boolean { + if (this.winid && this.targetBufnr == bufnr) return true + return false + } + + public get bufnr(): number { + return this._bufnr + } + + public get buffer(): Buffer | null { + return this.bufnr ? this.nvim.createBuffer(this.bufnr) : null + } + + public get window(): Window | null { + return this.winid ? this.nvim.createWindow(this.winid) : null + } + + public async activated(): Promise { + if (!this.winid) return false + return await this.nvim.call('coc#float#valid', [this.winid]) != 0 + } + + public dispose(): void { + this.cursor = undefined + this.close() + } +} diff --git a/sources_non_forked/coc.nvim/src/model/highligher.ts b/sources_non_forked/coc.nvim/src/model/highligher.ts new file mode 100644 index 00000000..3130853a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/highligher.ts @@ -0,0 +1,136 @@ +'use strict' +import { Buffer } from '@chemzqm/neovim' +import { parseAnsiHighlights } from '../util/ansiparse' +import { byteLength } from '../util/string' +import { HighlightItem } from '../types' + +export interface TextItem { + text: string + hlGroup?: string +} + +/** + * Build highlights, with lines and highlights + */ +export default class Highlighter { + private lines: string[] = [] + private _highlights: HighlightItem[] = [] + + public addLine(line: string, hlGroup?: string): void { + if (line.includes('\n')) { + for (let content of line.split(/\r?\n/)) { + this.addLine(content, hlGroup) + } + return + } + if (hlGroup) { + this._highlights.push({ + lnum: this.lines.length, + colStart: line.match(/^\s*/)[0].length, + colEnd: byteLength(line), + hlGroup + }) + } // '\x1b' + if (line.includes('\x1b')) { + let res = parseAnsiHighlights(line) + for (let hl of res.highlights) { + let { span, hlGroup } = hl + if (span[0] != span[1]) { + this._highlights.push({ + lnum: this.lines.length, + colStart: span[0], + colEnd: span[1], + hlGroup + }) + } + } + this.lines.push(res.line) + } else { + this.lines.push(line) + } + } + + public addLines(lines): void { + this.lines.push(...lines) + } + + /** + * Add texts to new Lines + */ + public addTexts(items: TextItem[]): void { + let len = this.lines.length + let text = '' + for (let item of items) { + let colStart = byteLength(text) + if (item.hlGroup) { + this._highlights.push({ + lnum: len, + colStart, + colEnd: colStart + byteLength(item.text), + hlGroup: item.hlGroup + }) + } + text += item.text + } + this.lines.push(text) + } + + public addText(text: string, hlGroup?: string): void { + let { lines } = this + let pre = lines[lines.length - 1] || '' + if (text.includes('\n')) { + let parts = text.split('\n') + this.addText(parts[0], hlGroup) + for (let line of parts.slice(1)) { + this.addLine(line, hlGroup) + } + return + } + if (hlGroup) { + let colStart = byteLength(pre) + this._highlights.push({ + lnum: lines.length ? lines.length - 1 : 0, + colStart, + colEnd: colStart + byteLength(text), + hlGroup + }) + } + if (lines.length) { + lines[lines.length - 1] = `${pre}${text}` + } else { + lines.push(text) + } + } + + public get length(): number { + return this.lines.length + } + + public getline(line: number): string { + return this.lines[line] || '' + } + + public get highlights(): ReadonlyArray { + return this._highlights + } + + public get content(): string { + return this.lines.join('\n') + } + + // default to replace + public render(buffer: Buffer, start = 0, end = -1): void { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + buffer.setLines(this.lines, { start, end, strictIndexing: false }, true) + for (let item of this._highlights) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + buffer.addHighlight({ + hlGroup: item.hlGroup, + colStart: item.colStart, + colEnd: item.colEnd == null ? -1 : item.colEnd, + line: start + item.lnum, + srcId: -1 + }) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/input.ts b/sources_non_forked/coc.nvim/src/model/input.ts new file mode 100644 index 00000000..f01546f1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/input.ts @@ -0,0 +1,142 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { disposeAll } from '../util' +const logger = require('../util/logger')('model-input') + +export interface InputPreference { + position?: 'cursor' | 'center' + marginTop?: number + border?: [0 | 1, 0 | 1, 0 | 1, 0 | 1] + rounded?: boolean + minWidth?: number + maxWidth?: number + highlight?: string + borderhighlight?: string + /** + * map list key-mappings + */ + list?: boolean +} + +export interface Dimension { + width: number + height: number + row: number + col: number +} + +export type InputOptions = Pick + +type RequestResult = [number, number, [number, number, number, number]] + +export default class InputBox implements Disposable { + private disposables: Disposable[] = [] + private _winid: number | undefined + private _bufnr: number | undefined + private _input: string + private accepted = false + public title: string + public loading: boolean + public borderhighlight: string + // width, height, row, col + private _dimension: [number, number, number, number] = [0, 0, 0, 0] + private readonly _onDidFinish = new Emitter() + private readonly _onDidChange = new Emitter() + public readonly onDidFinish: Event = this._onDidFinish.event + public readonly onDidChange: Event = this._onDidChange.event + constructor(private nvim: Neovim, defaultValue: string) { + this._input = defaultValue + this.disposables.push(this._onDidFinish) + this.disposables.push(this._onDidChange) + let _title: string | undefined + Object.defineProperty(this, 'title', { + set: (newTitle: string) => { + _title = newTitle + if (this._winid) nvim.call('coc#dialog#change_title', [this._winid, newTitle], true) + }, + get: () => { + return _title + } + }) + let _loading = false + Object.defineProperty(this, 'loading', { + set: (loading: boolean) => { + _loading = loading + if (this._winid) nvim.call('coc#dialog#change_loading', [this._winid, loading], true) + }, + get: () => { + return _loading + } + }) + let _borderhighlight: string + Object.defineProperty(this, 'borderhighlight', { + set: (borderhighlight: string) => { + _borderhighlight = borderhighlight + if (this._winid) nvim.call('coc#dialog#change_border_hl', [this._winid, borderhighlight], true) + }, + get: () => { + return _borderhighlight + } + }) + events.on('BufWinLeave', bufnr => { + if (bufnr == this._bufnr) { + this._winid = undefined + this.dispose() + } + }, null, this.disposables) + events.on('PromptInsert', (value, bufnr) => { + if (bufnr == this._bufnr) { + this._input = value + this.accepted = true + this.dispose() + } + }, null, this.disposables) + events.on('TextChangedI', (bufnr, info) => { + if (bufnr == this._bufnr) { + this._input = info.line + this._onDidChange.fire(info.line) + } + }, null, this.disposables) + } + + public get dimension(): Dimension | undefined { + let { _dimension } = this + return { width: _dimension[0], height: _dimension[1], row: _dimension[2], col: _dimension[3] } + } + + public get bufnr(): number | undefined { + return this._bufnr + } + + public get winid(): number | undefined { + return this._winid + } + + public get value(): string { + return this._input + } + + public async show(title: string, preferences: InputPreference): Promise { + this.title = title + this.borderhighlight = preferences.borderhighlight ?? 'CocFloating' + this.loading = false + let res = await this.nvim.call('coc#dialog#create_prompt_win', [title, this._input, preferences]) as RequestResult + if (!res) throw new Error('Unable to open input window') + this._bufnr = res[0] + this._winid = res[1] + this._dimension = res[2] + return true + } + + public dispose(): void { + this._onDidFinish.fire(this.accepted ? this._input : null) + if (this._winid) { + this.nvim.call('coc#float#close', [this._winid], true) + } + this._winid = undefined + this._bufnr = undefined + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/installBuffer.ts b/sources_non_forked/coc.nvim/src/model/installBuffer.ts new file mode 100644 index 00000000..113b30f5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/installBuffer.ts @@ -0,0 +1,152 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import { EventEmitter } from 'events' +import { Disposable } from 'vscode-languageserver-protocol' +import { OutputChannel } from '../types' +import { frames } from './status' +const logger = require('../util/logger')('model-installBuffer') + +export enum State { + Waiting, + Failed, + Progressing, + Success, +} + +export default class InstallBuffer extends EventEmitter implements Disposable { + private statMap: Map = new Map() + private messagesMap: Map = new Map() + private names: string[] = [] + // eslint-disable-next-line no-undef + private interval: NodeJS.Timer + public bufnr: number + + constructor( + private isUpdate = false, + private isSync = false, + private channel: OutputChannel | undefined = undefined) { + super() + } + + public setExtensions(names: string[]): void { + this.statMap.clear() + this.names = names + for (let name of names) { + this.statMap.set(name, State.Waiting) + } + } + + public addMessage(name: string, msg: string, isProgress = false): void { + if (isProgress && this.channel) return + let lines = this.messagesMap.get(name) || [] + this.messagesMap.set(name, lines.concat(msg.trim().split(/\r?\n/))) + if (this.channel) this.channel.appendLine(`[${name}] ${msg}`) + } + + public startProgress(names: string[]): void { + for (let name of names) { + this.statMap.set(name, State.Progressing) + } + } + + public finishProgress(name: string, succeed = true): void { + if (this.channel) { + if (succeed) { + this.channel.appendLine(`[${name}] install succeed!`) + } else { + this.channel.appendLine(`[${name}] install failed!`) + } + } + this.statMap.set(name, succeed ? State.Success : State.Failed) + } + + public get remains(): number { + let count = 0 + for (let name of this.names) { + let stat = this.statMap.get(name) + if (![State.Success, State.Failed].includes(stat)) { + count = count + 1 + } + } + return count + } + + private getLines(): string[] { + let lines: string[] = [] + for (let name of this.names) { + let state = this.statMap.get(name) + let processText = '*' + switch (state) { + case State.Progressing: { + let d = new Date() + let idx = Math.floor(d.getMilliseconds() / 100) + processText = frames[idx] + break + } + case State.Failed: + processText = '✗' + break + case State.Success: + processText = '✓' + break + } + let msgs = this.messagesMap.get(name) || [] + lines.push(`- ${processText} ${name} ${msgs.length ? msgs[msgs.length - 1] : ''}`) + } + return lines + } + + public getMessages(line: number): string[] { + if (line <= 1) return [] + let name = this.names[line - 2] + if (!name) return [] + return this.messagesMap.get(name) + } + + // draw frame + private draw(nvim: Neovim, buffer: Buffer): void { + let { remains } = this + let first = remains == 0 ? `${this.isUpdate ? 'Update' : 'Install'} finished` : `Installing, ${remains} remaining...` + let lines = [first, '', ...this.getLines()] + buffer.setLines(lines, { start: 0, end: -1, strictIndexing: false }, true) + if (remains == 0 && this.interval) { + clearInterval(this.interval) + this.interval = null + } + if (process.env.VIM_NODE_RPC) { + nvim.command('redraw', true) + } + } + + public highlight(nvim: Neovim): void { + nvim.call('matchadd', ['CocListFgCyan', '^\\-\\s\\zs\\*'], true) + nvim.call('matchadd', ['CocListFgGreen', '^\\-\\s\\zs✓'], true) + nvim.call('matchadd', ['CocListFgRed', '^\\-\\s\\zs✗'], true) + nvim.call('matchadd', ['CocListFgYellow', '^-.\\{3\\}\\zs\\S\\+'], true) + } + + public async show(nvim: Neovim): Promise { + let { isSync } = this + if (this.channel) return + nvim.pauseNotification() + nvim.command(isSync ? 'enew' : 'vs +enew', true) + nvim.call('bufnr', ['%'], true) + nvim.command('setl buftype=nofile bufhidden=wipe noswapfile nobuflisted wrap undolevels=-1', true) + if (!isSync) { + nvim.command('nnoremap q :q', true) + } + this.highlight(nvim) + let res = await nvim.resumeNotification() + this.bufnr = res[0][1] as number + let buffer = nvim.createBuffer(this.bufnr) + this.interval = setInterval(() => { + this.draw(nvim, buffer) + }, 100) + } + + public dispose(): void { + if (this.interval) { + clearInterval(this.interval) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/installer.ts b/sources_non_forked/coc.nvim/src/model/installer.ts new file mode 100644 index 00000000..b6e6c25e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/installer.ts @@ -0,0 +1,299 @@ +'use strict' +import { spawn } from 'child_process' +import { EventEmitter } from 'events' +import fs from 'fs-extra' +import { parse, ParseError } from 'jsonc-parser' +import os from 'os' +import path from 'path' +import readline from 'readline' +import semver from 'semver' +import { statAsync } from '../util/fs' +import { omit } from '../util/lodash' +import workspace from '../workspace' +import download from './download' +import fetch from './fetch' +const logger = require('../util/logger')('model-installer') +const HOME_DIR = global.__TEST__ ? os.tmpdir() : os.homedir() + +export interface Info { + 'dist.tarball'?: string + 'engines.coc'?: string + version?: string + name?: string +} + +export type Dependencies = Record + +export function registryUrl(scope = 'coc.nvim'): string { + let res = 'https://registry.npmjs.org/' + let filepath = path.join(HOME_DIR, '.npmrc') + if (fs.existsSync(filepath)) { + try { + let content = fs.readFileSync(filepath, 'utf8') + let obj = {} + for (let line of content.split(/\r?\n/)) { + if (line.indexOf('=') > -1) { + let [_, key, val] = line.match(/^(.*?)=(.*)$/) + obj[key] = val + } + } + if (obj[`${scope}:registry`]) { + res = obj[`${scope}:registry`] + } else if (obj['registry']) { + res = obj['registry'] + } + } catch (e) { + logger.error('Error on read .npmrc:', e) + } + } + return res.endsWith('/') ? res : res + '/' +} + +export function isNpmCommand(exePath: string): boolean { + let name = path.basename(exePath) + return name === 'npm' || name === 'npm.CMD' +} + +export function isYarn(exePath: string) { + let name = path.basename(exePath) + return ['yarn', 'yarn.CMD', 'yarnpkg', 'yarnpkg.CMD'].includes(name) +} + +export function getInstallArguments(exePath: string, url: string): string[] { + let args = ['install', '--ignore-scripts', '--no-lockfile', '--production'] + if (url.startsWith('https://github.com')) { + args = ['install'] + } + if (isNpmCommand(exePath)) { + args.push('--legacy-peer-deps') + args.push('--no-global') + } + if (isYarn(exePath)) { + args.push('--ignore-engines') + } + return args +} + +// remove properties that should be devDependencies. +export function getDependencies(content: string): Dependencies { + let dependencies: Dependencies + try { + let obj = JSON.parse(content) + dependencies = obj.dependencies || {} + } catch (e) { + // noop + dependencies = {} + } + return omit(dependencies, ['coc.nvim', 'esbuild', 'webpack', '@types/node']) +} + +function isSymbolicLink(folder: string): boolean { + if (fs.existsSync(folder)) { + let stat = fs.lstatSync(folder) + if (stat.isSymbolicLink()) { + return true + } + } + return false +} + +export class Installer extends EventEmitter { + private name: string + private url: string + private version: string + constructor( + private root: string, + private npm: string, + // could be url or name@version or name + private def: string + ) { + super() + if (!fs.existsSync(root)) fs.mkdirpSync(root) + if (/^https?:/.test(def)) { + this.url = def + } else { + let ms = def.match(/(.+)@([^/]+)$/) + if (ms) { + this.name = ms[1] + this.version = ms[2] + } else { + this.name = def + } + } + } + + public get info() { + return { name: this.name, version: this.version } + } + + public async install(): Promise { + this.log(`Using npm from: ${this.npm}`) + let info = await this.getInfo() + logger.info(`Fetched info of ${this.def}`, info) + let { name } = info + let required = info['engines.coc'] ? info['engines.coc'].replace(/^\^/, '>=') : '' + if (required && !semver.satisfies(workspace.version, required)) { + throw new Error(`${name} ${info.version} requires coc.nvim >= ${required}, please update coc.nvim.`) + } + await this.doInstall(info) + return name + } + + public async update(url?: string): Promise { + this.url = url + let folder = path.join(this.root, this.name) + if (isSymbolicLink(folder)) { + this.log(`Skipped update for symbol link`) + return + } + let version: string + if (fs.existsSync(path.join(folder, 'package.json'))) { + let content = await fs.readFile(path.join(folder, 'package.json'), 'utf8') + version = JSON.parse(content).version + } + this.log(`Using npm from: ${this.npm}`) + let info = await this.getInfo() + if (version && info.version && semver.gte(version, info.version)) { + this.log(`Current version ${version} is up to date.`) + return + } + let required = info['engines.coc'] ? info['engines.coc'].replace(/^\^/, '>=') : '' + if (required && !semver.satisfies(workspace.version, required)) { + throw new Error(`${info.version} requires coc.nvim ${required}, please update coc.nvim.`) + } + await this.doInstall(info) + let jsonFile = path.join(this.root, info.name, 'package.json') + this.log(`Updated to v${info.version}`) + return path.dirname(jsonFile) + } + + public async doInstall(info: Info): Promise { + let folder = path.join(this.root, info.name) + if (isSymbolicLink(folder)) return false + let tmpFolder = await fs.mkdtemp(path.join(os.tmpdir(), `${info.name.replace('/', '-')}-`)) + let url = info['dist.tarball'] + this.log(`Downloading from ${url}`) + await download(url, { dest: tmpFolder, onProgress: p => this.log(`Download progress ${p}%`, true), extract: 'untar' }) + this.log(`Extension download at ${tmpFolder}`) + let content = await fs.readFile(path.join(tmpFolder, 'package.json'), 'utf8') + let dependencies = getDependencies(content) + if (Object.keys(dependencies).length) { + let p = new Promise((resolve, reject) => { + let args = getInstallArguments(this.npm, url) + this.log(`Installing dependencies by: ${this.npm} ${args.join(' ')}.`) + const child = spawn(this.npm, args, { + cwd: tmpFolder, + }) + const rl = readline.createInterface({ + input: child.stdout + }) + rl.on('line', line => { + this.log(`[npm] ${line}`, true) + }) + child.stderr.setEncoding('utf8') + child.stdout.setEncoding('utf8') + child.on('error', reject) + let err = '' + child.stderr.on('data', data => { + err += data + }) + child.on('exit', code => { + if (code) { + if (err) this.log(err) + reject(new Error(`${this.npm} install exited with ${code}`)) + return + } + resolve() + }) + }) + await p + } + let jsonFile = path.resolve(this.root, global.__TEST__ ? '' : '..', 'package.json') + let errors: ParseError[] = [] + if (!fs.existsSync(jsonFile)) fs.writeFileSync(jsonFile, '{}') + let obj = parse(fs.readFileSync(jsonFile, 'utf8'), errors, { allowTrailingComma: true }) + if (errors && errors.length > 0) { + throw new Error(`Error on load ${jsonFile}`) + } + obj.dependencies = obj.dependencies || {} + if (this.url) { + obj.dependencies[info.name] = this.url + } else { + obj.dependencies[info.name] = '>=' + info.version + } + const sortedObj = { dependencies: {} } + Object.keys(obj.dependencies).sort().forEach(k => { + sortedObj.dependencies[k] = obj.dependencies[k] + }) + let stat = await statAsync(folder) + if (stat) { + if (stat.isDirectory()) { + fs.removeSync(folder) + } else { + fs.unlinkSync(folder) + } + } + await fs.move(tmpFolder, folder, { overwrite: true }) + await fs.writeFile(jsonFile, JSON.stringify(sortedObj, null, 2), { encoding: 'utf8' }) + if (fs.existsSync(tmpFolder)) fs.rmdirSync(tmpFolder) + this.log(`Update package.json at ${jsonFile}`) + this.log(`Installed extension ${this.name}@${info.version} at ${folder}`) + return true + } + + public async getInfo(): Promise { + if (this.url) return await this.getInfoFromUri() + let registry = registryUrl() + this.log(`Get info from ${registry}`) + let buffer = await fetch(registry + this.name, { timeout: 10000, buffer: true }) + let res = JSON.parse(buffer.toString()) + if (!this.version) this.version = res['dist-tags']['latest'] + let obj = res['versions'][this.version] + if (!obj) throw new Error(`${this.def} doesn't exists in ${registry}.`) + let requiredVersion = obj['engines'] && obj['engines']['coc'] + if (!requiredVersion) { + throw new Error(`${this.def} is not valid coc extension, "engines" field with coc property required.`) + } + return { + 'dist.tarball': obj['dist']['tarball'], + 'engines.coc': requiredVersion, + version: obj['version'], + name: res.name + } as Info + } + + public async getInfoFromUri(): Promise { + let { url } = this + if (!url.startsWith('https://github.com')) { + throw new Error(`"${url}" is not supported, coc.nvim support github.com only`) + } + url = url.replace(/\/$/, '') + let branch = 'master' + if (url.includes('@')) { + // https://github.com/sdras/vue-vscode-snippets@main + let idx = url.indexOf('@') + branch = url.substr(idx + 1) + url = url.substring(0, idx) + } + let fileUrl = url.replace('github.com', 'raw.githubusercontent.com') + `/${branch}/package.json` + this.log(`Get info from ${fileUrl}`) + let content = await fetch(fileUrl, { timeout: 10000 }) + let obj = typeof content == 'string' ? JSON.parse(content) : content + this.name = obj.name + return { + 'dist.tarball': `${url}/archive/${branch}.tar.gz`, + 'engines.coc': obj['engines'] ? obj['engines']['coc'] : null, + name: obj.name, + version: obj.version + } + } + + private log(msg: string, isProgress = false): void { + logger.info(msg) + this.emit('message', msg, isProgress) + } +} + +export function createInstallerFactory(npm: string, root: string): (def: string) => Installer { + return (def): Installer => new Installer(root, npm, def) +} diff --git a/sources_non_forked/coc.nvim/src/model/memos.ts b/sources_non_forked/coc.nvim/src/model/memos.ts new file mode 100644 index 00000000..799f17f4 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/memos.ts @@ -0,0 +1,64 @@ +'use strict' +import fs from 'fs' +import { deepClone } from '../util/object' +const logger = require('../util/logger')('model-memos') + +/** + * A memento represents a storage utility. It can store and retrieve + * values. + */ +export interface Memento { + get(key: string): T | undefined + get(key: string, defaultValue: T): T + update(key: string, value: any): Promise +} + +export default class Memos { + constructor(private filepath: string) { + if (!fs.existsSync(filepath)) { + fs.writeFileSync(filepath, '{}', 'utf8') + } + } + + private fetchContent(id: string, key: string): any { + try { + let content = fs.readFileSync(this.filepath, 'utf8') + let res = JSON.parse(content) + let obj = res[id] + if (!obj) return undefined + return obj[key] + } catch (e) { + return undefined + } + } + + private async update(id: string, key: string, value: any): Promise { + let { filepath } = this + try { + let content = fs.readFileSync(filepath, 'utf8') + let current = content ? JSON.parse(content) : {} + current[id] = current[id] || {} + if (value !== undefined) { + current[id][key] = deepClone(value) + } else { + delete current[id][key] + } + content = JSON.stringify(current, null, 2) + fs.writeFileSync(filepath, content, 'utf8') + } catch (e) { + logger.error(`Error on update memos:`, e) + } + } + + public createMemento(id: string): Memento { + return { + get: (key: string, defaultValue?: T): T | undefined => { + let res = this.fetchContent(id, key) + return res === undefined ? defaultValue : res + }, + update: async (key: string, value: any): Promise => { + await this.update(id, key, value) + } + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/menu.ts b/sources_non_forked/coc.nvim/src/model/menu.ts new file mode 100644 index 00000000..f3126cf7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/menu.ts @@ -0,0 +1,282 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import { CancellationToken, Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { HighlightItem } from '../types' +import { disposeAll } from '../util' +import { byteLength, isAlphabet } from '../util/string' +import { DialogPreferences } from './dialog' +import Popup from './popup' +const logger = require('../util/logger')('model-menu') + +export interface MenuItem { + text: string + disabled?: boolean | { reason: string } +} + +export interface MenuConfig { + items: string[] | MenuItem[] + title?: string + content?: string + shortcuts?: boolean + position?: 'cursor' | 'center' + borderhighlight?: string +} + +export function isMenuItem(item: any): item is MenuItem { + if (!item) return false + return typeof item.text === 'string' +} + +/** + * Select single item from menu at cursor position. + */ +export default class Menu { + private bufnr: number + private win: Popup + private currIndex = 0 + private contentHeight = 0 + private total: number + private disposables: Disposable[] = [] + private keyMappings: Map void> = new Map() + private shortcutIndexes: Set = new Set() + private _disposed = false + private readonly _onDidClose = new Emitter() + public readonly onDidClose: Event = this._onDidClose.event + constructor(private nvim: Neovim, private config: MenuConfig, token?: CancellationToken) { + this.total = config.items.length + if (token) { + token.onCancellationRequested(() => { + if (this.win) { + this.win?.close() + } else { + this._onDidClose.fire(-1) + this.dispose() + } + }) + } + this.disposables.push(this._onDidClose) + this.addKeymappings() + } + + private attachEvents(): void { + events.on('InputChar', this.onInputChar.bind(this), null, this.disposables) + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + this._onDidClose.fire(-1) + this.dispose() + } + }, null, this.disposables) + } + + private addKeymappings(): void { + let { nvim } = this + this.addKeys(['', ''], () => { + this._onDidClose.fire(-1) + this.dispose() + }) + this.addKeys(['\r', ''], () => { + this.selectCurrent() + }) + let setCursorIndex = idx => { + if (!this.win) return + nvim.pauseNotification() + this.setCursor(idx + this.contentHeight) + this.win?.refreshScrollbar() + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + this.addKeys('', async () => { + await this.win?.scrollForward() + }) + this.addKeys('', async () => { + await this.win?.scrollBackward() + }) + this.addKeys(['j', '', '', ''], () => { + // next + let idx = this.currIndex == this.total - 1 ? 0 : this.currIndex + 1 + setCursorIndex(idx) + }) + this.addKeys(['k', '', '', ''], () => { + // previous + let idx = this.currIndex == 0 ? this.total - 1 : this.currIndex - 1 + setCursorIndex(idx) + }) + this.addKeys(['g'], () => { + setCursorIndex(0) + }) + this.addKeys(['G'], () => { + setCursorIndex(this.total - 1) + }) + let timer: NodeJS.Timeout + let firstNumber: number + const choose = (n: number) => { + let disabled = this.isDisabled(n) + if (disabled) return + this._onDidClose.fire(n) + this.dispose() + } + this.addKeys(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], character => { + if (timer) clearTimeout(timer) + let n = parseInt(character, 10) + if (isNaN(n) || n > this.total) return + if (firstNumber == null && n == 0) return + if (firstNumber) { + let count = firstNumber * 10 + n + firstNumber = undefined + choose(count - 1) + return + } + if (this.total < 10 || n * 10 > this.total) { + choose(n - 1) + return + } + timer = setTimeout(async () => { + choose(n - 1) + }, 200) + firstNumber = n + }) + if (this.config.shortcuts) { + this.addShortcuts(choose) + } + } + + private addShortcuts(choose: (idx: number) => void): void { + let { items } = this.config + let texts: string[] = items.map(o => { + return isMenuItem(o) ? o.text : o + }) + texts.forEach((text, idx) => { + if (text.length) { + let s = text[0] + if (isAlphabet(s.charCodeAt(0)) && !this.keyMappings.has(s)) { + this.shortcutIndexes.add(idx) + this.addKeys(s, () => { + choose(idx) + }) + } + } + }) + } + + private isDisabled(idx: number): boolean { + let { items } = this.config + let item = items[idx] + if (isMenuItem(item) && item.disabled) { + return true + } + return false + } + + public async show(preferences: DialogPreferences = {}): Promise { + let { nvim, shortcutIndexes } = this + let { title, items, borderhighlight, position, content } = this.config + let opts: any = {} + if (title) opts.title = title + if (position === 'center') opts.relative = 'editor' + if (preferences.maxHeight) opts.maxHeight = preferences.maxHeight + if (preferences.maxWidth) opts.maxWidth = preferences.maxWidth + if (preferences.floatHighlight) opts.highlight = preferences.floatHighlight + if (borderhighlight) { + opts.borderhighlight = [borderhighlight] + } else if (preferences.floatBorderHighlight) { + opts.borderhighlight = [preferences.floatBorderHighlight] + } + if (preferences.rounded) opts.rounded = 1 + if (typeof content === 'string') opts.content = content + let highlights: HighlightItem[] = [] + let lines = items.map((v, i) => { + let text: string = isMenuItem(v) ? v.text : v + let pre = i < 99 ? `${i + 1}. ` : '' + // if (i < 99) return `${i + 1}. ${text.trim()}` + if (shortcutIndexes.has(i)) { + highlights.push({ + lnum: i, + hlGroup: preferences.shortcutHighlight || 'MoreMsg', + colStart: byteLength(pre), + colEnd: byteLength(pre) + 1 + }) + } + return pre + text.trim() + }) + lines.forEach((line, i) => { + let item = items[i] + if (isMenuItem(item) && item.disabled) { + highlights.push({ + hlGroup: 'CocDisabled', + lnum: i, + colStart: 0, + colEnd: byteLength(line) + }) + } + }) + if (highlights.length) opts.highlights = highlights + if (preferences.confirmKey && preferences.confirmKey != '') { + this.addKeys(preferences.confirmKey, () => { + this.selectCurrent() + }) + } + let res = await nvim.call('coc#dialog#create_menu', [lines, opts]) as [number, number, number] + if (!res) throw new Error('Unable to create menu window') + nvim.command('redraw', true) + if (this._disposed) return + this.win = new Popup(nvim, res[0], res[1], lines.length + res[2], res[2]) + this.bufnr = res[1] + this.contentHeight = res[2] + this.attachEvents() + nvim.call('coc#prompt#start_prompt', ['menu'], true) + } + + private selectCurrent(): void { + if (this.isDisabled(this.currIndex)) { + let item = this.config.items[this.currIndex] as MenuItem + if (item.disabled['reason']) { + this.nvim.outWriteLine(`Item disabled: ${item.disabled['reason']}`) + } + return + } + this._onDidClose.fire(this.currIndex) + this.dispose() + } + + public get buffer(): Buffer { + return this.bufnr ? this.nvim.createBuffer(this.bufnr) : undefined + } + + public dispose(): void { + this._disposed = true + disposeAll(this.disposables) + this.shortcutIndexes.clear() + this.keyMappings.clear() + this.nvim.call('coc#prompt#stop_prompt', ['menu'], true) + this.win?.close() + this.bufnr = undefined + this.win = undefined + } + + private async onInputChar(session: string, character: string): Promise { + if (session != 'menu' || !this.win) return + let fn = this.keyMappings.get(character) + if (fn) { + await Promise.resolve(fn(character)) + } else { + logger.warn(`Ignored key press: ${character}`) + } + } + + private setCursor(index: number): void { + if (!this.win) return + this.currIndex = index - this.contentHeight + this.win.setCursor(index) + } + + private addKeys(keys: string | string[], fn: (character: string) => void): void { + if (Array.isArray(keys)) { + for (let key of keys) { + this.keyMappings.set(key, fn) + } + } else { + this.keyMappings.set(keys, fn) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/mru.ts b/sources_non_forked/coc.nvim/src/model/mru.ts new file mode 100644 index 00000000..25c3993b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/mru.ts @@ -0,0 +1,92 @@ +'use strict' +import path from 'path' +import fs from 'fs-extra' +import { readFileLines, writeFile } from '../util/fs' +import { distinct } from '../util/array' + +/** + * Mru - manage string items as lines in mru file. + */ +export default class Mru { + private file: string + + /** + * @param {string} name unique name + * @param {string} base? optional directory name, default to config root of coc.nvim + */ + constructor( + name: string, + base?: string, + private maximum = 5000) { + this.file = path.join(base || process.env.COC_DATA_HOME, name) + let dir = path.dirname(this.file) + fs.mkdirpSync(dir) + } + + /** + * Load iems from mru file + */ + public async load(): Promise { + try { + let lines = await readFileLines(this.file, 0, this.maximum) + if (lines.length > this.maximum) { + await writeFile(this.file, lines.join('\n')) + } + if (lines[lines.length - 1] == '') lines = lines.slice(0, -1) + return distinct(lines) + } catch (e) { + return [] + } + } + + public loadSync(): string[] { + if (!fs.existsSync(this.file)) return [] + try { + let content = fs.readFileSync(this.file, 'utf8') + content = content.trim() + return content.length ? content.trim().split('\n') : [] + } catch (e) { + return [] + } + } + + /** + * Add item to mru file. + */ + public async add(item: string): Promise { + let buf: Buffer + try { + buf = fs.readFileSync(this.file) + if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) { + buf = buf.slice(3) + } + buf = Buffer.concat([Buffer.from(item, 'utf8'), new Uint8Array([10]), buf]) + } catch (e) { + buf = Buffer.concat([Buffer.from(item, 'utf8'), new Uint8Array([10])]) + } + await fs.writeFile(this.file, buf, 'utf8') + } + + /** + * Remove item from mru file. + */ + public async remove(item: string): Promise { + let items = await this.load() + let len = items.length + items = items.filter(s => s != item) + if (items.length != len) { + await fs.writeFile(this.file, items.join('\n'), 'utf8') + } + } + + /** + * Remove the data file. + */ + public async clean(): Promise { + try { + await fs.unlink(this.file) + } catch (e) { + // noop + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/notification.ts b/sources_non_forked/coc.nvim/src/model/notification.ts new file mode 100644 index 00000000..cf1eb3e9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/notification.ts @@ -0,0 +1,105 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable } from 'vscode-languageserver-protocol' +import events from '../events' +import { disposeAll } from '../util' +import { DialogButton } from './dialog' +const logger = require('../util/logger')('model-notification') + +export interface NotificationPreferences { + disabled: boolean + maxWidth: number + maxHeight: number + highlight: string + winblend: number + broder: boolean + timeout: number + marginRight: number + focusable: boolean + minWidth?: number + source?: string +} + +export type NotificationKind = 'error' | 'info' | 'warning' | 'progress' + +export interface NotificationConfig { + kind?: NotificationKind + + content?: string + /** + * Optional title text. + */ + title?: string + /** + * Buttons as bottom of dialog. + */ + buttons?: DialogButton[] + /** + * index is -1 for window close without button click + */ + callback?: (index: number) => void +} + +export default class Notification { + protected disposables: Disposable[] = [] + protected bufnr: number + protected _winid: number + protected _disposed = false + constructor(protected nvim: Neovim, protected config: NotificationConfig, attachEvents = true) { + if (attachEvents) { + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + this.dispose() + if (config.callback) config.callback(-1) + } + }, null, this.disposables) + events.on('FloatBtnClick', (bufnr, idx) => { + if (bufnr == this.bufnr) { + this.dispose() + let btns = config?.buttons.filter(o => o.disabled != true) + if (config.callback) config.callback(btns[idx].index) + } + }, null, this.disposables) + } + } + + protected get lines(): string[] { + return this.config.content ? this.config.content.split(/\r?\n/) : [] + } + + public async show(preferences: Partial): Promise { + let { nvim } = this + let { buttons, kind, title } = this.config + let opts: any = Object.assign({}, preferences) + opts.kind = kind ?? '' + if (title) opts.title = title + if (preferences.broder) { + opts.borderhighlight = kind ? `CocNotification${kind[0].toUpperCase()}${kind.slice(1)}` : preferences.highlight + } + if (Array.isArray(buttons)) { + let actions: string[] = buttons.filter(o => !o.disabled).map(o => o.text) + if (actions.length) opts.actions = actions + } + let res = await nvim.call('coc#notify#create', [this.lines, opts]) as [number, number] + if (!res) throw new Error(`Unable to create notification window`) + this._winid = res[0] + this.bufnr = res[1] + } + + public get winid(): number | undefined { + return this._winid + } + + public dispose(): void { + if (this._disposed) return + this._disposed = true + let { winid } = this + if (winid) { + this.nvim.call('coc#notify#close', [winid], true) + this.nvim.redrawVim() + } + this.bufnr = undefined + this._winid = undefined + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/outputChannel.ts b/sources_non_forked/coc.nvim/src/model/outputChannel.ts new file mode 100644 index 00000000..47a72367 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/outputChannel.ts @@ -0,0 +1,88 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { OutputChannel } from '../types' +const logger = require('../util/logger')('outpubChannel') + +export default class BufferChannel implements OutputChannel { + private lines: string[] = [''] + private _disposed = false + public created = false + constructor(public name: string, private nvim: Neovim, private onDispose?: () => void) { + if (!/^[\w\s-.]+$/.test(name)) throw new Error(`Invalid channel name "${name}", only word characters and white space allowed.`) + } + + public get content(): string { + return this.lines.join('\n') + } + + private _append(value: string): void { + let { nvim } = this + let idx = this.lines.length - 1 + let newlines = value.split(/\r?\n/) + let lastline = this.lines[idx] + newlines[0] + this.lines[idx] = lastline + let append = newlines.slice(1) + this.lines = this.lines.concat(append) + if (!this.created) return + nvim.pauseNotification() + nvim.call('setbufline', [this.bufname, '$', lastline], true) + if (append.length) { + nvim.call('appendbufline', [this.bufname, '$', append], true) + } + nvim.resumeNotification(false, true) + } + + public append(value: string): void { + if (!this.validate()) return + this._append(value) + } + + public appendLine(value: string): void { + if (!this.validate()) return + this._append(value + '\n') + } + + public clear(keep?: number): void { + if (!this.validate()) return + let { nvim } = this + this.lines = keep ? this.lines.slice(-keep) : [] + if (!this.created) return + nvim.pauseNotification() + nvim.call('deletebufline', [this.bufname, 1, '$'], true) + if (this.lines.length) { + nvim.call('appendbufline', [this.bufname, '$', this.lines], true) + } + nvim.resumeNotification(true, true) + } + + public hide(): void { + this.created = false + this.nvim.command(`exe 'silent! bd! '.fnameescape('${this.bufname}')`, true) + } + + private get bufname(): string { + return `output:///${this.name}` + } + + public show(preserveFocus?: boolean, cmd = 'vs'): void { + let { nvim } = this + nvim.pauseNotification() + nvim.command(`exe '${cmd} '.fnameescape('${this.bufname}')`, true) + if (preserveFocus) { + nvim.command('wincmd p', true) + } + nvim.resumeNotification(true, true) + this.created = true + } + + private validate(): boolean { + return !this._disposed + } + + public dispose(): void { + if (this.onDispose) this.onDispose() + this._disposed = true + this.hide() + this.lines = [] + } +} diff --git a/sources_non_forked/coc.nvim/src/model/picker.ts b/sources_non_forked/coc.nvim/src/model/picker.ts new file mode 100644 index 00000000..e4ef8b83 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/picker.ts @@ -0,0 +1,241 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import { CancellationToken, Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { HighlightItem, QuickPickItem } from '../types' +import { disposeAll } from '../util' +import { byteLength } from '../util/string' +import { DialogPreferences } from './dialog' +import Popup from './popup' +const logger = require('../util/logger')('model-dialog') +const isVim = process.env.VIM_NODE_RPC == '1' + +interface PickerConfig { + title: string + items: QuickPickItem[] +} + +/** + * Pick multiple items from dialog + */ +export default class Picker { + private bufnr: number + private win: Popup | undefined + private picked: Set = new Set() + private total: number + private disposables: Disposable[] = [] + private keyMappings: Map void> = new Map() + private readonly _onDidClose = new Emitter() + public readonly onDidClose: Event = this._onDidClose.event + constructor(private nvim: Neovim, private config: PickerConfig, token?: CancellationToken) { + for (let i = 0; i < config.items.length; i++) { + let item = config.items[i] + if (item.picked) this.picked.add(i) + } + this.total = config.items.length + if (token) { + token.onCancellationRequested(() => { + this.win?.close() + }) + } + this.disposables.push(this._onDidClose) + this.addKeymappings() + } + + public get currIndex(): number { + return this.win ? this.win.currIndex : 0 + } + + private attachEvents(): void { + events.on('InputChar', this.onInputChar.bind(this), null, this.disposables) + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + this._onDidClose.fire(undefined) + this.bufnr = undefined + this.win = undefined + this.dispose() + } + }, null, this.disposables) + events.on('FloatBtnClick', (bufnr, idx) => { + if (bufnr == this.bufnr) { + if (idx == 0) { + let selected = Array.from(this.picked) + this._onDidClose.fire(selected.length ? selected : undefined) + } else { + this._onDidClose.fire(undefined) + } + this.dispose() + } + }, null, this.disposables) + } + + private addKeymappings(): void { + let { nvim } = this + const toggleSelect = idx => { + if (this.picked.has(idx)) { + this.picked.delete(idx) + } else { + this.picked.add(idx) + } + } + this.addKeys('', async () => { + // not work on vim + if (isVim || !this.win) return + let [winid, lnum, col] = await nvim.eval('[v:mouse_winid,v:mouse_lnum,v:mouse_col]') as [number, number, number] + // can't simulate vvar. + if (global.hasOwnProperty('__TEST__')) { + let res = await nvim.getVar('mouse_position') + winid = res[0] + lnum = res[1] + col = res[2] + } + nvim.pauseNotification() + if (winid == this.win.winid) { + if (col <= 3) { + toggleSelect(lnum - 1) + this.changeLine(lnum - 1) + } else { + this.setCursor(lnum - 1) + } + } + nvim.call('win_gotoid', [winid], true) + nvim.call('cursor', [lnum, col], true) + nvim.call('coc#float#nvim_float_click', [], true) + nvim.command('redraw', true) + await nvim.resumeNotification() + }) + this.addKeys(['', ''], () => { + this._onDidClose.fire(undefined) + this.dispose() + }) + this.addKeys('', () => { + if (this.picked.size == 0) { + this._onDidClose.fire(undefined) + } else { + let selected = Array.from(this.picked) + this._onDidClose.fire(selected) + } + this.dispose() + }) + this.addKeys(['j', '', '', ''], () => { + this.win.setCursor(this.currIndex + 1, true) + }) + this.addKeys(['k', '', '', ''], () => { + this.win.setCursor(this.currIndex - 1, true) + }) + this.addKeys(['g'], () => { + this.win.setCursor(0, true) + }) + this.addKeys(['G'], () => { + this.win.setCursor(this.total - 1, true) + }) + this.addKeys(' ', async () => { + let idx = this.currIndex + toggleSelect(idx) + nvim.pauseNotification() + this.changeLine(idx) + this.setCursor(this.currIndex + 1) + nvim.command('redraw', true) + await nvim.resumeNotification() + }) + this.addKeys('', async () => { + await this.win?.scrollForward() + }) + this.addKeys('', async () => { + await this.win?.scrollBackward() + }) + } + + public async show(preferences: DialogPreferences = {}): Promise { + let { nvim } = this + let { title, items } = this.config + let opts: any = { close: 1, cursorline: 1 } + if (preferences.maxHeight) opts.maxHeight = preferences.maxHeight + if (preferences.maxWidth) opts.maxWidth = preferences.maxWidth + if (title) opts.title = title + if (preferences.floatHighlight) opts.highlight = preferences.floatHighlight + if (preferences.floatBorderHighlight) opts.borderhighlight = [preferences.floatBorderHighlight] + if (preferences.pickerButtons) { + let shortcut = preferences.pickerButtonShortcut + opts.buttons = ['Submit' + (shortcut ? ' ' : ''), 'Cancel' + (shortcut ? ' ' : '')] + } + if (preferences.rounded) opts.rounded = 1 + if (preferences.confirmKey && preferences.confirmKey != '') { + this.addKeys(preferences.confirmKey, () => { + this._onDidClose.fire(undefined) + this.dispose() + }) + } + let lines = [] + let highlights: HighlightItem[] = [] + for (let i = 0; i < items.length; i++) { + let item = items[i] + let line = `[${item.picked ? 'x' : ' '}] ${item.label}` + if (item.description) { + let start = byteLength(line) + line = line + ` ${item.description}` + highlights.push({ hlGroup: 'Comment', lnum: i, colStart: start, colEnd: byteLength(line) }) + } + lines.push(line) + } + if (highlights.length) opts.highlights = highlights + let res = await nvim.call('coc#dialog#create_dialog', [lines, opts]) as [number, number] + this.win = new Popup(nvim, res[0], res[1], lines.length) + this.bufnr = res[1] + nvim.call('coc#prompt#start_prompt', ['picker'], true) + this.attachEvents() + this.win.setCursor(0, true) + return res[0] + } + + public get buffer(): Buffer { + return this.bufnr ? this.nvim.createBuffer(this.bufnr) : undefined + } + + public dispose(): void { + this.picked.clear() + this.keyMappings.clear() + disposeAll(this.disposables) + this.nvim.call('coc#prompt#stop_prompt', ['picker'], true) + this.win?.close() + this.win = undefined + } + + private async onInputChar(session: string, character: string): Promise { + if (session != 'picker' || !this.win) return + let fn = this.keyMappings.get(character) + if (fn) { + await Promise.resolve(fn(character)) + } else { + logger.warn(`Ignored key press: ${character}`) + } + } + + private changeLine(index: number): void { + let { nvim } = this + let item = this.config.items[index] + if (!item) return + let line = `[${this.picked.has(index) ? 'x' : ' '}] ${item.label}` + let col = byteLength(line) + if (item.description) line = line + ` ${item.description}` + nvim.call('setbufline', [this.bufnr, index + 1, line], true) + let buf = nvim.createBuffer(this.bufnr) + // eslint-disable-next-line @typescript-eslint/no-floating-promises + buf.addHighlight({ hlGroup: 'Comment', line: index, srcId: 1, colStart: col, colEnd: -1 }) + } + + private setCursor(index: number): void { + if (!this.win) return + this.win.setCursor(index) + } + + private addKeys(keys: string | string[], fn: (character: string) => void): void { + if (Array.isArray(keys)) { + for (let key of keys) { + this.keyMappings.set(key, fn) + } + } else { + this.keyMappings.set(keys, fn) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/popup.ts b/sources_non_forked/coc.nvim/src/model/popup.ts new file mode 100644 index 00000000..90d0e470 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/popup.ts @@ -0,0 +1,104 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +const isVim = process.env.VIM_NODE_RPC == '1' + +/** + * More methods for float window/popup + */ +export default class Popup { + constructor( + private nvim: Neovim, + public readonly winid, + public readonly bufnr, + public linecount: number, + private _currIndex = 0 + ) { + } + + public get currIndex(): number { + return this._currIndex + } + + public get valid(): Promise { + return this.nvim.call('coc#float#valid', [this.winid]).then(res => { + return !!res + }) + } + + public close(): void { + this.nvim.call('coc#float#close', [this.winid], true) + } + + public refreshScrollbar(): void { + if (!isVim) this.nvim.call('coc#float#nvim_scrollbar', [this.winid], true) + } + + public execute(cmd: string): void { + this.nvim.call('coc#compat#execute', [this.winid, cmd], true) + } + + /** + * Simple scroll method, not consider wrapped lines. + */ + public async scrollForward(): Promise { + let { nvim, bufnr, winid } = this + let buf = nvim.createBuffer(bufnr) + let total = await buf.length + let botline: number + if (!isVim) { + let infos = await nvim.call('getwininfo', [winid]) + if (!infos || !infos.length) return + botline = infos[0].botline + } else { + botline = await nvim.eval(`get(popup_getpos(${winid}), 'lastline', 0)`) as number + } + if (botline >= total || botline == 0) return + nvim.pauseNotification() + this.setCursor(botline - 1) + this.execute(`silent! noa setl scrolloff=0`) + this.execute(`normal! ${botline}Gzt`) + this.refreshScrollbar() + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + + /** + * Simple scroll method, not consider wrapped lines. + */ + public async scrollBackward(): Promise { + let { nvim, winid } = this + let topline: number + if (!isVim) { + let infos = await nvim.call('getwininfo', [winid]) + if (!infos || !infos.length) return + topline = infos[0].topline + } else { + topline = await nvim.eval(`get(popup_getpos(${winid}), 'firstline', 0)`) as number + } + if (topline == 1) return + nvim.pauseNotification() + this.setCursor(topline - 1) + this.execute(`normal! ${topline}Gzb`) + this.refreshScrollbar() + nvim.command('redraw', true) + nvim.resumeNotification(false, true) + } + + /** + * Move cursor and highlight. + */ + public setCursor(index: number, redraw = false): void { + let { nvim, bufnr, winid, linecount } = this + if (index < 0) { + index = 0 + } else if (index > linecount - 1) { + index = linecount - 1 + } + this._currIndex = index + nvim.call('coc#dialog#set_cursor', [winid, bufnr, index + 1], true) + if (redraw) { + this.refreshScrollbar() + nvim.command('redraw', true) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/progress.ts b/sources_non_forked/coc.nvim/src/model/progress.ts new file mode 100644 index 00000000..84d72dd7 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/progress.ts @@ -0,0 +1,69 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import Notification, { NotificationPreferences } from './notification' +import { CancellationToken, CancellationTokenSource, Event, Emitter } from 'vscode-languageserver-protocol' +import events from '../events' +const logger = require('../util/logger')('model-progress') + +export interface Progress { + report(value: { message?: string; increment?: number }): void +} + +export interface ProgressOptions { + title?: string + cancellable?: boolean + task: (progress: Progress, token: CancellationToken) => Thenable +} + +export default class ProgressNotification extends Notification { + private tokenSource: CancellationTokenSource + private readonly _onDidFinish = new Emitter() + public readonly onDidFinish: Event = this._onDidFinish.event + constructor(nvim: Neovim, private option: ProgressOptions) { + super(nvim, { + kind: 'progress', + title: option.title, + buttons: option.cancellable ? [{ index: 1, text: 'Cancel' }] : undefined + }, false) + this.disposables.push(this._onDidFinish) + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + if (this.tokenSource) this.tokenSource.cancel() + this._onDidFinish.fire(undefined) + this.dispose() + } + }, null, this.disposables) + } + + public async show(preferences: Partial): Promise { + let { task } = this.option + let tokenSource = this.tokenSource = new CancellationTokenSource() + this.disposables.push(tokenSource) + let total = 0 + if (this.config.buttons || !preferences.disabled) { + await super.show(preferences) + } else { + logger.warn(`progress window disabled by "notification.disabledProgressSources"`) + } + task({ + report: p => { + if (!this.winid) return + let { nvim } = this + if (p.increment) { + total += p.increment + nvim.call('coc#window#set_var', [this.winid, 'percent', `${total}%`], true) + } + if (p.message) nvim.call('coc#window#set_var', [this.winid, 'message', p.message.replace(/\r?\n/g, ' ')], true) + } + }, tokenSource.token).then(res => { + if (this._disposed) return + this._onDidFinish.fire(res) + this.dispose() + }, err => { + this.nvim.echoError(err) + if (this._disposed) return + this._onDidFinish.fire(undefined) + this.dispose() + }) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/quickpick.ts b/sources_non_forked/coc.nvim/src/model/quickpick.ts new file mode 100644 index 00000000..6b25add3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/quickpick.ts @@ -0,0 +1,318 @@ +'use strict' +import { Buffer, Neovim } from '@chemzqm/neovim' +import stringWidth from '@chemzqm/string-width' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { HighlightItem, QuickPickItem } from '../types' +import { disposeAll } from '../util' +import { hasMatch, positions } from '../util/fzy' +import { byteIndex, byteLength } from '../util/string' +import { DialogPreferences } from './dialog' +import InputBox from './input' +import Popup from './popup' +const logger = require('../util/logger')('model-quickpick') + +export interface QuickPickConfig { + title?: string + items: readonly T[] + value?: string + canSelectMany?: boolean + maxHeight?: number +} + +/** + * Pick single/multiple items from prompt list. + */ +export default class QuickPick { + public title: string + public loading: boolean + public matchOnDescription: boolean + public items: readonly T[] + public activeItems: readonly T[] + public selectedItems: T[] + private bufnr: number + private win: Popup + private filteredItems: readonly T[] + private disposables: Disposable[] = [] + private input: InputBox | undefined + private _changed = false + // emitted with selected items or undefined when cancelled. + private readonly _onDidFinish = new Emitter() + private readonly _onDidChangeSelection = new Emitter>() + private readonly _onDidChangeValue = new Emitter() + public readonly onDidFinish: Event = this._onDidFinish.event + public readonly onDidChangeSelection: Event> = this._onDidChangeSelection.event + public readonly onDidChangeValue: Event = this._onDidChangeValue.event + constructor(private nvim: Neovim, private config: QuickPickConfig) { + let items = config.items ?? [] + Object.defineProperty(this, 'items', { + set: (list: T[]) => { + this._changed = true + items = list + this.filterItems('') + }, + get: () => { + return items + } + }) + Object.defineProperty(this, 'activeItems', { + set: (list: T[]) => { + this._changed = true + this.filteredItems = list + this.showFilteredItems() + }, + get: () => { + return this.filteredItems + } + }) + Object.defineProperty(this, 'title', { + set: (newTitle: string) => { + if (this.input) this.input.title = newTitle + }, + get: () => { + return this.input ? this.input.title : config.title + } + }) + Object.defineProperty(this, 'loading', { + set: (loading: boolean) => { + if (this.input) this.input.loading = loading + }, + get: () => { + return this.input ? this.input.loading : false + } + }) + } + + /** + * Current input value + */ + public get value(): string { + return this.input ? this.input.value : this.config.value ?? '' + } + + public get currIndex(): number { + return this.win ? this.win.currIndex : 0 + } + + public get buffer(): Buffer { + return this.bufnr ? this.nvim.createBuffer(this.bufnr) : undefined + } + + private setCursor(index: number): void { + this.win?.setCursor(index, true) + } + + private attachEvents(inputBufnr: number): void { + events.on('BufWinLeave', bufnr => { + if (bufnr == this.bufnr) { + this.dispose() + } + }, null, this.disposables) + events.on('PromptKeyPress', async (bufnr, key) => { + if (bufnr == inputBufnr) { + if (key == 'C-f') { + await this.win?.scrollForward() + } else if (key == 'C-b') { + await this.win?.scrollBackward() + } else if (['C-j', 'C-n', 'down'].includes(key)) { + this.setCursor(this.currIndex + 1) + } else if (['C-k', 'C-p', 'up'].includes(key)) { + this.setCursor(this.currIndex - 1) + } else if (this.config.canSelectMany && key == 'C-@') { + this.toggePicked(this.currIndex) + } + } + }, null, this.disposables) + } + + public async show(preferences: DialogPreferences = {}): Promise { + let { nvim, items } = this + let { title, canSelectMany, value } = this.config + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let selectedItems: T[] = [] + for (let i = 0; i < items.length; i++) { + let item = items[i] + let line = canSelectMany ? `[${item.picked ? 'x' : ' '}] ${item.label}` : item.label + if (item.picked) selectedItems.push(item) + if (item.description) { + let start = byteLength(line) + line = line + ` ${item.description}` + highlights.push({ hlGroup: 'Comment', lnum: i, colStart: start, colEnd: byteLength(line) }) + } + lines.push(line) + } + let input = this.input = new InputBox(this.nvim, value ?? '') + input.onDidChange(value => { + this._onDidChangeValue.fire(value) + // Updated by extension + if (this._changed) { + this._changed = false + return + } + this.filterItems(value) + }, this) + input.onDidFinish(this.onFinish, this) + let minWidth = Math.max(40, Math.min(80, lines.reduce((p, c) => Math.max(p, stringWidth(c)), 0))) + await input.show(title ?? '', { + position: 'center', + marginTop: 10, + border: [1, 1, 0, 1], + list: true, + minWidth, + maxWidth: preferences.maxWidth || 80, + rounded: !!preferences.rounded, + highlight: preferences.floatHighlight, + borderhighlight: preferences.floatBorderHighlight + }) + this.selectedItems = selectedItems + let opts: any = { lines, rounded: !!preferences.rounded } + opts.highlights = highlights + if (preferences.floatHighlight) opts.highlight = preferences.floatHighlight + if (preferences.floatBorderHighlight) opts.borderhighlight = preferences.floatBorderHighlight + let maxHeight = this.config.maxHeight || preferences.maxHeight + if (maxHeight) opts.maxHeight = maxHeight + let res = await nvim.call('coc#dialog#create_list', [input.winid, input.dimension, opts]) + if (!res) throw new Error('Unable to open list window.') + this.filteredItems = items + // let height + this.win = new Popup(nvim, res[0], res[1], lines.length) + this.win.refreshScrollbar() + this.bufnr = res[1] + let idx = canSelectMany || selectedItems.length == 0 ? 0 : items.indexOf(selectedItems[0]) + this.setCursor(idx) + this.attachEvents(input.bufnr) + } + + /** + * Filter items with input + */ + private filterItems(input: string): void { + let { items, win, selectedItems } = this + if (!win) return + let { canSelectMany } = this.config + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let idx = 0 + let filteredItems: T[] = [] + for (let item of items) { + let filterText = this.toFilterText(item) + if (input.length > 0 && !hasMatch(input, filterText)) continue + let picked = selectedItems.includes(item) + let line = canSelectMany ? `[${picked ? 'x' : ' '}] ${item.label}` : item.label + if (item.description) { + let start = byteLength(line) + line = line + ` ${item.description}` + highlights.push({ hlGroup: 'Comment', lnum: idx, colStart: start, colEnd: byteLength(line) }) + } + let arr = positions(input, filterText) + arr.forEach(n => { + let colStart = byteIndex(filterText, n) + highlights.push({ + hlGroup: 'CocSearch', + colStart, + colEnd: colStart + 1, + lnum: idx + }) + }) + filteredItems.push(item) + lines.push(line) + idx += 1 + } + this.filteredItems = filteredItems + this.win.linecount = lines.length + this.nvim.call('coc#dialog#update_list', [this.win.winid, this.win.bufnr, lines, highlights], true) + this.setCursor(0) + } + + private showFilteredItems(): void { + let { win, input, filteredItems } = this + if (!win) return + let { canSelectMany } = this.config + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let idx = 0 + let selectedItems: T[] = [] + for (let item of filteredItems) { + let filterText = this.toFilterText(item) + let line = canSelectMany ? `[${item.picked ? 'x' : ' '}] ${item.label}` : item.label + if (item.picked) selectedItems.push(item) + if (item.description) { + let start = byteLength(line) + line = line + ` ${item.description}` + highlights.push({ hlGroup: 'Comment', lnum: idx, colStart: start, colEnd: byteLength(line) }) + } + let arr = positions(input.value, filterText) + arr.forEach(n => { + let colStart = byteIndex(filterText, n) + highlights.push({ + hlGroup: 'CocSearch', + colStart, + colEnd: colStart + 1, + lnum: idx + }) + }) + lines.push(line) + idx += 1 + } + this.selectedItems = selectedItems + this.win.linecount = lines.length + this.nvim.call('coc#dialog#update_list', [this.win.winid, this.win.bufnr, lines, highlights], true) + this.setCursor(canSelectMany || selectedItems.length == 0 ? 0 : filteredItems.indexOf(selectedItems[0])) + } + + private onFinish(input: string | undefined): void { + if (input == null) { + this._onDidChangeSelection.fire([]) + this._onDidFinish.fire(null) + return + } + let selected = this.getSelectedItems() + if (!this.config.canSelectMany) { + this._onDidChangeSelection.fire(selected) + } + this._onDidFinish.fire(selected) + } + + private getSelectedItems(): T[] { + let { win } = this + let { canSelectMany } = this.config + if (canSelectMany) return this.selectedItems + let item = this.filteredItems[win.currIndex] + return item == null ? [] : [item] + } + + private toggePicked(index: number): void { + let { nvim, filteredItems, selectedItems } = this + let item = filteredItems[index] + if (!item) return + let idx = selectedItems.indexOf(item) + if (idx != -1) { + selectedItems.splice(idx, 1) + } else { + selectedItems.push(item) + } + let text = idx == -1 ? 'x' : ' ' + nvim.pauseNotification() + this.win.execute(`normal! ^1lr${text}`) + this.win.setCursor(this.win.currIndex + 1) + nvim.resumeNotification(true, true) + this._onDidChangeSelection.fire(selectedItems) + } + + private toFilterText(item: T): string { + let { label, description } = item + let { canSelectMany } = this.config + let line = `${canSelectMany ? ' ' : ''}${label.replace(/\r?\n/, '')}` + return this.matchOnDescription ? line + ' ' + (description ?? '') : line + } + + public dispose(): void { + this.bufnr = undefined + this.input?.dispose() + this.win?.close() + this._onDidFinish.dispose() + this._onDidChangeSelection.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/regions.ts b/sources_non_forked/coc.nvim/src/model/regions.ts new file mode 100644 index 00000000..a5285373 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/regions.ts @@ -0,0 +1,72 @@ +'use strict' +/** + * Remember used regions + */ +export default class Regions { + /** + * ranges that never overlaps. + */ + private ranges: [number, number][] = [] + + public get current(): ReadonlyArray { + let res: number[] = [] + this.ranges.sort((a, b) => a[0] - b[0]) + this.ranges.forEach(o => { + res.push(o[0], o[1]) + }) + return res + } + + public clear(): void { + this.ranges = [] + } + + public add(start: number, end: number): void { + if (start > end) { + [start, end] = [end, start] + } + let { ranges } = this + if (ranges.length == 0) { + ranges.push([start, end]) + } else { + // 1, 2, 3 + ranges.sort((a, b) => a[0] - b[0]) + let s: number + let e: number + let removedIndexes: number[] = [] + for (let i = 0; i < ranges.length; i++) { + let r = ranges[i] + if (r[1] < start || r[0] > end) continue + removedIndexes.push(i) + if (s == null) s = Math.min(start, r[0]) + e = Math.max(end, r[1]) + } + let newRanges = removedIndexes.length ? ranges.filter((_, i) => !removedIndexes.includes(i)) : ranges + this.ranges = newRanges + if (s != null && e != null) { + this.ranges.push([s, e]) + } else { + this.ranges.push([start, end]) + } + } + } + + public has(start: number, end: number): boolean { + let idx = this.ranges.findIndex(o => o[0] <= start && o[1] >= end) + return idx !== -1 + } + + public static mergeSpans(ranges: [number, number][]): [number, number][] { + let res: [number, number][] = [] + for (let r of ranges) { + let idx = res.findIndex(o => !(r[1] < o[0] || r[0] > o[1])) + if (idx == -1) { + res.push(r) + } else { + let o = res[idx] + res[idx] = [Math.min(r[0], o[0]), Math.max(r[1], o[1])] + } + } + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/model/relativePattern.ts b/sources_non_forked/coc.nvim/src/model/relativePattern.ts new file mode 100644 index 00000000..867a0788 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/relativePattern.ts @@ -0,0 +1,35 @@ +'use strict' +import { URI } from 'vscode-uri' +import { illegalArgument } from '../util/errors' +import { WorkspaceFolder } from 'vscode-languageserver-protocol' + +export default class RelativePattern { + public pattern: string + public baseUri: URI + + constructor(base: WorkspaceFolder | URI | string, pattern: string) { + if (typeof base !== 'string') { + if (!base || !URI.isUri(base) && typeof base.uri !== 'string') { + throw illegalArgument('base') + } + } + if (typeof pattern !== 'string') { + throw illegalArgument('pattern') + } + if (typeof base === 'string') { + this.baseUri = URI.file(base) + } else if (URI.isUri(base)) { + this.baseUri = base + } else { + this.baseUri = URI.parse(base.uri) + } + this.pattern = pattern + } + + public toJSON() { + return { + pattern: this.pattern, + baseUri: this.baseUri.toJSON() + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/resolver.ts b/sources_non_forked/coc.nvim/src/model/resolver.ts new file mode 100644 index 00000000..65774cfc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/resolver.ts @@ -0,0 +1,46 @@ +'use strict' +import path from 'path' +import fs from 'fs' +import { executable, runCommand } from '../util' +import { statAsync } from '../util/fs' +import stripAnsi from 'strip-ansi' +const logger = require('../util/logger')('model-resolver') + +export default class Resolver { + private _npmFolder: string + private _yarnFolder: string + + private get nodeFolder(): Promise { + if (!executable('npm')) return Promise.resolve('') + if (this._npmFolder) return Promise.resolve(this._npmFolder) + return runCommand('npm --loglevel silent root -g', {}, 3000).then(root => { + this._npmFolder = stripAnsi(root).trim() + return this._npmFolder + }) + } + + private get yarnFolder(): Promise { + if (!executable('yarnpkg')) return Promise.resolve('') + if (this._yarnFolder) return Promise.resolve(this._yarnFolder) + return runCommand('yarnpkg global dir', {}, 3000).then(root => { + let folder = path.join(stripAnsi(root).trim(), 'node_modules') + let exists = fs.existsSync(folder) + if (exists) this._yarnFolder = folder + return exists ? folder : '' + }) + } + + public async resolveModule(mod: string): Promise { + let nodeFolder = await this.nodeFolder + let yarnFolder = await this.yarnFolder + if (yarnFolder) { + let s = await statAsync(path.join(yarnFolder, mod, 'package.json')) + if (s && s.isFile()) return path.join(yarnFolder, mod) + } + if (nodeFolder) { + let s = await statAsync(path.join(nodeFolder, mod, 'package.json')) + if (s && s.isFile()) return path.join(nodeFolder, mod) + } + return null + } +} diff --git a/sources_non_forked/coc.nvim/src/model/semanticTokensBuilder.ts b/sources_non_forked/coc.nvim/src/model/semanticTokensBuilder.ts new file mode 100644 index 00000000..528b29f0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/semanticTokensBuilder.ts @@ -0,0 +1,208 @@ +'use strict' +import { Range, SemanticTokens, SemanticTokensLegend } from "vscode-languageserver-protocol" + +function isStringArray(value: any): value is string[] { + return Array.isArray(value) && (value as any[]).every(elem => typeof elem === 'string') +} + +function isStrArrayOrUndefined(arg: any): arg is string[] | undefined { + return ((typeof arg === 'undefined') || isStringArray(arg)) +} + +/** + * A semantic tokens builder can help with creating a `SemanticTokens` instance + * which contains delta encoded semantic tokens. + */ +export class SemanticTokensBuilder { + private _prevLine: number + private _prevChar: number + private _dataIsSortedAndDeltaEncoded: boolean + private _data: number[] + private _dataLen: number + private _tokenTypeStrToInt: Map + private _tokenModifierStrToInt: Map + private _hasLegend: boolean + + constructor(legend?: SemanticTokensLegend) { + this._prevLine = 0 + this._prevChar = 0 + this._dataIsSortedAndDeltaEncoded = true + this._data = [] + this._dataLen = 0 + this._tokenTypeStrToInt = new Map() + this._tokenModifierStrToInt = new Map() + this._hasLegend = false + if (legend) { + this._hasLegend = true + for (let i = 0, len = legend.tokenTypes.length; i < len; i++) { + this._tokenTypeStrToInt.set(legend.tokenTypes[i], i) + } + for (let i = 0, len = legend.tokenModifiers.length; i < len; i++) { + this._tokenModifierStrToInt.set(legend.tokenModifiers[i], i) + } + } + } + + /** + * Add another token. + * + * @param line The token start line number (absolute value). + * @param char The token start character (absolute value). + * @param length The token length in characters. + * @param tokenType The encoded token type. + * @param tokenModifiers The encoded token modifiers. + */ + public push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void + /** + * Add another token. Use only when providing a legend. + * + * @param range The range of the token. Must be single-line. + * @param tokenType The token type. + * @param tokenModifiers The token modifiers. + */ + public push(range: Range, tokenType: string, tokenModifiers?: string[]): void + public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void { + if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) { + if (typeof arg4 === 'undefined') { + arg4 = 0 + } + // 1st overload + return this._pushEncoded(arg0, arg1, arg2, arg3, arg4) + } + if (Range.is(arg0) && typeof arg1 === 'string' && isStrArrayOrUndefined(arg2)) { + // 2nd overload + return this._push(arg0, arg1, arg2) + } + throw new Error('Illegal argument') + } + + private _push(range: Range, tokenType: string, tokenModifiers?: string[]): void { + if (!this._hasLegend) { + throw new Error('Legend must be provided in constructor') + } + if (range.start.line !== range.end.line) { + throw new Error('`range` cannot span multiple lines') + } + if (!this._tokenTypeStrToInt.has(tokenType)) { + throw new Error('`tokenType` is not in the provided legend') + } + const line = range.start.line + const char = range.start.character + const length = range.end.character - range.start.character + const nTokenType = this._tokenTypeStrToInt.get(tokenType)! + let nTokenModifiers = 0 + if (tokenModifiers) { + for (const tokenModifier of tokenModifiers) { + if (!this._tokenModifierStrToInt.has(tokenModifier)) { + throw new Error('`tokenModifier` is not in the provided legend') + } + const nTokenModifier = this._tokenModifierStrToInt.get(tokenModifier)! + nTokenModifiers |= (1 << nTokenModifier) >>> 0 + } + } + this._pushEncoded(line, char, length, nTokenType, nTokenModifiers) + } + + private _pushEncoded(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void { + if (this._dataIsSortedAndDeltaEncoded && (line < this._prevLine || (line === this._prevLine && char < this._prevChar))) { + // push calls were ordered and are no longer ordered + this._dataIsSortedAndDeltaEncoded = false + + // Remove delta encoding from data + const tokenCount = (this._data.length / 5) | 0 + let prevLine = 0 + let prevChar = 0 + for (let i = 0; i < tokenCount; i++) { + let line = this._data[5 * i] + let char = this._data[5 * i + 1] + + if (line === 0) { + // on the same line as previous token + line = prevLine + char += prevChar + } else { + // on a different line than previous token + line += prevLine + } + + this._data[5 * i] = line + this._data[5 * i + 1] = char + + prevLine = line + prevChar = char + } + } + + let pushLine = line + let pushChar = char + if (this._dataIsSortedAndDeltaEncoded && this._dataLen > 0) { + pushLine -= this._prevLine + if (pushLine === 0) { + pushChar -= this._prevChar + } + } + + this._data[this._dataLen++] = pushLine + this._data[this._dataLen++] = pushChar + this._data[this._dataLen++] = length + this._data[this._dataLen++] = tokenType + this._data[this._dataLen++] = tokenModifiers + + this._prevLine = line + this._prevChar = char + } + + private static _sortAndDeltaEncode(data: number[]): number[] { + let pos: number[] = [] + const tokenCount = (data.length / 5) | 0 + for (let i = 0; i < tokenCount; i++) { + pos[i] = i + } + pos.sort((a, b) => { + const aLine = data[5 * a] + const bLine = data[5 * b] + if (aLine === bLine) { + const aChar = data[5 * a + 1] + const bChar = data[5 * b + 1] + return aChar - bChar + } + return aLine - bLine + }) + const result = new Array(data.length) + let prevLine = 0 + let prevChar = 0 + for (let i = 0; i < tokenCount; i++) { + const srcOffset = 5 * pos[i] + const line = data[srcOffset + 0] + const char = data[srcOffset + 1] + const length = data[srcOffset + 2] + const tokenType = data[srcOffset + 3] + const tokenModifiers = data[srcOffset + 4] + + const pushLine = line - prevLine + const pushChar = (pushLine === 0 ? char - prevChar : char) + + const dstOffset = 5 * i + result[dstOffset + 0] = pushLine + result[dstOffset + 1] = pushChar + result[dstOffset + 2] = length + result[dstOffset + 3] = tokenType + result[dstOffset + 4] = tokenModifiers + + prevLine = line + prevChar = char + } + + return result + } + + /** + * Finish and create a `SemanticTokens` instance. + */ + public build(resultId?: string): SemanticTokens { + if (!this._dataIsSortedAndDeltaEncoded) { + return { data: SemanticTokensBuilder._sortAndDeltaEncode(this._data), resultId } + } + return { data: this._data, resultId } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/status.ts b/sources_non_forked/coc.nvim/src/model/status.ts new file mode 100644 index 00000000..17c877e9 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/status.ts @@ -0,0 +1,97 @@ +'use strict' +import { Disposable } from 'vscode-languageserver-protocol' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import { v1 as uuidv1 } from 'uuid' +const logger = require('../util/logger')('model-status') + +export const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] + +export interface StatusBarItem { + /** + * The priority of this item. Higher value means the item should + * be shown more to the left. + */ + readonly priority: number + isProgress: boolean + text: string + show(): void + hide(): void + dispose(): void +} + +export default class StatusLine implements Disposable { + private items: Map = new Map() + private shownIds: Set = new Set() + private _text = '' + private interval: NodeJS.Timer + constructor(private nvim: Neovim) { + this.interval = setInterval(() => { + this.setStatusText() + }, 100) + } + + public dispose(): void { + this.items.clear() + this.shownIds.clear() + clearInterval(this.interval) + } + + public createStatusBarItem(priority = 0, isProgress = false): StatusBarItem { + let uid = uuidv1() + + let item: StatusBarItem = { + text: '', + priority, + isProgress, + show: () => { + this.shownIds.add(uid) + this.setStatusText() + }, + hide: () => { + this.shownIds.delete(uid) + this.setStatusText() + }, + dispose: () => { + this.shownIds.delete(uid) + this.items.delete(uid) + this.setStatusText() + } + } + this.items.set(uid, item) + return item + } + + private getText(): string { + if (this.shownIds.size == 0) return '' + let d = new Date() + let idx = Math.floor(d.getMilliseconds() / 100) + let text = '' + let items: StatusBarItem[] = [] + for (let [id, item] of this.items) { + if (this.shownIds.has(id)) { + items.push(item) + } + } + items.sort((a, b) => a.priority - b.priority) + for (let item of items) { + if (!item.isProgress) { + text = `${text} ${item.text}` + } else { + text = `${text} ${frames[idx]} ${item.text}` + } + } + return text + } + + private setStatusText(): void { + let text = this.getText() + let { nvim } = this + if (text != this._text) { + this._text = text + nvim.pauseNotification() + this.nvim.setVar('coc_status', text, true) + this.nvim.call('coc#util#do_autocmd', ['CocStatusChange'], true) + nvim.resumeNotification(false, true) + } + } +} diff --git a/sources_non_forked/coc.nvim/src/model/task.ts b/sources_non_forked/coc.nvim/src/model/task.ts new file mode 100644 index 00000000..7b7a538f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/task.ts @@ -0,0 +1,91 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import events from '../events' +import { disposeAll } from '../util' + +export interface TaskOptions { + cmd: string + args?: string[] + cwd?: string + pty?: boolean + env?: { [key: string]: string } + detach?: boolean +} + +/** + * Controls long running task started by vim. + * Useful to keep the task running after CocRestart. + * + * @public + */ +export default class Task implements Disposable { + private disposables: Disposable[] = [] + private readonly _onExit = new Emitter() + private readonly _onStderr = new Emitter() + private readonly _onStdout = new Emitter() + public readonly onExit: Event = this._onExit.event + public readonly onStdout: Event = this._onStdout.event + public readonly onStderr: Event = this._onStderr.event + + /** + * @param {Neovim} nvim + * @param {string} id unique id + */ + constructor(private nvim: Neovim, private id: string) { + events.on('TaskExit', (id, code) => { + if (id == this.id) { + this._onExit.fire(code) + } + }, null, this.disposables) + events.on('TaskStderr', (id, lines) => { + if (id == this.id) { + this._onStderr.fire(lines) + } + }, null, this.disposables) + events.on('TaskStdout', (id, lines) => { + if (id == this.id) { + this._onStdout.fire(lines) + } + }, null, this.disposables) + } + + /** + * Start task, task will be restarted when already running. + * + * @param {TaskOptions} opts + * @returns {Promise} + */ + public async start(opts: TaskOptions): Promise { + let { nvim } = this + return await nvim.call('coc#task#start', [this.id, opts]) + } + + /** + * Stop task by SIGTERM or SIGKILL + */ + public async stop(): Promise { + let { nvim } = this + await nvim.call('coc#task#stop', [this.id]) + } + + /** + * Check if the task is running. + */ + public get running(): Promise { + let { nvim } = this + return nvim.call('coc#task#running', [this.id]) + } + + /** + * Stop task and dispose all events. + */ + public dispose(): void { + let { nvim } = this + nvim.call('coc#task#stop', [this.id], true) + this._onStdout.dispose() + this._onStderr.dispose() + this._onExit.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/terminal.ts b/sources_non_forked/coc.nvim/src/model/terminal.ts new file mode 100644 index 00000000..2186c78c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/terminal.ts @@ -0,0 +1,120 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +const logger = require('../util/logger')('model-terminal') + +export interface TerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name?: string + + /** + * A path to a custom shell executable to be used in the terminal. + */ + shellPath?: string + + /** + * Args for the custom shell executable, this does not work on Windows (see #8429) + */ + shellArgs?: string[] + + /** + * A path or URI for the current working directory to be used for the terminal. + */ + cwd?: string + + /** + * Object with environment variables that will be added to the VS Code process. + */ + env?: { [key: string]: string | null } + + /** + * Whether the terminal process environment should be exactly as provided in + * `TerminalOptions.env`. When this is false (default), the environment will be based on the + * window's environment and also apply configured platform settings like + * `terminal.integrated.windows.env` on top. When this is true, the complete environment + * must be provided as nothing will be inherited from the process or any configuration. + */ + strictEnv?: boolean +} + +export interface TerminalExitStatus { + code: number | undefined +} + +export default class TerminalModel { + public bufnr: number + private pid = 0 + public exitStatus: TerminalExitStatus | undefined + + constructor(private cmd: string, + private args: string[], + private nvim: Neovim, + private _name?: string, + private strictEnv?: boolean + ) { + } + + public async start(cwd?: string, env?: { [key: string]: string | null }): Promise { + let { nvim } = this + let cmd = [this.cmd, ...this.args] + let [bufnr, pid] = await nvim.call('coc#terminal#start', [cmd, cwd, env || {}, !!this.strictEnv]) + this.bufnr = bufnr + this.pid = pid + } + + public onExit(code: number | undefined): void { + this.exitStatus = { code: code === -1 ? undefined : code } + } + + public get name(): string { + return this._name || this.cmd + } + + public get processId(): Promise { + return Promise.resolve(this.pid) + } + + public sendText(text: string, addNewLine = true): void { + if (!this.bufnr) return + this.nvim.call('coc#terminal#send', [this.bufnr, text, addNewLine], true) + } + + public async show(preserveFocus?: boolean): Promise { + let { bufnr, nvim } = this + if (!bufnr) return + let [loaded, winid, curr] = await nvim.eval(`[bufloaded(${bufnr}),bufwinid(${bufnr}),win_getid()]`) as [number, number, number] + if (!loaded) return false + if (curr == winid) return true + nvim.pauseNotification() + if (winid == -1) { + nvim.command(`below ${bufnr}sb`, true) + nvim.command('resize 8', true) + nvim.call('coc#util#do_autocmd', ['CocTerminalOpen'], true) + } else { + nvim.call('win_gotoid', [winid], true) + } + nvim.command('normal! G', true) + if (preserveFocus) { + nvim.command('wincmd p', true) + } + await nvim.resumeNotification() + return true + } + + public async hide(): Promise { + let { bufnr, nvim } = this + if (!bufnr) return + await nvim.eval(`coc#window#close(bufwinid(${bufnr}))`) + } + + public dispose(): void { + if (!this.exitStatus) { + this.exitStatus = { code: undefined } + } + let { bufnr, nvim } = this + if (!bufnr) return + this.bufnr = undefined + nvim.call('coc#terminal#close', [bufnr], true) + } +} diff --git a/sources_non_forked/coc.nvim/src/model/textdocument.ts b/sources_non_forked/coc.nvim/src/model/textdocument.ts new file mode 100644 index 00000000..19dae86f --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/textdocument.ts @@ -0,0 +1,127 @@ +'use strict' +import { Position, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { TextLine } from './textline' + +export function computeLinesOffsets(lines: ReadonlyArray, eol: boolean): number[] { + const result: number[] = [] + let textOffset = 0 + for (let line of lines) { + result.push(textOffset) + textOffset += line.length + 1 + } + if (eol) result.push(textOffset) + return result +} + +/** + * Text document that created with readonly lines. + * + * Created for save memory since we could reuse readonly lines. + */ +export class LinesTextDocument implements TextDocument { + private _lineOffsets: number[] | undefined + private _content: string + constructor( + public readonly uri: string, + public readonly languageId: string, + public readonly version: number, + public lines: ReadonlyArray, + public readonly bufnr: number, + public readonly eol: boolean + ) { + } + + private get content(): string { + if (!this._content) { + this._content = this.lines.join('\n') + (this.eol ? '\n' : '') + } + return this._content + } + + public get length(): number { + if (!this._content) { + let n = this.lines.reduce((p, c) => { + return p + c.length + 1 + }, 0) + return this.eol ? n : n - 1 + } + return this._content.length + } + + public get end(): Position { + let line = this.lineCount - 1 + if (this.eol) return Position.create(line, 0) + return Position.create(line, this.lines[line].length) + } + + public get lineCount(): number { + return this.lines.length + (this.eol ? 1 : 0) + } + + public getText(range?: Range): string { + if (range) { + let { start, end } = range + if (start.line === end.line) { + if (start.character === end.character) return '' + let line = this.lines[start.line] ?? '' + return line.substring(start.character, end.character) + } + return this.content.substring(this.offsetAt(range.start), this.offsetAt(range.end)) + } + return this.content + } + + public lineAt(lineOrPos: number | Position): TextLine { + const line = Position.is(lineOrPos) ? lineOrPos.line : lineOrPos + if (typeof line !== 'number' || + line < 0 || + line >= this.lineCount || + Math.floor(line) !== line) { + throw new Error('Illegal value for `line`') + } + + return new TextLine(line, this.lines[line] ?? '', line === this.lineCount - 1) + } + + public positionAt(offset: number): Position { + offset = Math.max(Math.min(offset, this.content.length), 0) + let lineOffsets = this.getLineOffsets() + let low = 0 + let high = lineOffsets.length + if (high === 0) { + return { line: 0, character: offset } + } + while (low < high) { + let mid = Math.floor((low + high) / 2) + if (lineOffsets[mid] > offset) { + high = mid + } else { + low = mid + 1 + } + } + // low is the least x for which the line offset is larger than the current offset + // or array.length if no line offset is larger than the current offset + let line = low - 1 + return { line, character: offset - lineOffsets[line] } + } + + public offsetAt(position: Position) { + let lineOffsets = this.getLineOffsets() + if (position.line >= lineOffsets.length) { + return this.content.length + } else if (position.line < 0) { + return 0 + } + let lineOffset = lineOffsets[position.line] + let nextLineOffset = (position.line + 1 < lineOffsets.length) ? lineOffsets[position.line + 1] : this.content.length + return Math.max(Math.min(lineOffset + position.character, nextLineOffset), lineOffset) + } + + private getLineOffsets(): number[] { + if (this._lineOffsets === undefined) { + this._lineOffsets = computeLinesOffsets(this.lines, this.eol) + } + return this._lineOffsets + } +} diff --git a/sources_non_forked/coc.nvim/src/model/textline.ts b/sources_non_forked/coc.nvim/src/model/textline.ts new file mode 100644 index 00000000..1718526a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/model/textline.ts @@ -0,0 +1,66 @@ +'use strict' +import { Range } from 'vscode-languageserver-protocol' + +/** + * Represents a line of text, such as a line of source code. + * + * TextLine objects are __immutable__. When a {@link TextDocument document} changes, + * previously retrieved lines will not represent the latest state. + */ +export class TextLine { + + private readonly _line: number + private readonly _text: string + private readonly _isLastLine: boolean + + constructor(line: number, text: string, isLastLine: boolean) { + this._line = line + this._text = text + this._isLastLine = isLastLine + } + + /** + * The zero-based line number. + */ + public get lineNumber(): number { + return this._line + } + + /** + * The text of this line without the line separator characters. + */ + public get text(): string { + return this._text + } + + /** + * The range this line covers without the line separator characters. + */ + public get range(): Range { + return Range.create(this._line, 0, this._line, this._text.length) + } + + /** + * The range this line covers with the line separator characters. + */ + public get rangeIncludingLineBreak(): Range { + return this._isLastLine ? this.range : Range.create(this._line, 0, this._line + 1, 0) + } + + /** + * The offset of the first character which is not a whitespace character as defined + * by `/\s/`. **Note** that if a line is all whitespace the length of the line is returned. + */ + public get firstNonWhitespaceCharacterIndex(): number { + // TODO@api, rename to 'leadingWhitespaceLength' + return /^(\s*)/.exec(this._text)![1].length + } + + /** + * Whether this line is whitespace only, shorthand + * for {@link TextLine.firstNonWhitespaceCharacterIndex} === {@link TextLine.text TextLine.text.length}. + */ + public get isEmptyOrWhitespace(): boolean { + return this.firstNonWhitespaceCharacterIndex === this._text.length + } +} diff --git a/sources_non_forked/coc.nvim/src/plugin.ts b/sources_non_forked/coc.nvim/src/plugin.ts new file mode 100644 index 00000000..07c2b987 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/plugin.ts @@ -0,0 +1,262 @@ +'use strict' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import { EventEmitter } from 'events' +import { CodeActionKind, Disposable } from 'vscode-languageserver-protocol' +import commandManager from './commands' +import completion from './completion' +import channels from './core/channels' +import Cursors from './cursors' +import diagnosticManager from './diagnostic/manager' +import events from './events' +import extensions from './extensions' +import Handler from './handler' +import listManager from './list/manager' +import services from './services' +import snippetManager from './snippets/manager' +import sources from './sources' +import { disposeAll } from './util' +import window from './window' +import workspace from './workspace' +const logger = require('./util/logger')('plugin') + +export default class Plugin extends EventEmitter { + private _ready = false + private handler: Handler | undefined + private cursors: Cursors + private actions: Map = new Map() + private disposables: Disposable[] = [] + + constructor(public nvim: Neovim) { + super() + this.disposables.push(workspace.registerTextDocumentContentProvider('output', channels.getProvider(nvim))) + Object.defineProperty(workspace, 'nvim', { + get: () => this.nvim + }) + Object.defineProperty(window, 'cursors', { + get: () => this.cursors + }) + workspace.onDidChangeWorkspaceFolders(() => { + nvim.setVar('WorkspaceFolders', workspace.folderPaths, true) + }, null, this.disposables) + events.on('VimResized', (columns, lines) => { + if (workspace.env) Object.assign(workspace.env, { columns, lines }) + }, null, this.disposables) + this.cursors = new Cursors(nvim) + commandManager.init(nvim, this) + this.addAction('checkJsonExtension', () => { + if (extensions.has('coc-json')) return + window.showMessage(`Run :CocInstall coc-json for json intellisense`, 'more') + }) + this.addAction('rootPatterns', (bufnr: number) => this.handler.workspace.getRootPatterns(bufnr)) + this.addAction('ensureDocument', () => this.handler.workspace.ensureDocument()) + this.addAction('getConfig', async key => this.handler.workspace.getConfiguration(key)) + this.addAction('doAutocmd', async (id: number, ...args: []) => this.handler.workspace.doAutocmd(id, args)) + this.addAction('openLog', async () => this.handler.workspace.openLog()) + this.addAction('attach', () => workspace.attach()) + this.addAction('detach', () => workspace.detach()) + this.addAction('doKeymap', async (key, defaultReturn, pressed) => this.handler.workspace.doKeymap(key, defaultReturn, pressed)) + this.addAction('registExtensions', (...folders: string[]) => extensions.loadExtension(folders)) + this.addAction('snippetCheck', async (checkExpand: boolean, checkJump: boolean) => this.handler.workspace.snippetCheck(checkExpand, checkJump)) + this.addAction('snippetNext', () => snippetManager.nextPlaceholder()) + this.addAction('snippetPrev', () => snippetManager.previousPlaceholder()) + this.addAction('snippetCancel', () => snippetManager.cancel()) + this.addAction('openLocalConfig', () => window.openLocalConfig()) + this.addAction('bufferCheck', () => window.bufferCheck()) + this.addAction('showInfo', () => this.handler.workspace.showInfo()) + this.addAction('hasProvider', id => this.handler.hasProvider(id)) + this.addAction('hasSelected', () => completion.hasSelected()) + this.addAction('listNames', () => listManager.names) + this.addAction('listDescriptions', () => listManager.descriptions) + this.addAction('listLoadItems', name => listManager.loadItems(name)) + this.addAction('search', (...args: string[]) => this.handler.refactor.search(args)) + this.addAction('cursorsSelect', (bufnr: number, kind: string, mode: string) => this.cursors.select(bufnr, kind, mode)) + this.addAction('fillDiagnostics', (bufnr: number) => diagnosticManager.setLocationlist(bufnr)) + this.addAction('saveRefactor', bufnr => this.handler.refactor.save(bufnr)) + this.addAction('commandList', () => this.handler.commands.getCommandList()) + this.addAction('selectSymbolRange', (inner: boolean, visualmode: string, supportedSymbols: string[]) => this.handler.symbols.selectSymbolRange(inner, visualmode, supportedSymbols)) + this.addAction('openList', (...args: string[]) => listManager.start(args)) + this.addAction('listResume', (name?: string) => listManager.resume(name)) + this.addAction('listCancel', () => listManager.cancel(true)) + this.addAction('listPrev', (name?: string) => listManager.previous(name)) + this.addAction('listNext', (name?: string) => listManager.next(name)) + this.addAction('listFirst', (name?: string) => listManager.first(name)) + this.addAction('listLast', (name?: string) => listManager.last(name)) + this.addAction('sendRequest', (id: string, method: string, params?: any) => services.sendRequest(id, method, params)) + this.addAction('sendNotification', (id: string, method: string, params?: any) => services.sendNotification(id, method, params)) + this.addAction('registNotification', (id: string, method: string) => services.registNotification(id, method)) + this.addAction('updateConfig', (section: string, val: any) => workspace.configurations.updateUserConfig({ [section]: val })) + this.addAction('links', () => this.handler.links.getLinks()) + this.addAction('openLink', () => this.handler.links.openCurrentLink()) + this.addAction('pickColor', () => this.handler.colors.pickColor()) + this.addAction('colorPresentation', () => this.handler.colors.pickPresentation()) + this.addAction('highlight', () => this.handler.documentHighlighter.highlight()) + this.addAction('fold', (kind?: string) => this.handler.fold.fold(kind)) + this.addAction('startCompletion', option => completion.startCompletion(option)) + this.addAction('stopCompletion', () => completion.stop()) + this.addAction('sourceStat', () => sources.sourceStats()) + this.addAction('refreshSource', name => sources.refresh(name)) + this.addAction('toggleSource', name => sources.toggleSource(name)) + this.addAction('diagnosticRefresh', bufnr => diagnosticManager.refresh(bufnr)) + this.addAction('diagnosticInfo', () => diagnosticManager.echoMessage()) + this.addAction('diagnosticToggle', enable => diagnosticManager.toggleDiagnostic(enable)) + this.addAction('diagnosticToggleBuffer', (bufnr, enable) => diagnosticManager.toggleDiagnosticBuffer(bufnr, enable)) + this.addAction('diagnosticNext', severity => diagnosticManager.jumpNext(severity)) + this.addAction('diagnosticPrevious', severity => diagnosticManager.jumpPrevious(severity)) + this.addAction('diagnosticPreview', () => diagnosticManager.preview()) + this.addAction('diagnosticList', async () => diagnosticManager.getDiagnosticList()) + this.addAction('findLocations', (id, method, params, openCommand) => this.handler.locations.findLocations(id, method, params, openCommand)) + this.addAction('getTagList', () => this.handler.locations.getTagList()) + this.addAction('jumpDefinition', openCommand => this.handler.locations.gotoDefinition(openCommand)) + this.addAction('definitions', () => this.handler.locations.definitions()) + this.addAction('jumpDeclaration', openCommand => this.handler.locations.gotoDeclaration(openCommand)) + this.addAction('declarations', () => this.handler.locations.declarations()) + this.addAction('jumpImplementation', openCommand => this.handler.locations.gotoImplementation(openCommand)) + this.addAction('implementations', () => this.handler.locations.implementations()) + this.addAction('jumpTypeDefinition', openCommand => this.handler.locations.gotoTypeDefinition(openCommand)) + this.addAction('typeDefinitions', () => this.handler.locations.typeDefinitions()) + this.addAction('jumpReferences', openCommand => this.handler.locations.gotoReferences(openCommand)) + this.addAction('references', excludeDeclaration => this.handler.locations.references(excludeDeclaration)) + this.addAction('jumpUsed', openCommand => this.handler.locations.gotoReferences(openCommand, false)) + this.addAction('doHover', hoverTarget => this.handler.hover.onHover(hoverTarget)) + this.addAction('definitionHover', hoverTarget => this.handler.hover.definitionHover(hoverTarget)) + this.addAction('getHover', () => this.handler.hover.getHover()) + this.addAction('showSignatureHelp', () => this.handler.signature.triggerSignatureHelp()) + this.addAction('documentSymbols', (bufnr?: number) => this.handler.symbols.getDocumentSymbols(bufnr)) + this.addAction('symbolRanges', () => this.handler.documentHighlighter.getSymbolsRanges()) + this.addAction('selectionRanges', () => this.handler.selectionRange.getSelectionRanges()) + this.addAction('rangeSelect', (visualmode, forward) => this.handler.selectionRange.selectRange(visualmode, forward)) + this.addAction('rename', newName => this.handler.rename.rename(newName)) + this.addAction('getWorkspaceSymbols', input => this.handler.symbols.getWorkspaceSymbols(input)) + this.addAction('resolveWorkspaceSymbol', symbolInfo => this.handler.symbols.resolveWorkspaceSymbol(symbolInfo)) + this.addAction('formatSelected', mode => this.handler.format.formatCurrentRange(mode)) + this.addAction('format', () => this.handler.format.formatCurrentBuffer()) + this.addAction('commands', () => this.handler.commands.getCommands()) + this.addAction('services', () => services.getServiceStats()) + this.addAction('toggleService', name => services.toggle(name)) + this.addAction('codeAction', (mode, only) => this.handler.codeActions.doCodeAction(mode, only)) + this.addAction('organizeImport', () => this.handler.codeActions.organizeImport()) + this.addAction('fixAll', () => this.handler.codeActions.doCodeAction(null, [CodeActionKind.SourceFixAll])) + this.addAction('doCodeAction', codeAction => this.handler.codeActions.applyCodeAction(codeAction)) + this.addAction('codeActions', (mode, only) => this.handler.codeActions.getCurrentCodeActions(mode, only)) + this.addAction('quickfixes', mode => this.handler.codeActions.getCurrentCodeActions(mode, [CodeActionKind.QuickFix])) + this.addAction('codeLensAction', () => this.handler.codeLens.doAction()) + this.addAction('runCommand', (...args: any[]) => this.handler.commands.runCommand(...args)) + this.addAction('doQuickfix', () => this.handler.codeActions.doQuickfix()) + this.addAction('refactor', () => this.handler.refactor.doRefactor()) + this.addAction('repeatCommand', () => this.handler.commands.repeat()) + this.addAction('installExtensions', (...list: string[]) => extensions.installExtensions(list)) + this.addAction('updateExtensions', sync => extensions.updateExtensions(sync)) + this.addAction('extensionStats', () => extensions.getExtensionStates()) + this.addAction('loadedExtensions', () => extensions.loadedExtensions()) + this.addAction('watchExtension', (id: string) => extensions.watchExtension(id)) + this.addAction('activeExtension', name => extensions.activate(name)) + this.addAction('deactivateExtension', name => extensions.deactivate(name)) + this.addAction('reloadExtension', name => extensions.reloadExtension(name)) + this.addAction('toggleExtension', name => extensions.toggleExtension(name)) + this.addAction('uninstallExtension', (...args: string[]) => extensions.uninstallExtension(args)) + this.addAction('getCurrentFunctionSymbol', () => this.handler.symbols.getCurrentFunctionSymbol()) + this.addAction('showOutline', (keep?: number) => this.handler.symbols.showOutline(keep)) + this.addAction('hideOutline', () => this.handler.symbols.hideOutline()) + this.addAction('getWordEdit', () => this.handler.rename.getWordEdit()) + this.addAction('addCommand', cmd => this.handler.commands.addVimCommand(cmd)) + this.addAction('addRanges', ranges => this.cursors.addRanges(ranges)) + this.addAction('currentWorkspacePath', () => workspace.rootPath) + this.addAction('selectCurrentPlaceholder', triggerAutocmd => snippetManager.selectCurrentPlaceholder(!!triggerAutocmd)) + this.addAction('codeActionRange', (start, end, only) => this.handler.codeActions.codeActionRange(start, end, only)) + this.addAction('incomingCalls', item => this.handler.callHierarchy.getIncoming(item)) + this.addAction('outgoingCalls', item => this.handler.callHierarchy.getOutgoing(item)) + this.addAction('showIncomingCalls', () => this.handler.callHierarchy.showCallHierarchyTree('incoming')) + this.addAction('showOutgoingCalls', () => this.handler.callHierarchy.showCallHierarchyTree('outgoing')) + this.addAction('inspectSemanticToken', () => this.handler.semanticHighlighter.inspectSemanticToken()) + this.addAction('semanticHighlight', () => this.handler.semanticHighlighter.highlightCurrent()) + this.addAction('showSemanticHighlightInfo', () => this.handler.semanticHighlighter.showHighlightInfo()) + } + + private addAction(key: string, fn: Function): void { + if (this.actions.has(key)) { + throw new Error(`Action ${key} already exists`) + } + this.actions.set(key, fn) + } + + public async init(): Promise { + let { nvim } = this + let s = Date.now() + try { + await extensions.init() + await workspace.init(window) + nvim.setVar('coc_workspace_initialized', true, true) + snippetManager.init() + completion.init() + diagnosticManager.init() + listManager.init(nvim) + sources.init() + this.handler = new Handler(nvim) + services.init() + extensions.activateExtensions() + workspace.autocmds.setupDynamicAutocmd(true) + nvim.pauseNotification() + nvim.setVar('WorkspaceFolders', workspace.folderPaths, true) + nvim.setVar('coc_service_initialized', 1, true) + nvim.call('coc#util#do_autocmd', ['CocNvimInit'], true) + nvim.resumeNotification(false, true) + this._ready = true + await events.fire('ready', []) + logger.info(`coc.nvim initialized with node: ${process.version} after ${Date.now() - s}ms`) + this.emit('ready') + } catch (e) { + nvim.echoError(e) + } + } + + public get isReady(): boolean { + return this._ready + } + + public get ready(): Promise { + if (this._ready) return Promise.resolve() + return new Promise(resolve => { + this.once('ready', () => { + resolve() + }) + }) + } + + public hasAction(method: string): boolean { + return this.actions.has(method) + } + + public async cocAction(method: string, ...args: any[]): Promise { + let fn = this.actions.get(method) + if (!fn) throw new Error(`Action "${method}" doesn't exist`) + let ts = Date.now() + let res = await Promise.resolve(fn.apply(null, args)) + let dt = Date.now() - ts + if (dt > 500) logger.warn(`Slow action "${method}" cost ${dt}ms`) + return res + } + + public getHandler(): Handler { + return this.handler + } + + public dispose(): void { + this.removeAllListeners() + disposeAll(this.disposables) + extensions.dispose() + listManager.dispose() + workspace.dispose() + channels.dispose() + window.dispose() + sources.dispose() + services.stopAll() + services.dispose() + if (this.handler) { + this.handler.dispose() + } + snippetManager.dispose() + commandManager.dispose() + completion.dispose() + diagnosticManager.dispose() + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/callHierarchyManager.ts b/sources_non_forked/coc.nvim/src/provider/callHierarchyManager.ts new file mode 100644 index 00000000..cdf9b673 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/callHierarchyManager.ts @@ -0,0 +1,46 @@ +'use strict' +import { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CancellationToken, Disposable, DocumentSelector, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { CallHierarchyProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class CallHierarchyManager extends Manager { + + public register(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + if (provider.prepareCallHierarchy === null) return null + return await Promise.resolve(provider.prepareCallHierarchy(document, position, token)) + } + + public async provideCallHierarchyOutgoingCalls(document: TextDocument, item: CallHierarchyItem, token: CancellationToken): Promise { + let providerItem = this.getProvider(document) + if (!providerItem) return null + let { provider } = providerItem + if (provider.provideCallHierarchyOutgoingCalls === null) return null + return await Promise.resolve(provider.provideCallHierarchyOutgoingCalls(item, token)) + } + + public async provideCallHierarchyIncomingCalls(document: TextDocument, item: CallHierarchyItem, token: CancellationToken): Promise { + let providerItem = this.getProvider(document) + if (!providerItem) return null + let { provider } = providerItem + if (provider.provideCallHierarchyIncomingCalls(item, token) === null) return null + + return await Promise.resolve(provider.provideCallHierarchyIncomingCalls(item, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/codeActionManager.ts b/sources_non_forked/coc.nvim/src/provider/codeActionManager.ts new file mode 100644 index 00000000..73641041 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/codeActionManager.ts @@ -0,0 +1,91 @@ +'use strict' +import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, Command, Disposable, DocumentSelector, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { CodeActionProvider } from './index' +import { ExtendedCodeAction } from '../types' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' +import { omit } from '../util/lodash' +const logger = require('../util/logger')('codeActionManager') + +export default class CodeActionManager extends Manager { + public register(selector: DocumentSelector, provider: CodeActionProvider, clientId: string | undefined, codeActionKinds?: CodeActionKind[]): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider, + kinds: codeActionKinds, + clientId + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideCodeActions( + document: TextDocument, + range: Range, + context: CodeActionContext, + token: CancellationToken + ): Promise { + let providers = this.getProviders(document) + if (!providers.length) return null + if (context.only) { + let { only } = context + providers = providers.filter(p => { + if (p.kinds && !p.kinds.some(kind => only.includes(kind))) { + return false + } + return true + }) + } + let res: ExtendedCodeAction[] = [] + await Promise.all(providers.map(item => { + let { provider, id } = item + return Promise.resolve(provider.provideCodeActions(document, range, context, token)).then(actions => { + if (!actions || actions.length == 0) return + for (let action of actions) { + if (Command.is(action)) { + let codeAction: ExtendedCodeAction = { + title: action.title, + command: action, + providerId: id + } + res.push(codeAction) + } else { + if (context.only) { + if (!action.kind) continue + let found = false + for (let only of context.only) { + if (action.kind.startsWith(only)) { + found = true + break + } + } + if (!found) continue + } + let idx = res.findIndex(o => o.title == action.title) + if (idx == -1) { + res.push(Object.assign({ providerId: id }, action)) + } + } + } + }) + })) + return res + } + + public async resolveCodeAction(codeAction: ExtendedCodeAction, token: CancellationToken): Promise { + // no need to resolve + if (codeAction.edit != null) return codeAction + let id = codeAction.providerId + if (!id) throw new Error(`provider id not found from codeAction`) + let provider = this.getProviderById(id) + if (!provider || typeof provider.resolveCodeAction !== 'function') { + return codeAction + } + let resolved = await Promise.resolve(provider.resolveCodeAction(omit(codeAction, ['providerId']), token)) + return resolved || codeAction + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/codeLensManager.ts b/sources_non_forked/coc.nvim/src/provider/codeLensManager.ts new file mode 100644 index 00000000..23ea82bc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/codeLensManager.ts @@ -0,0 +1,59 @@ +'use strict' +import { CancellationToken, CodeLens, Disposable, DocumentSelector } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { CodeLensProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' +import { omit } from '../util/lodash' +// const logger = require('../util/logger')('codeActionManager') + +export default class CodeLensManager extends Manager { + + public register(selector: DocumentSelector, provider: CodeLensProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideCodeLenses( + document: TextDocument, + token: CancellationToken + ): Promise { + let providers = this.getProviders(document) + if (!providers.length) return null + let arr = await Promise.all(providers.map(item => { + let { provider, id } = item + return Promise.resolve(provider.provideCodeLenses(document, token)).then(res => { + if (Array.isArray(res)) { + for (let item of res) { + (item as any).source = id + } + } + return res + }) + })) + return [].concat(...arr) + } + + public async resolveCodeLens( + codeLens: CodeLens, + token: CancellationToken + ): Promise { + // no need to resolve + if (codeLens.command) return codeLens + let { source } = codeLens as any + let provider = this.getProviderById(source) + if (!provider || typeof provider.resolveCodeLens != 'function') { + return codeLens + } + let res = await Promise.resolve(provider.resolveCodeLens(omit(codeLens, ['source']), token)) + Object.assign(codeLens, res) + return codeLens + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/declarationManager.ts b/sources_non_forked/coc.nvim/src/provider/declarationManager.ts new file mode 100644 index 00000000..a442cdf6 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/declarationManager.ts @@ -0,0 +1,33 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Location, Position, LocationLink } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DeclarationProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' +const logger = require('../util/logger')('definitionManager') + +export default class DeclarationManager extends Manager { + + public register(selector: DocumentSelector, provider: DeclarationProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideDeclaration( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return await Promise.resolve(provider.provideDeclaration(document, position, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/definitionManager.ts b/sources_non_forked/coc.nvim/src/provider/definitionManager.ts new file mode 100644 index 00000000..054abece --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/definitionManager.ts @@ -0,0 +1,65 @@ +'use strict' +import { CancellationToken, Definition, DefinitionLink, Disposable, DocumentSelector, Location, LocationLink, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DefinitionProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' +import { equals } from '../util/object' +const logger = require('../util/logger')('definitionManager') + +export default class DefinitionManager extends Manager { + + public register(selector: DocumentSelector, provider: DefinitionProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + private async getDefinitions( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise<(Definition | DefinitionLink[])[]> { + const providers = this.getProviders(document) + if (!providers.length) return [] + const arr = await Promise.all(providers.map(item => { + const { provider } = item + return Promise.resolve(provider.provideDefinition(document, position, token)) + })) + return arr + } + + public async provideDefinition( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + const arr = await this.getDefinitions(document, position, token) + return this.toLocations(arr) + } + + public async provideDefinitionLinks( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + const arr = await this.getDefinitions(document, position, token) + const defs: DefinitionLink[] = [] + for (const def of arr) { + if (!Array.isArray(def)) continue + for (const val of def) { + if (LocationLink.is(val)) { + let idx = defs.findIndex(o => o.targetUri == val.targetUri && equals(o.targetRange, val.targetRange)) + if (idx == -1) defs.push(val) + } + } + } + return defs + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/documentColorManager.ts b/sources_non_forked/coc.nvim/src/provider/documentColorManager.ts new file mode 100644 index 00000000..be08e2e0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/documentColorManager.ts @@ -0,0 +1,38 @@ +'use strict' +import { CancellationToken, ColorInformation, ColorPresentation, Disposable, DocumentSelector } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentColorProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class DocumentColorManager extends Manager { + + public register(selector: DocumentSelector, provider: DocumentColorProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideDocumentColors(document: TextDocument, token: CancellationToken): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + let res: ColorInformation[] = await Promise.resolve(provider.provideDocumentColors(document, token)) + return res + } + + public async provideColorPresentations(colorInformation: ColorInformation, document: TextDocument, token: CancellationToken): Promise { + let { range, color } = colorInformation + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + let res = await Promise.resolve(provider.provideColorPresentations(color, { document, range }, token)) + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/documentHighlightManager.ts b/sources_non_forked/coc.nvim/src/provider/documentHighlightManager.ts new file mode 100644 index 00000000..3f7c513b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/documentHighlightManager.ts @@ -0,0 +1,32 @@ +'use strict' +import { CancellationToken, Disposable, DocumentHighlight, DocumentSelector, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentHighlightProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class DocumentHighlightManager extends Manager { + + public register(selector: DocumentSelector, provider: DocumentHighlightProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideDocumentHighlights( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return await Promise.resolve(provider.provideDocumentHighlights(document, position, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/documentLinkManager.ts b/sources_non_forked/coc.nvim/src/provider/documentLinkManager.ts new file mode 100644 index 00000000..51d1050b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/documentLinkManager.ts @@ -0,0 +1,52 @@ +'use strict' +import { CancellationToken, Disposable, DocumentLink, DocumentSelector } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentLinkProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class DocumentLinkManager extends Manager { + + public register(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable { + let item = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + private async _provideDocumentLinks(item: ProviderItem, document: TextDocument, token: CancellationToken): Promise { + let { provider, id } = item + let items = await Promise.resolve(provider.provideDocumentLinks(document, token)) + if (!items || !items.length) return [] + items.forEach(item => { + item.data = item.data || {} + item.data.source = id + }) + return items + } + + public async provideDocumentLinks(document: TextDocument, token: CancellationToken): Promise { + let items = this.getProviders(document) + if (items.length == 0) return [] + const arr = await Promise.all(items.map(item => this._provideDocumentLinks(item, document, token))) + return [].concat(...arr) + } + + public async resolveDocumentLink(link: DocumentLink, token: CancellationToken): Promise { + let { data } = link + if (!data || !data.source) return null + for (let item of this.providers) { + if (item.id == data.source) { + let { provider } = item + link = await Promise.resolve(provider.resolveDocumentLink(link, token)) + return link + } + } + return null + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/documentSymbolManager.ts b/sources_non_forked/coc.nvim/src/provider/documentSymbolManager.ts new file mode 100644 index 00000000..8913a6b5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/documentSymbolManager.ts @@ -0,0 +1,38 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, DocumentSymbol, SymbolInformation } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentSymbolProvider, DocumentSymbolProviderMetadata } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class DocumentSymbolManager extends Manager { + + public register(selector: DocumentSelector, provider: DocumentSymbolProvider, meta?: DocumentSymbolProviderMetadata): Disposable { + let item: ProviderItem = { + id: uuid(), + meta, + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public getMetaData(document: TextDocument): DocumentSymbolProviderMetadata { + let item = this.getProvider(document) + if (!item) return {} + return item.provider.meta ?? {} + } + + public async provideDocumentSymbols( + document: TextDocument, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return (await Promise.resolve(provider.provideDocumentSymbols(document, token))) || [] + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/foldingRangeManager.ts b/sources_non_forked/coc.nvim/src/provider/foldingRangeManager.ts new file mode 100644 index 00000000..1fe81868 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/foldingRangeManager.ts @@ -0,0 +1,28 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, FoldingRange } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { FoldingContext, FoldingRangeProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class FoldingRangeManager extends Manager { + + public register(selector: DocumentSelector, provider: FoldingRangeProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideFoldingRanges(document: TextDocument, context: FoldingContext, token: CancellationToken): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return (await Promise.resolve(provider.provideFoldingRanges(document, context, token)) || []) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/formatManager.ts b/sources_non_forked/coc.nvim/src/provider/formatManager.ts new file mode 100644 index 00000000..94609b8d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/formatManager.ts @@ -0,0 +1,39 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, FormattingOptions, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentFormattingEditProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class FormatManager extends Manager { + + public register(selector: DocumentSelector, + provider: DocumentFormattingEditProvider, + priority = 0): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + priority, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public handles(doc: TextDocument): boolean { + return this.getProvider(doc) != null + } + + public async provideDocumentFormattingEdits( + document: TextDocument, + options: FormattingOptions, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return await Promise.resolve(provider.provideDocumentFormattingEdits(document, options, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/formatRangeManager.ts b/sources_non_forked/coc.nvim/src/provider/formatRangeManager.ts new file mode 100644 index 00000000..0d97b4cc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/formatRangeManager.ts @@ -0,0 +1,36 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, FormattingOptions, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentRangeFormattingEditProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class FormatRangeManager extends Manager { + + public register(selector: DocumentSelector, + provider: DocumentRangeFormattingEditProvider, + priority = 0): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider, + priority + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideDocumentRangeFormattingEdits( + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return await Promise.resolve(provider.provideDocumentRangeFormattingEdits(document, range, options, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/hoverManager.ts b/sources_non_forked/coc.nvim/src/provider/hoverManager.ts new file mode 100644 index 00000000..0527bb6e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/hoverManager.ts @@ -0,0 +1,37 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Hover, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { HoverProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class HoverManager extends Manager { + + public register(selector: DocumentSelector, provider: HoverProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideHover( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let items = this.getProviders(document) + if (items.length === 0) return null + let res = [] + for (let i = 0, len = items.length; i < len; i += 1) { + const item = items[i] + let hover = await Promise.resolve(item.provider.provideHover(document, position, token)) + if (hover && hover.contents != '') res.push(hover) + } + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/implementationManager.ts b/sources_non_forked/coc.nvim/src/provider/implementationManager.ts new file mode 100644 index 00000000..88c17096 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/implementationManager.ts @@ -0,0 +1,35 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Location, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { ImplementationProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class ImplementationManager extends Manager { + + public register(selector: DocumentSelector, provider: ImplementationProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideReferences( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let providers = this.getProviders(document) + if (!providers.length) return null + let arr = await Promise.all(providers.map(item => { + let { provider } = item + return Promise.resolve(provider.provideImplementation(document, position, token)) + })) + return this.toLocations(arr) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/index.ts b/sources_non_forked/coc.nvim/src/provider/index.ts new file mode 100644 index 00000000..640163f2 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/index.ts @@ -0,0 +1,860 @@ +'use strict' +import { CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, CancellationToken, CodeAction, CodeActionContext, CodeActionKind, CodeLens, Color, ColorInformation, ColorPresentation, Command, CompletionContext, CompletionItem, CompletionList, Definition, DefinitionLink, DocumentHighlight, DocumentLink, DocumentSymbol, Event, FoldingRange, FormattingOptions, Hover, LinkedEditingRanges, Location, Position, Range, SelectionRange, SemanticTokens, SemanticTokensDelta, SignatureHelp, SignatureHelpContext, SymbolInformation, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import { InlayHint } from '../inlayHint' + +/** + * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves + * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a + * thenable. + * + * The snippets below are all valid implementations of the [`HoverProvider`](#HoverProvider): + * + * ```ts + * let a: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Hover('Hello World') + * } + * } + * + * let b: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Promise(resolve => { + * resolve(new Hover('Hello World')) + * }) + * } + * } + * + * let c: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return; // undefined + * } + * } + * ``` + */ +export type ProviderResult = + | T + | undefined + | null + | Thenable + +/** + * The completion item provider interface defines the contract between extensions and + * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). + * + * Providers can delay the computation of the [`detail`](#CompletionItem.detail) + * and [`documentation`](#CompletionItem.documentation) properties by implementing the + * [`resolveCompletionItem`](#CompletionItemProvider.resolveCompletionItem)-function. However, properties that + * are needed for the initial sorting and filtering, like `sortText`, `filterText`, `insertText`, and `range`, must + * not be changed during resolve. + * + * Providers are asked for completions either explicitly by a user gesture or -depending on the configuration- + * implicitly when typing words or trigger characters. + */ +export interface CompletionItemProvider { + /** + * Provide completion items for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @param context How the completion was triggered. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideCompletionItems( + document: TextDocument, + position: Position, + token: CancellationToken, + context?: CompletionContext + ): ProviderResult + + /** + * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) + * or [details](#CompletionItem.detail). + * + * The editor will only resolve a completion item once. + * + * @param item A completion item currently active in the UI. + * @param token A cancellation token. + * @return The resolved completion item or a thenable that resolves to of such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveCompletionItem?( + item: CompletionItem, + token: CancellationToken + ): ProviderResult +} + +/** + * The hover provider interface defines the contract between extensions and + * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ +export interface HoverProvider { + /** + * Provide a hover for the given position and document. Multiple hovers at the same + * position will be merged by the editor. A hover can have a range which defaults + * to the word range at the position when omitted. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A hover or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideHover( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * The definition provider interface defines the contract between extensions and + * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) + * and peek definition features. + */ +export interface DefinitionProvider { + /** + * Provide the definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideDefinition( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * The definition provider interface defines the contract between extensions and + * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) + * and peek definition features. + */ +export interface DeclarationProvider { + /** + * Provide the declaration of the symbol at the given position and document. + */ + provideDeclaration(document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +/** + * The signature help provider interface defines the contract between extensions and + * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ +export interface SignatureHelpProvider { + /** + * Provide help for the signature at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return Signature help or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideSignatureHelp( + document: TextDocument, + position: Position, + token: CancellationToken, + context: SignatureHelpContext + ): ProviderResult +} + +/** + * The type definition provider defines the contract between extensions and + * the go to type definition feature. + */ +export interface TypeDefinitionProvider { + /** + * Provide the type definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideTypeDefinition( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * Value-object that contains additional information when + * requesting references. + */ +export interface ReferenceContext { + /** + * Include the declaration of the current symbol. + */ + includeDeclaration: boolean +} + +/** + * The reference provider interface defines the contract between extensions and + * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature. + */ +export interface ReferenceProvider { + /** + * Provide a set of project-wide references for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param context + * @param token A cancellation token. + * @return An array of locations or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideReferences( + document: TextDocument, + position: Position, + context: ReferenceContext, + token: CancellationToken + ): ProviderResult +} + +/** + * Folding context (for future use) + */ +export interface FoldingContext {} + +/** + * The folding range provider interface defines the contract between extensions and + * [Folding](https://code.visualstudio.com/docs/editor/codebasics#_folding) in the editor. + */ +export interface FoldingRangeProvider { + /** + * Returns a list of folding ranges or null and undefined if the provider + * does not want to participate or was cancelled. + * + * @param document The document in which the command was invoked. + * @param context Additional context information (for future use) + * @param token A cancellation token. + */ + provideFoldingRanges( + document: TextDocument, + context: FoldingContext, + token: CancellationToken + ): ProviderResult +} + +export interface DocumentSymbolProviderMetadata { + /** + * A human-readable string that is shown when multiple outlines trees show for one document. + */ + label?: string +} + +/** + * The document symbol provider interface defines the contract between extensions and + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. + */ +export interface DocumentSymbolProvider { + + meta?: DocumentSymbolProviderMetadata + + /** + * Provide symbol information for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentSymbols( + document: TextDocument, + token: CancellationToken + ): ProviderResult +} + +/** + * The implementation provider interface defines the contract between extensions and + * the go to implementation feature. + */ +export interface ImplementationProvider { + /** + * Provide the implementations of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideImplementation( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * The workspace symbol provider interface defines the contract between extensions and + * the [symbol search](https://code.visualstudio.com/docs/editor/editingevolved#_open-symbol-by-name)-feature. + */ +export interface WorkspaceSymbolProvider { + /** + * Project-wide search for a symbol matching the given query string. It is up to the provider + * how to search given the query string, like substring, indexOf etc. To improve performance implementors can + * skip the [location](#SymbolInformation.location) of symbols and implement `resolveWorkspaceSymbol` to do that + * later. + * + * The `query`-parameter should be interpreted in a *relaxed way* as the editor will apply its own highlighting + * and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the + * characters of *query* appear in their order in a candidate symbol. Don't use prefix, substring, or similar + * strict matching. + * + * @param query A non-empty query string. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideWorkspaceSymbols( + query: string, + token: CancellationToken + ): ProviderResult + + /** + * Given a symbol fill in its [location](#SymbolInformation.location). This method is called whenever a symbol + * is selected in the UI. Providers can implement this method and return incomplete symbols from + * [`provideWorkspaceSymbols`](#WorkspaceSymbolProvider.provideWorkspaceSymbols) which often helps to improve + * performance. + * + * @param symbol The symbol that is to be resolved. Guaranteed to be an instance of an object returned from an + * earlier call to `provideWorkspaceSymbols`. + * @param token A cancellation token. + * @return The resolved symbol or a thenable that resolves to that. When no result is returned, + * the given `symbol` is used. + */ + resolveWorkspaceSymbol?( + symbol: SymbolInformation, + token: CancellationToken + ): ProviderResult +} + +/** + * The rename provider interface defines the contract between extensions and + * the [rename](https://code.visualstudio.com/docs/editor/editingevolved#_rename-symbol)-feature. + */ +export interface RenameProvider { + /** + * Provide an edit that describes changes that have to be made to one + * or many resources to rename a symbol to a different name. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param newName The new name of the symbol. If the given name is not valid, the provider must return a rejected promise. + * @param token A cancellation token. + * @return A workspace edit or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideRenameEdits( + document: TextDocument, + position: Position, + newName: string, + token: CancellationToken + ): ProviderResult + + /** + * Optional function for resolving and validating a position *before* running rename. The result can + * be a range or a range and a placeholder text. The placeholder text should be the identifier of the symbol + * which is being renamed - when omitted the text in the returned range is used. + * + * @param document The document in which rename will be invoked. + * @param position The position at which rename will be invoked. + * @param token A cancellation token. + * @return The range or range and placeholder text of the identifier that is to be renamed. The lack of a result can signaled by returning `undefined` or `null`. + */ + prepareRename?( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ +export interface DocumentFormattingEditProvider { + /** + * Provide formatting edits for a whole document. + * + * @param document The document in which the command was invoked. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentFormattingEdits( + document: TextDocument, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult +} + +/** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ +export interface DocumentRangeFormattingEditProvider { + /** + * Provide formatting edits for a range in a document. + * + * The given range is a hint and providers can decide to format a smaller + * or larger range. Often this is done by adjusting the start and end + * of the range to full syntax nodes. + * + * @param document The document in which the command was invoked. + * @param range The range which should be formatted. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentRangeFormattingEdits( + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult +} + +/** + * The code action interface defines the contract between extensions and + * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + * + * A code action can be any command that is [known](#commands.getCommands) to the system. + */ +export interface CodeActionProvider { + /** + * Provide commands for the given document and range. + * + * @param document The document in which the command was invoked. + * @param range The selector or range for which the command was invoked. This will always be a selection if + * there is a currently active editor. + * @param context Context carrying additional information. + * @param token A cancellation token. + * @return An array of commands, quick fixes, or refactorings or a thenable of such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeActions( + document: TextDocument, + range: Range, + context: CodeActionContext, + token: CancellationToken + ): ProviderResult<(Command | CodeAction)[]> + + /** + * Given a code action fill in its [`edit`](#CodeAction.edit)-property. Changes to + * all other properties, like title, are ignored. A code action that has an edit + * will not be resolved. + * + * @param codeAction A code action. + * @param token A cancellation token. + * @return The resolved code action or a thenable that resolves to such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveCodeAction?(codeAction: T, token: CancellationToken): ProviderResult +} + +/** + * Metadata about the type of code actions that a [CodeActionProvider](#CodeActionProvider) providers + */ +export interface CodeActionProviderMetadata { + /** + * [CodeActionKinds](#CodeActionKind) that this provider may return. + * + * The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the provider + * may list our every specific kind they provide, such as `CodeActionKind.Refactor.Extract.append('function`)` + */ + readonly providedCodeActionKinds?: ReadonlyArray +} + +/** + * The document highlight provider interface defines the contract between extensions and + * the word-highlight-feature. + */ +export interface DocumentHighlightProvider { + + /** + * Provide a set of document highlights, like all occurrences of a variable or + * all exit-points of a function. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentHighlights( + document: TextDocument, + position: Position, + token: CancellationToken + ): ProviderResult +} + +/** + * The document link provider defines the contract between extensions and feature of showing + * links in the editor. + */ +export interface DocumentLinkProvider { + + /** + * Provide links for the given document. Note that the editor ships with a default provider that detects + * `http(s)` and `file` links. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [document links](#DocumentLink) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentLinks(document: TextDocument, token: CancellationToken): ProviderResult + + /** + * Given a link fill in its [target](#DocumentLink.target). This method is called when an incomplete + * link is selected in the UI. Providers can implement this method and return incomple links + * (without target) from the [`provideDocumentLinks`](#DocumentLinkProvider.provideDocumentLinks) method which + * often helps to improve performance. + * + * @param link The link that is to be resolved. + * @param token A cancellation token. + */ + resolveDocumentLink?(link: DocumentLink, token: CancellationToken): ProviderResult +} + +/** + * A code lens provider adds [commands](#Command) to source text. The commands will be shown + * as dedicated horizontal lines in between the source text. + */ +export interface CodeLensProvider { + + /** + * An optional event to signal that the code lenses from this provider have changed. + */ + onDidChangeCodeLenses?: Event + + /** + * Compute a list of [lenses](#CodeLens). This call should return as fast as possible and if + * computing the commands is expensive implementors should only return code lens objects with the + * range set and implement [resolve](#CodeLensProvider.resolveCodeLens). + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of code lenses or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeLenses(document: TextDocument, token: CancellationToken): ProviderResult + + /** + * This function will be called for each visible code lens, usually when scrolling and after + * calls to [compute](#CodeLensProvider.provideCodeLenses)-lenses. + * + * @param codeLens code lens that must be resolved. + * @param token A cancellation token. + * @return The given, resolved code lens or thenable that resolves to such. + */ + resolveCodeLens?(codeLens: CodeLens, token: CancellationToken): ProviderResult +} + +/** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ +export interface OnTypeFormattingEditProvider { + + /** + * Provide formatting edits after a character has been typed. + * + * The given position and character should hint to the provider + * what range the position to expand to, like find the matching `{` + * when `}` has been entered. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param ch The character that has been typed. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideOnTypeFormattingEdits(document: TextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult +} + +/** + * The document color provider defines the contract between extensions and feature of + * picking and modifying colors in the editor. + */ +export interface DocumentColorProvider { + + /** + * Provide colors for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [color information](#ColorInformation) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult + + /** + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideColorPresentations(color: Color, context: { document: TextDocument; range: Range }, token: CancellationToken): ProviderResult +} + +export interface TextDocumentContentProvider { + + /** + * An event to signal a resource has changed. + */ + onDidChange?: Event + + /** + * Provide textual content for a given uri. + * + * The editor will use the returned string-content to create a readonly + * [document](#TextDocument). Resources allocated should be released when + * the corresponding document has been [closed](#workspace.onDidCloseTextDocument). + * + * @param uri An uri which scheme matches the scheme this provider was [registered](#workspace.registerTextDocumentContentProvider) for. + * @param token A cancellation token. + * @return A string or a thenable that resolves to such. + */ + provideTextDocumentContent(uri: URI, token: CancellationToken): ProviderResult +} + +export interface SelectionRangeProvider { + /** + * Provide selection ranges starting at a given position. The first range must [contain](#Range.contains) + * position and subsequent ranges must contain the previous range. + */ + provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult +} + +/** + * The call hierarchy provider interface describes the contract between extensions + * and the call hierarchy feature which allows to browse calls and caller of function, + * methods, constructor etc. + */ +export interface CallHierarchyProvider { + + /** + * Bootstraps call hierarchy by returning the item that is denoted by the given document + * and position. This item will be used as entry into the call graph. Providers should + * return `undefined` or `null` when there is no item at the given location. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @returns A call hierarchy item or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): ProviderResult + + /** + * Provide all incoming calls for an item, e.g all callers for a method. In graph terms this describes directed + * and annotated edges inside the call graph, e.g the given item is the starting node and the result is the nodes + * that can be reached. + * + * @param item The hierarchy item for which incoming calls should be computed. + * @param token A cancellation token. + * @returns A set of incoming calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult + + /** + * Provide all outgoing calls for an item, e.g call calls to functions, methods, or constructors from the given item. In + * graph terms this describes directed and annotated edges inside the call graph, e.g the given item is the starting + * node and the result is the nodes that can be reached. + * + * @param item The hierarchy item for which outgoing calls should be computed. + * @param token A cancellation token. + * @returns A set of outgoing calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult +} + +/** + * The document semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ +export interface DocumentSemanticTokensProvider { + /** + * An optional event to signal that the semantic tokens from this provider have changed. + */ + onDidChangeSemanticTokens?: Event + + /** + * Tokens in a file are represented as an array of integers. The position of each token is expressed relative to + * the token before it, because most tokens remain stable relative to each other when edits are made in a file. + * + * --- + * In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices: + * + * - at index `5*i` - `deltaLine`: token line number, relative to the previous token + * - at index `5*i+1` - `deltaStart`: token start character, relative to the previous token (relative to 0 or the previous token's start if they are on the same line) + * - at index `5*i+2` - `length`: the length of the token. A token cannot be multiline. + * - at index `5*i+3` - `tokenType`: will be looked up in `SemanticTokensLegend.tokenTypes`. We currently ask that `tokenType` < 65536. + * - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + * + * --- + * ### How to encode tokens + * + * Here is an example for encoding a file with 3 tokens in a uint32 array: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 2, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 5, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * + * 1. First of all, a legend must be devised. This legend must be provided up-front and capture all possible token types. + * For this example, we will choose the following legend which must be passed in when registering the provider: + * ``` + * tokenTypes: ['property', 'type', 'class'], + * tokenModifiers: ['private', 'static'] + * ``` + * + * 2. The first transformation step is to encode `tokenType` and `tokenModifiers` as integers using the legend. Token types are looked + * up by index, so a `tokenType` value of `1` means `tokenTypes[1]`. Multiple token modifiers can be set by using bit flags, + * so a `tokenModifier` value of `3` is first viewed as binary `0b00000011`, which means `[tokenModifiers[0], tokenModifiers[1]]` because + * bits 0 and 1 are set. Using this legend, the tokens now are: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { line: 2, startChar: 10, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { line: 5, startChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 3. The next step is to represent each token relative to the previous token in the file. In this case, the second token + * is on the same line as the first token, so the `startChar` of the second token is made relative to the `startChar` + * of the first token, so it will be `10 - 5`. The third token is on a different line than the second token, so the + * `startChar` of the third token will not be altered: + * ``` + * { deltaLine: 2, deltaStartChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { deltaLine: 0, deltaStartChar: 5, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { deltaLine: 3, deltaStartChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 4. Finally, the last step is to inline each of the 5 fields for a token in a single array, which is a memory friendly representation: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to encode tokens as integers. + * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. + * *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'. + */ + provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult + + /** + * Instead of always returning all the tokens in a file, it is possible for a `DocumentSemanticTokensProvider` to implement + * this method (`provideDocumentSemanticTokensEdits`) and then return incremental updates to the previously provided semantic tokens. + * + * --- + * ### How tokens change when the document changes + * + * Suppose that `provideDocumentSemanticTokens` has previously returned the following semantic tokens: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * Also suppose that after some edits, the new semantic tokens in a file are: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * It is possible to express these new tokens in terms of an edit applied to the previous tokens: + * ``` + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // new tokens + * + * edit: { start: 0, deleteCount: 1, data: [3] } // replace integer at offset 0 with 3 + * ``` + * + * *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again. + * *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state. + */ + provideDocumentSemanticTokensEdits?(document: TextDocument, previousResultId: string, token: CancellationToken): ProviderResult +} + +/** + * The document range semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ +export interface DocumentRangeSemanticTokensProvider { + /** + * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens). + */ + provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult +} + +export interface LinkedEditingRangeProvider { + /** + * For a given position in a document, returns the range of the symbol at the position and all ranges + * that have the same content. A change to one of the ranges can be applied to all other ranges if the new content + * is valid. An optional word pattern can be returned with the result to describe valid contents. + * If no result-specific word pattern is provided, the word pattern from the language configuration is used. + * + * @param document The document in which the provider was invoked. + * @param position The position at which the provider was invoked. + * @param token A cancellation token. + * @return A list of ranges that can be edited together + */ + provideLinkedEditingRanges(document: TextDocument, position: Position, token: CancellationToken): ProviderResult +} + +/** + * The inlay hints provider interface defines the contract between extensions and + * the inlay hints feature. + */ +export interface InlayHintsProvider { + + /** + * An optional event to signal that inlay hints from this provider have changed. + */ + onDidChangeInlayHints?: Event + + /** + * Provide inlay hints for the given range and document. + * + * *Note* that inlay hints that are not {@link Range.contains contained} by the given range are ignored. + * + * @param document The document in which the command was invoked. + * @param range The range for which inlay hints should be computed. + * @param token A cancellation token. + * @return An array of inlay hints or a thenable that resolves to such. + */ + provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): ProviderResult + + /** + * Given an inlay hint fill in {@link InlayHint.tooltip tooltip}, {@link InlayHint.textEdits text edits}, + * or complete label {@link InlayHintLabelPart parts}. + * + * *Note* that the editor will resolve an inlay hint at most once. + * + * @param hint An inlay hint. + * @param token A cancellation token. + * @return The resolved inlay hint or a thenable that resolves to such. It is OK to return the given `item`. When no result is returned, the given `item` will be used. + */ + resolveInlayHint?(hint: T, token: CancellationToken): ProviderResult +} diff --git a/sources_non_forked/coc.nvim/src/provider/inlayHintManager.ts b/sources_non_forked/coc.nvim/src/provider/inlayHintManager.ts new file mode 100644 index 00000000..66e39600 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/inlayHintManager.ts @@ -0,0 +1,97 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, Disposable, DocumentSelector, Range } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { InlayHint } from '../inlayHint' +import { comparePosition, positionInRange } from '../util/position' +import { InlayHintsProvider } from './index' +import Manager, { ProviderItem } from './manager' +const logger = require('../util/logger')('inlayHintManger') + +export interface InlayHintWithProvider extends InlayHint { + providerId: string + resolved?: boolean +} + +export default class InlayHintManger extends Manager { + + public register(selector: DocumentSelector, provider: InlayHintsProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + /** + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + */ + public async provideInlayHints( + document: TextDocument, + range: Range, + token: CancellationToken + ): Promise { + let items = this.getProviders(document) + if (items.length === 0) return null + let results: InlayHintWithProvider[] = [] + let finished = 0 + await Promise.all(items.map(item => { + let { id, provider } = item + return Promise.resolve(provider.provideInlayHints(document, range, token)).then(hints => { + if (token.isCancellationRequested) return + for (let hint of hints) { + if (!isValidInlayHint(hint, range)) continue + if (finished > 0 && results.findIndex(o => sameHint(o, hint)) != -1) continue + results.push({ + providerId: id, + ...hint + }) + } + finished += 1 + }, e => { + logger.error(`Error on provideInlayHints`, e) + }) + })) + return results + } + + public async resolveInlayHint(hint: InlayHintWithProvider, token: CancellationToken): Promise { + let provider = this.getProviderById(hint.providerId) + if (!provider || typeof provider.resolveInlayHint !== 'function' || hint.resolved === true) return hint + let res = await Promise.resolve(provider.resolveInlayHint(hint, token)) + if (token.isCancellationRequested) return hint + return Object.assign(hint, res, { resolved: true }) + } +} + +export function sameHint(one: InlayHint, other: InlayHint): boolean { + if (comparePosition(one.position, other.position) !== 0) return false + return getLabel(one) === getLabel(other) +} + +export function isValidInlayHint(hint: InlayHint, range: Range): boolean { + if (hint.label.length === 0 || (Array.isArray(hint.label) && hint.label.every(part => part.value.length === 0))) { + logger.warn('INVALID inlay hint, empty label', hint) + return false + } + if (!InlayHint.is(hint)) { + logger.warn('INVALID inlay hint', hint) + return false + } + if (range && positionInRange(hint.position, range) !== 0) { + // console.log('INVALID inlay hint, position outside range', range, hint); + return false + } + return true +} + +export function getLabel(hint: InlayHint): string { + if (typeof hint.label === 'string') return hint.label + return hint.label.map(o => o.value).join(' ') +} diff --git a/sources_non_forked/coc.nvim/src/provider/linkedEditingRangeManager.ts b/sources_non_forked/coc.nvim/src/provider/linkedEditingRangeManager.ts new file mode 100644 index 00000000..9042f174 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/linkedEditingRangeManager.ts @@ -0,0 +1,30 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, Disposable, DocumentSelector, LinkedEditingRanges, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { LinkedEditingRangeProvider } from './index' +import Manager, { ProviderItem } from './manager' +const logger = require('../util/logger')('linkedEditingManager') + +export default class LinkedEditingRangeManager extends Manager { + public register(selector: DocumentSelector, provider: LinkedEditingRangeProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideLinkedEditingRanges(document: TextDocument, position: Position, token: CancellationToken): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + if (!provider.provideLinkedEditingRanges) return null + + return await Promise.resolve(provider.provideLinkedEditingRanges(document, position, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/manager.ts b/sources_non_forked/coc.nvim/src/provider/manager.ts new file mode 100644 index 00000000..7c316cc0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/manager.ts @@ -0,0 +1,80 @@ +'use strict' +import { Definition, DocumentSelector, Location, LocationLink } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import workspace from '../workspace' +import { equals } from '../util/object' +const logger = require('../util/logger')('provider-manager') + +export interface ProviderItem { + id: string + selector: DocumentSelector + provider: T + [key: string]: any +} + +export default class Manager { + protected providers: Set> = new Set() + + public hasProvider(document: TextDocument): boolean { + return this.getProvider(document) != null + } + + protected getProvider(document: TextDocument): ProviderItem { + let currScore = 0 + let providerItem: ProviderItem + for (let item of this.providers) { + let { selector, priority } = item + let score = workspace.match(selector, document) + if (score == 0) continue + if (typeof priority == 'number') { + score = priority + } + if (score < currScore) continue + currScore = score + providerItem = item + } + return providerItem + } + + protected getProviderById(id: string): T { + let item = Array.from(this.providers).find(o => o.id == id) + return item ? item.provider : null + } + + protected getProviders(document: TextDocument): ProviderItem[] { + let items = Array.from(this.providers) + items = items.filter(item => workspace.match(item.selector, document) > 0) + return items.sort((a, b) => workspace.match(b.selector, document) - workspace.match(a.selector, document)) + } + + protected toLocations(arr: (Definition | LocationLink[] | null)[]): Location[] { + let res: Location[] = [] + for (let def of arr) { + if (!def) continue + if (Location.is(def)) { + addLocation(res, def) + } else if (Array.isArray(def)) { + for (let d of def) { + if (Location.is(d)) { + addLocation(res, d) + } else if (LocationLink.is(d)) { + let { targetUri, targetSelectionRange, targetRange } = d + addLocation(res, Location.create(targetUri, targetSelectionRange || targetRange)) + } + } + } else { + logger.error(`Bad definition`, def) + } + } + return res + } +} + +/** + * Add unique location + */ +function addLocation(arr: Location[], location: Location): void { + let { range, uri } = location + if (arr.find(o => o.uri == uri && equals(o.range, range)) != null) return + arr.push(location) +} diff --git a/sources_non_forked/coc.nvim/src/provider/onTypeFormatManager.ts b/sources_non_forked/coc.nvim/src/provider/onTypeFormatManager.ts new file mode 100644 index 00000000..669f3f33 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/onTypeFormatManager.ts @@ -0,0 +1,55 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Position, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import workspace from '../workspace' +import { OnTypeFormattingEditProvider } from './index' +const logger = require('../util/logger')('onTypeFormatManager') + +export interface ProviderItem { + triggerCharacters: string[] + selector: DocumentSelector + provider: OnTypeFormattingEditProvider +} + +export default class OnTypeFormatManager { + private providers: Set = new Set() + + public register(selector: DocumentSelector, provider: OnTypeFormattingEditProvider, triggerCharacters: string[]): Disposable { + let item: ProviderItem = { + triggerCharacters, + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public hasProvider(document: TextDocument): boolean { + for (let o of this.providers) { + let { selector } = o + if (workspace.match(selector, document) > 0) { + return true + } + } + return false + } + + public getProvider(document: TextDocument, triggerCharacter: string): OnTypeFormattingEditProvider | null { + for (let o of this.providers) { + let { triggerCharacters, selector } = o + if (workspace.match(selector, document) > 0 && triggerCharacters.includes(triggerCharacter)) { + return o.provider + } + } + return null + } + + public async onCharacterType(character: string, document: TextDocument, position: Position, token: CancellationToken): Promise { + let provider = this.getProvider(document, character) + if (!provider) return + let formatOpts = await workspace.getFormatOptions(document.uri) + return await Promise.resolve(provider.provideOnTypeFormattingEdits(document, position, character, formatOpts, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/referenceManager.ts b/sources_non_forked/coc.nvim/src/provider/referenceManager.ts new file mode 100644 index 00000000..cd56ae5c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/referenceManager.ts @@ -0,0 +1,36 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Location, Position, ReferenceContext } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { ReferenceProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class ReferenceManager extends Manager { + + public register(selector: DocumentSelector, provider: ReferenceProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideReferences( + document: TextDocument, + position: Position, + context: ReferenceContext, + token: CancellationToken + ): Promise { + let providers = this.getProviders(document) + if (!providers.length) return null + let arr = await Promise.all(providers.map(item => { + let { provider } = item + return Promise.resolve(provider.provideReferences(document, position, context, token)) + })) + return this.toLocations(arr) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/renameManager.ts b/sources_non_forked/coc.nvim/src/provider/renameManager.ts new file mode 100644 index 00000000..1b87659e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/renameManager.ts @@ -0,0 +1,48 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Position, Range, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { RenameProvider } from './index' +import Manager from './manager' +import { v4 as uuid } from 'uuid' + +export default class RenameManager extends Manager { + + public register(selector: DocumentSelector, provider: RenameProvider): Disposable { + let item = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideRenameEdits( + document: TextDocument, + position: Position, + newName: string, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + return await Promise.resolve(provider.provideRenameEdits(document, position, newName, token)) + } + + public async prepareRename( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + if (provider.prepareRename == null) return null + let res = await Promise.resolve(provider.prepareRename(document, position, token)) + // can not rename + if (res == null) return false + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/selectionRangeManager.ts b/sources_non_forked/coc.nvim/src/provider/selectionRangeManager.ts new file mode 100644 index 00000000..e87ba60a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/selectionRangeManager.ts @@ -0,0 +1,38 @@ +'use strict' +import { SelectionRange, CancellationToken, Disposable, DocumentSelector, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { SelectionRangeProvider } from './index' +import Manager from './manager' +import { v4 as uuid } from 'uuid' + +export default class SelectionRangeManager extends Manager { + + public register(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable { + let item = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideSelectionRanges( + document: TextDocument, + positions: Position[], + token: CancellationToken + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + let ranges: SelectionRange[] = await Promise.resolve(provider.provideSelectionRanges(document, positions, token)) + if (!ranges || ranges.length == 0) return [] + for (let i = 0; i < ranges.length - 1; i++) { + let r = ranges[i] + if (!r.parent) r.parent = ranges[i + 1] + } + return ranges + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/semanticTokensManager.ts b/sources_non_forked/coc.nvim/src/provider/semanticTokensManager.ts new file mode 100644 index 00000000..f0e18ca3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/semanticTokensManager.ts @@ -0,0 +1,69 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, Disposable, DocumentSelector, SemanticTokens, SemanticTokensDelta, SemanticTokensLegend } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentSemanticTokensProvider } from './index' +import Manager, { ProviderItem } from './manager' +const logger = require('../util/logger')('semanticTokensManager') + +export default class SemanticTokensManager extends Manager { + private resolvedProvider: Map = new Map() + + public register(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend, onChange: () => void): Disposable { + let id = uuid() + let item: ProviderItem = { + id, + selector, + legend, + provider + } + this.providers.add(item) + let disposable: Disposable | undefined + if (typeof provider.onDidChangeSemanticTokens === 'function') { + disposable = provider.onDidChangeSemanticTokens(() => { + onChange() + }) + } + return Disposable.create(() => { + disposable?.dispose() + for (let [uri, providerId] of this.resolvedProvider.entries()) { + if (providerId == id) { + this.resolvedProvider.delete(uri) + } + } + this.providers.delete(item) + }) + } + + public getLegend(document: TextDocument): SemanticTokensLegend { + const item = this.getProvider(document) + if (!item) return + // save matched provider + this.resolvedProvider.set(document.uri, item.id) + return item.legend + } + + protected resolveProvider(document: TextDocument): DocumentSemanticTokensProvider { + let id = this.resolvedProvider.get(document.uri) + if (id) return this.getProviderById(id) + return this.getProvider(document)?.provider + } + + public hasSemanticTokensEdits(document: TextDocument): boolean { + let provider = this.resolveProvider(document) + if (!provider) return false + return (typeof provider.provideDocumentSemanticTokensEdits === 'function') + } + + public async provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): Promise { + let provider = this.resolveProvider(document) + if (!provider || typeof provider.provideDocumentSemanticTokens !== 'function') return null + return await Promise.resolve(provider.provideDocumentSemanticTokens(document, token)) + } + + public async provideDocumentSemanticTokensEdits(document: TextDocument, previousResultId: string, token: CancellationToken): Promise { + let provider = this.resolveProvider(document) + if (!provider || typeof provider.provideDocumentSemanticTokensEdits !== 'function') return null + return await Promise.resolve(provider.provideDocumentSemanticTokensEdits(document, previousResultId, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/semanticTokensRangeManager.ts b/sources_non_forked/coc.nvim/src/provider/semanticTokensRangeManager.ts new file mode 100644 index 00000000..401ac06c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/semanticTokensRangeManager.ts @@ -0,0 +1,36 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, Disposable, DocumentSelector, Range, SemanticTokens, SemanticTokensLegend } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { DocumentRangeSemanticTokensProvider } from './index' +import Manager, { ProviderItem } from './manager' +const logger = require('../util/logger')('semanticTokensRangeManager') + +export default class SemanticTokensRangeManager extends Manager { + public register(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + legend, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public getLegend(document: TextDocument): SemanticTokensLegend { + const item = this.getProvider(document) + if (!item) return + return item.legend as SemanticTokensLegend + } + + public async provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): Promise { + let item = this.getProvider(document) + if (!item) return null + let { provider } = item + if (provider.provideDocumentRangeSemanticTokens === null) return null + return await Promise.resolve(provider.provideDocumentRangeSemanticTokens(document, range, token)) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/signatureManager.ts b/sources_non_forked/coc.nvim/src/provider/signatureManager.ts new file mode 100644 index 00000000..4366d1fa --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/signatureManager.ts @@ -0,0 +1,43 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Position, SignatureHelp, SignatureHelpContext } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { SignatureHelpProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class SignatureManager extends Manager { + + public register(selector: DocumentSelector, provider: SignatureHelpProvider, triggerCharacters?: string[]): Disposable { + let characters = triggerCharacters.reduce((p, c) => p.concat(c.length == 1 ? [c] : c.split(/\s*/g)), [] as string[]) + let item: ProviderItem = { + id: uuid(), + selector, + provider, + triggerCharacters: characters + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public shouldTrigger(document: TextDocument, triggerCharacter: string): boolean { + let item = this.getProvider(document) + if (!item) return false + let { triggerCharacters } = item + return triggerCharacters && triggerCharacters.indexOf(triggerCharacter) != -1 + } + + public async provideSignatureHelp( + document: TextDocument, + position: Position, + token: CancellationToken, + context: SignatureHelpContext + ): Promise { + let item = this.getProvider(document) + if (!item) return null + let res = await Promise.resolve(item.provider.provideSignatureHelp(document, position, token, context)) + if (res && res.signatures && res.signatures.length) return res + return null + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/typeDefinitionManager.ts b/sources_non_forked/coc.nvim/src/provider/typeDefinitionManager.ts new file mode 100644 index 00000000..d0647344 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/typeDefinitionManager.ts @@ -0,0 +1,35 @@ +'use strict' +import { CancellationToken, Disposable, DocumentSelector, Location, Position } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { TypeDefinitionProvider } from './index' +import Manager, { ProviderItem } from './manager' +import { v4 as uuid } from 'uuid' + +export default class TypeDefinitionManager extends Manager { + + public register(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable { + let item: ProviderItem = { + id: uuid(), + selector, + provider + } + this.providers.add(item) + return Disposable.create(() => { + this.providers.delete(item) + }) + } + + public async provideTypeDefinition( + document: TextDocument, + position: Position, + token: CancellationToken + ): Promise { + let providers = this.getProviders(document) + if (!providers.length) return null + let arr = await Promise.all(providers.map(item => { + let { provider } = item + return Promise.resolve(provider.provideTypeDefinition(document, position, token)) + })) + return this.toLocations(arr) + } +} diff --git a/sources_non_forked/coc.nvim/src/provider/workspaceSymbolsManager.ts b/sources_non_forked/coc.nvim/src/provider/workspaceSymbolsManager.ts new file mode 100644 index 00000000..a46aa48d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/provider/workspaceSymbolsManager.ts @@ -0,0 +1,48 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, Disposable, SymbolInformation } from 'vscode-languageserver-protocol' +import { WorkspaceSymbolProvider } from './index' + +export default class WorkspaceSymbolManager { + private providers: Map = new Map() + + public register(provider: WorkspaceSymbolProvider): Disposable { + let id = uuid() + this.providers.set(id, provider) + return Disposable.create(() => { + this.providers.delete(id) + }) + } + + public async provideWorkspaceSymbols( + query: string, + token: CancellationToken + ): Promise { + let entries = Array.from(this.providers.entries()) + if (!entries.length) return [] + let res: SymbolInformation[] = [] + await Promise.all(entries.map(o => { + let [id, p] = o + return Promise.resolve(p.provideWorkspaceSymbols(query, token)).then(list => { + if (list) res.push(...list.map(item => Object.assign({ source: id }, item))) + }) + })) + return res + } + + public async resolveWorkspaceSymbol( + symbolInfo: SymbolInformation, + token: CancellationToken + ): Promise { + let provider = this.providers.get((symbolInfo as any).source) + if (!provider) return + if (typeof provider.resolveWorkspaceSymbol != 'function') { + return Promise.resolve(symbolInfo) + } + return await Promise.resolve(provider.resolveWorkspaceSymbol(symbolInfo, token)) + } + + public hasProvider(): boolean { + return this.providers.size > 0 + } +} diff --git a/sources_non_forked/coc.nvim/src/services.ts b/sources_non_forked/coc.nvim/src/services.ts new file mode 100644 index 00000000..09ea19e3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/services.ts @@ -0,0 +1,569 @@ +'use strict' +import { SpawnOptions } from 'child_process' +import { EventEmitter } from 'events' +import fs from 'fs' +import net from 'net' +import { CancellationToken, CancellationTokenSource, Disposable, DocumentSelector, Emitter, Event } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { Executable, ForkOptions, LanguageClient, LanguageClientOptions, RevealOutputChannelOn, ServerOptions, State, Transport, TransportKind } from './language-client' +import { ServiceStat } from './types' +import { disposeAll, wait } from './util' +import window from './window' +import workspace from './workspace' +const logger = require('./util/logger')('services') + +interface ServiceInfo { + id: string + state: string + languageIds: string[] +} + +export interface LanguageServerConfig { + module?: string + command?: string + transport?: string + transportPort?: number + disableSnippetCompletion?: boolean + disableDynamicRegister?: boolean + disabledFeatures?: string[] + formatterPriority?: number + filetypes: string[] + additionalSchemes?: string[] + enable?: boolean + args?: string[] + cwd?: string + env?: any + // socket port + port?: number + host?: string + detached?: boolean + shell?: boolean + execArgv?: string[] + rootPatterns?: string[] + ignoredRootPaths?: string[] + initializationOptions?: any + progressOnInitialization?: boolean + revealOutputChannelOn?: string + configSection?: string + stdioEncoding?: string + runtime?: string +} + +export function getStateName(state: ServiceStat): string { + switch (state) { + case ServiceStat.Initial: + return 'init' + case ServiceStat.Running: + return 'running' + case ServiceStat.Starting: + return 'starting' + case ServiceStat.StartFailed: + return 'startFailed' + case ServiceStat.Stopping: + return 'stopping' + case ServiceStat.Stopped: + return 'stopped' + default: + return 'unknown' + } +} + +export interface IServiceProvider { + // unique service id + id: string + name: string + client?: LanguageClient + selector: DocumentSelector + // current state + state: ServiceStat + start(): Promise + dispose(): void + stop(): Promise | void + restart(): Promise | void + onServiceReady: Event +} + +export class ServiceManager extends EventEmitter implements Disposable { + private readonly registered: Map = new Map() + private disposables: Disposable[] = [] + + public init(): void { + workspace.onDidOpenTextDocument(document => { + this.start(document) + }, null, this.disposables) + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('languageserver')) { + this.createCustomServices() + } + }, null, this.disposables) + this.createCustomServices() + } + + public dispose(): void { + this.removeAllListeners() + disposeAll(this.disposables) + for (let service of this.registered.values()) { + service.dispose() + } + } + + public regist(service: IServiceProvider): Disposable { + let { id } = service + if (!id) logger.error('invalid service configuration. ', service.name) + if (this.registered.get(id)) return + this.registered.set(id, service) + logger.info(`registered service "${id}"`) + if (this.shouldStart(service)) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + service.start() + } + if (service.state == ServiceStat.Running) { + this.emit('ready', id) + } + service.onServiceReady(() => { + logger.info(`service ${id} started`) + this.emit('ready', id) + }, null, this.disposables) + return Disposable.create(() => { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + service.stop() + service.dispose() + this.registered.delete(id) + }) + } + + public getService(id: string): IServiceProvider { + let service = this.registered.get(id) + if (!service) service = this.registered.get(`languageserver.${id}`) + return service + } + + private shouldStart(service: IServiceProvider): boolean { + if (service.state != ServiceStat.Initial) { + return false + } + let selector = service.selector + for (let doc of workspace.documents) { + if (workspace.match(selector, doc.textDocument)) { + return true + } + } + return false + } + + private start(document: TextDocument): void { + let services = this.getServices(document) + for (let service of services) { + if (service.state == ServiceStat.Initial) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + service.start() + } + } + } + + public getServices(document: TextDocument): IServiceProvider[] { + let res: IServiceProvider[] = [] + for (let service of this.registered.values()) { + if (workspace.match(service.selector, document) > 0) { + res.push(service) + } + } + return res + } + + public stop(id: string): Promise { + let service = this.registered.get(id) + if (!service) { + window.showMessage(`Service ${id} not found`, 'error') + return + } + return Promise.resolve(service.stop()) + } + + public stopAll(): void { + for (let service of this.registered.values()) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + service.stop() + } + } + + public async toggle(id: string): Promise { + let service = this.registered.get(id) + if (!service) { + window.showMessage(`Service ${id} not found`, 'error') + return + } + let { state } = service + try { + if (state == ServiceStat.Running) { + await Promise.resolve(service.stop()) + } else if (state == ServiceStat.Initial) { + await service.start() + } else if (state == ServiceStat.Stopped) { + await service.restart() + } + } catch (e) { + window.showMessage(`Service error: ${e}`, 'error') + } + } + + public getServiceStats(): ServiceInfo[] { + let res: ServiceInfo[] = [] + for (let [id, service] of this.registered) { + res.push({ + id, + languageIds: documentSelectorToLanguageIds(service.selector), + state: getStateName(service.state) + }) + } + return res + } + + private createCustomServices(): void { + let lspConfig = workspace.getConfiguration().get<{ key: LanguageServerConfig }>('languageserver', {} as any) + for (let key of Object.keys(lspConfig)) { + let config: LanguageServerConfig = lspConfig[key] + if (!this.validServerConfig(key, config)) { + continue + } + this.registLanguageClient(key, config) + } + } + + private validServerConfig(key: string, config: LanguageServerConfig): boolean { + let errors: string[] = [] + if (config.module != null && typeof config.module !== 'string') { + errors.push(`"module" field of languageserver ${key} should be string`) + } + if (config.command != null && typeof config.command !== 'string') { + errors.push(`"command" field of languageserver ${key} should be string`) + } + if (config.transport != null && typeof config.transport !== 'string') { + errors.push(`"transport" field of languageserver ${key} should be string`) + } + if (config.transportPort != null && typeof config.transportPort !== 'number') { + errors.push(`"transportPort" field of languageserver ${key} should be string`) + } + if (!Array.isArray(config.filetypes) || !config.filetypes.every(s => typeof s === 'string')) { + errors.push(`"filetypes" field of languageserver ${key} should be array of string`) + } + if (config.additionalSchemes && (!Array.isArray(config.additionalSchemes) || config.additionalSchemes.some(s => typeof s !== 'string'))) { + errors.push(`"additionalSchemes" field of languageserver ${key} should be array of string`) + } + if (errors.length) { + window.showMessage(errors.join('\n'), 'error') + return false + } + return true + } + + private waitClient(id: string): Promise { + let service = this.getService(id) + if (service && service.state == ServiceStat.Running) return Promise.resolve() + if (service) return new Promise(resolve => { + service.onServiceReady(() => { + resolve() + }) + }) + return new Promise(resolve => { + let listener = clientId => { + if (clientId == id || clientId == `languageserver.${id}`) { + this.off('ready', listener) + resolve() + } + } + this.on('ready', listener) + }) + } + + public async registNotification(id: string, method: string): Promise { + await this.waitClient(id) + let service = this.getService(id) + if (!service.client) { + window.showMessage(`Not a language client: ${id}`, 'error') + return + } + let client = service.client + client.onNotification(method, async result => { + workspace.nvim.call('coc#do_notify', [id, method, result], true) + }) + } + + public async sendNotification(id: string, method: string, params?: any): Promise { + if (!method) throw new Error(`method required for ontification`) + let service = this.getService(id) + // wait for extension activate + if (!service || !service.client) throw new Error(`Language server ${id} not found`) + if (service.state == ServiceStat.Starting) { + await service.client.onReady() + } + if (service.state != ServiceStat.Running) { + throw new Error(`Language server ${id} not running`) + } + await Promise.resolve(service.client.sendNotification(method, params)) + } + + public async sendRequest(id: string, method: string, params?: any, token?: CancellationToken): Promise { + if (!method) throw new Error(`method required for sendRequest`) + let service = this.getService(id) + // wait for extension activate + if (!service) await wait(100) + service = this.getService(id) + if (!service || !service.client) { + throw new Error(`Language server ${id} not found`) + } + if (service.state == ServiceStat.Starting) { + await service.client.onReady() + } + if (service.state != ServiceStat.Running) { + throw new Error(`Language server ${id} not running`) + } + if (!token) { + let tokenSource = new CancellationTokenSource() + token = tokenSource.token + } + return await Promise.resolve(service.client.sendRequest(method, params, token)) + } + + public registLanguageClient(client: LanguageClient): Disposable + public registLanguageClient(name: string, config: LanguageServerConfig): Disposable + public registLanguageClient(name: string | LanguageClient, config?: LanguageServerConfig): Disposable { + let id = typeof name === 'string' ? `languageserver.${name}` : name.id + let disposables: Disposable[] = [] + let onDidServiceReady = new Emitter() + let client: LanguageClient | null = typeof name === 'string' ? null : name + if (this.registered.has(id)) return + let created = false + let service: IServiceProvider = { + id, + client, + name: typeof name === 'string' ? name : name.name, + selector: typeof name === 'string' ? getDocumentSelector(config.filetypes, config.additionalSchemes) : name.clientOptions.documentSelector, + state: ServiceStat.Initial, + onServiceReady: onDidServiceReady.event, + start: (): Promise => { + if (service.state == ServiceStat.Starting || service.state == ServiceStat.Running) { + return + } + if (client && !client.needsStart()) { + return + } + if (created && client) { + client.restart() + return Promise.resolve() + } + if (!created) { + if (typeof name == 'string' && !client) { + let config: LanguageServerConfig = workspace.getConfiguration().get<{ key: LanguageServerConfig }>('languageserver', {} as any)[name] + if (!config || config.enable === false) return + let opts = getLanguageServerOptions(id, name, config) + if (!opts) return + client = new LanguageClient(id, name, opts[1], opts[0]) + service.selector = opts[0].documentSelector + service.client = client + } + client.onDidChangeState(changeEvent => { + let { oldState, newState } = changeEvent + if (newState == State.Starting) { + service.state = ServiceStat.Starting + } else if (newState == State.Running) { + service.state = ServiceStat.Running + } else if (newState == State.Stopped) { + service.state = ServiceStat.Stopped + } + let oldStr = stateString(oldState) + let newStr = stateString(newState) + logger.info(`${client.name} state change: ${oldStr} => ${newStr}`) + }, null, disposables) + created = true + } + service.state = ServiceStat.Starting + logger.debug(`starting service: ${id}`) + let disposable = client.start() + disposables.push(disposable) + return new Promise(resolve => { + client.onReady().then(() => { + onDidServiceReady.fire(void 0) + resolve() + }, e => { + window.showMessage(`Server ${id} failed to start: ${e}`, 'error') + logger.error(`Server ${id} failed to start:`, e) + service.state = ServiceStat.StartFailed + resolve() + }) + }) + }, + dispose: async () => { + onDidServiceReady.dispose() + disposeAll(disposables) + }, + stop: async (): Promise => { + if (!client || !client.needsStop()) return + await Promise.resolve(client.stop()) + }, + restart: async (): Promise => { + if (client) { + service.state = ServiceStat.Starting + client.restart() + } else { + await service.start() + } + }, + } + return this.regist(service) + } +} + +export function documentSelectorToLanguageIds(documentSelector: DocumentSelector): string[] { + let res = documentSelector.map(filter => { + if (typeof filter == 'string') { + return filter + } + return filter.language + }) + res = res.filter(s => typeof s == 'string') + return Array.from(new Set(res)) +} + +// convert config to options +export function getLanguageServerOptions(id: string, name: string, config: Readonly): [LanguageClientOptions, ServerOptions] { + let { command, module, port, args, filetypes } = config + args = args || [] + if (!filetypes) { + window.showMessage(`Wrong configuration of LS "${name}", filetypes not found`, 'error') + return null + } + if (!command && !module && !port) { + window.showMessage(`Wrong configuration of LS "${name}", no command or module specified.`, 'error') + return null + } + let serverOptions: ServerOptions + if (module) { + module = workspace.expand(module) + if (!fs.existsSync(module)) { + window.showMessage(`Module file "${module}" not found for LS "${name}"`, 'error') + return null + } + serverOptions = { + module, + runtime: config.runtime || process.execPath, + args, + transport: getTransportKind(config), + options: getForkOptions(config) + } + } else if (command) { + serverOptions = { + command, + args, + options: getSpawnOptions(config) + } as Executable + } else if (port) { + serverOptions = () => new Promise((resolve, reject) => { + let client = new net.Socket() + let host = config.host || '127.0.0.1' + logger.info(`languageserver "${id}" connecting to ${host}:${port}`) + client.connect(port, host, () => { + resolve({ + reader: client, + writer: client + }) + }) + client.on('error', e => { + reject(new Error(`Connection error for ${id}: ${e.message}`)) + }) + }) + } + // compatible + let disabledFeatures: string[] = Array.from(config.disabledFeatures || []) + for (let key of ['disableWorkspaceFolders', 'disableCompletion', 'disableDiagnostics']) { + if (config[key] === true) { + let s = key.slice(7) + disabledFeatures.push(s[0].toLowerCase() + s.slice(1)) + } + } + let disableSnippetCompletion = !!config.disableSnippetCompletion + let ignoredRootPaths = config.ignoredRootPaths || [] + let clientOptions: LanguageClientOptions = { + ignoredRootPaths: ignoredRootPaths.map(s => workspace.expand(s)), + disableSnippetCompletion, + disableDynamicRegister: !!config.disableDynamicRegister, + disabledFeatures, + formatterPriority: config.formatterPriority || 0, + documentSelector: getDocumentSelector(config.filetypes, config.additionalSchemes), + revealOutputChannelOn: getRevealOutputChannelOn(config.revealOutputChannelOn), + synchronize: { + configurationSection: `${id}.settings` + }, + diagnosticCollectionName: name, + outputChannelName: id, + stdioEncoding: config.stdioEncoding || 'utf8', + progressOnInitialization: config.progressOnInitialization === true, + initializationOptions: config.initializationOptions || {} + } + return [clientOptions, serverOptions] +} + +export function getRevealOutputChannelOn(revealOn: string | undefined): RevealOutputChannelOn { + switch (revealOn) { + case 'info': + return RevealOutputChannelOn.Info + case 'warn': + return RevealOutputChannelOn.Warn + case 'error': + return RevealOutputChannelOn.Error + case 'never': + return RevealOutputChannelOn.Never + default: + return RevealOutputChannelOn.Never + } +} + +export function getDocumentSelector(filetypes: string[] | undefined, additionalSchemes?: string[]): DocumentSelector { + let documentSelector: DocumentSelector = [] + let schemes = ['file', 'untitled'].concat(additionalSchemes || []) + if (!filetypes) return schemes.map(s => ({ scheme: s })) + filetypes.forEach(filetype => { + documentSelector.push(...schemes.map(scheme => ({ language: filetype, scheme }))) + }) + return documentSelector +} + +export function getTransportKind(config: LanguageServerConfig): Transport { + let { transport, transportPort } = config + if (!transport || transport == 'ipc') return TransportKind.ipc + if (transport == 'stdio') return TransportKind.stdio + if (transport == 'pipe') return TransportKind.pipe + return { kind: TransportKind.socket, port: transportPort } +} + +function getForkOptions(config: LanguageServerConfig): ForkOptions { + return { + cwd: config.cwd, + execArgv: config.execArgv || [], + env: config.env || undefined + } +} + +function getSpawnOptions(config: LanguageServerConfig): SpawnOptions { + return { + cwd: config.cwd, + detached: !!config.detached, + shell: !!config.shell, + env: config.env || undefined + } +} + +function stateString(state: State): string { + switch (state) { + case State.Running: + return 'running' + case State.Starting: + return 'starting' + case State.Stopped: + return 'stopped' + default: + return 'unknown' + } +} + +export default new ServiceManager() diff --git a/sources_non_forked/coc.nvim/src/snippets/eval.ts b/sources_non_forked/coc.nvim/src/snippets/eval.ts new file mode 100644 index 00000000..389f303d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/eval.ts @@ -0,0 +1,165 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Range } from '@chemzqm/neovim/lib/types' +import { exec } from 'child_process' +import { promisify } from 'util' +export type EvalKind = 'vim' | 'python' | 'shell' +const logger = require('../util/logger')('snippets-eval') +const isVim = process.env.VIM_NODE_RPC == '1' + +export interface UltiSnippetContext { + /** + * line on insert + */ + line: string + /** + * Range to replace, start.line should equal end.line + */ + range: Range + /** + * Context python code. + */ + context?: string + /** + * Regex trigger (python code) + */ + regex?: string + /** + * Avoid python code eval when is true. + */ + noPython?: boolean +} + +/** + * Eval code for code placeholder. + */ +export async function evalCode(nvim: Neovim, kind: EvalKind, code: string, curr = ''): Promise { + if (kind == 'vim') { + let res = await nvim.eval(code) + return res.toString() + } + + if (kind == 'shell') { + let res = await promisify(exec)(code) + return res.stdout.replace(/\s*$/, '') || res.stderr + } + + let lines = [`snip._reset("${escapeString(curr)}")`] + lines.push(...code.split(/\r?\n/).map(line => line.replace(/\t/g, ' '))) + await executePythonCode(nvim, lines) + return await nvim.call(`pyxeval`, 'str(snip.rv)') as string +} + +export function prepareMatchCode(snip: UltiSnippetContext): string { + let { range, regex, line } = snip + let pyCodes: string[] = [] + if (regex && range != null) { + let trigger = line.slice(range.start.character, range.end.character) + pyCodes.push(`pattern = re.compile("${escapeString(regex)}")`) + pyCodes.push(`match = pattern.search("${escapeString(trigger)}")`) + } else { + pyCodes.push(`match = None`) + } + return pyCodes.join('\n') +} + +export function preparePythonCodes(snip: UltiSnippetContext): string[] { + let { range, context, line } = snip + let pyCodes: string[] = [ + 'import re, os, vim, string, random', + `path = vim.eval('expand("%:p")') or ""`, + `fn = os.path.basename(path)`, + ] + if (context) { + pyCodes.push(`snip = ContextSnippet()`) + pyCodes.push(`context = ${context}`) + } else { + pyCodes.push(`context = True`) + } + let start = `(${range.start.line},${Buffer.byteLength(line.slice(0, range.start.character))})` + let end = `(${range.start.line},${Buffer.byteLength(line.slice(0, range.end.character))})` + let indent = line.match(/^\s*/)[0] + pyCodes.push(`snip = SnippetUtil("${escapeString(indent)}", ${start}, ${end}, context)`) + return pyCodes +} + +export async function executePythonCode(nvim: Neovim, codes: string[]) { + try { + await nvim.command(`pyx ${addPythonTryCatch(codes.join('\n'))}`) + } catch (e) { + let err = new Error(e instanceof Error ? e.message : e.toString()) + err.stack = `Error on execute python code:\n${codes.join('\n')}\n` + (e instanceof Error ? e.stack : e) + throw err + } +} + +export function getVariablesCode(values: { [index: number]: string }): string { + let keys = Object.keys(values) + let maxIndex = keys.length ? Math.max.apply(null, keys.map(v => Number(v))) : 0 + let vals = (new Array(maxIndex)).fill('""') + for (let [idx, val] of Object.entries(values)) { + vals[idx] = `"${escapeString(val)}"` + } + return `t = (${vals.join(',')},)` +} + +/** + * vim8 doesn't throw any python error with :py command + * we have to use g:errmsg since v:errmsg can't be changed in python script. + */ +export function addPythonTryCatch(code: string, force = false): string { + if (!isVim && force === false) return code + let lines = [ + 'import traceback, vim', + `vim.vars['errmsg'] = ''`, + 'try:', + ] + lines.push(...code.split('\n').map(line => ' ' + line)) + lines.push('except Exception as e:') + lines.push(` vim.vars['errmsg'] = traceback.format_exc()`) + return lines.join('\n') +} + +function escapeString(input: string): string { + return input + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\t/g, '\\t') + .replace(/\n/g, '\\n') +} + +const stringStartRe = /\\A/ +const conditionRe = /\(\?\(\w+\).+\|/ +const commentRe = /\(\?#.*?\)/ +const namedCaptureRe = /\(\?P<\w+>.*?\)/ +const namedReferenceRe = /\(\?P=(\w+)\)/ +const regex = new RegExp(`${commentRe.source}|${stringStartRe.source}|${namedCaptureRe.source}|${namedReferenceRe.source}`, 'g') + +/** + * Convert python regex to javascript regex, + * throw error when unsupported pattern found + */ +export function convertRegex(str: string): string { + if (str.indexOf('\\z') !== -1) { + throw new Error('pattern \\z not supported') + } + if (str.indexOf('(?s)') !== -1) { + throw new Error('pattern (?s) not supported') + } + if (str.indexOf('(?x)') !== -1) { + throw new Error('pattern (?x) not supported') + } + if (str.indexOf('\n') !== -1) { + throw new Error('pattern \\n not supported') + } + if (conditionRe.test(str)) { + throw new Error('pattern (?id/name)yes-pattern|no-pattern not supported') + } + return str.replace(regex, (match, p1) => { + if (match == '\\A') return '^' + if (match.startsWith('(?#')) return '' + if (match.startsWith('(?P<')) return '(?' + match.slice(3) + if (match.startsWith('(?P=')) return `\\k<${p1}>` + return '' + }) +} diff --git a/sources_non_forked/coc.nvim/src/snippets/manager.ts b/sources_non_forked/coc.nvim/src/snippets/manager.ts new file mode 100644 index 00000000..99cc094a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/manager.ts @@ -0,0 +1,208 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, InsertTextMode, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import events from '../events' +import { StatusBarItem } from '../model/status' +import { UltiSnippetOption } from '../types' +import { deepClone } from '../util/object' +import { emptyRange, rangeInRange, rangeOverlap } from '../util/position' +import window from '../window' +import workspace from '../workspace' +import { UltiSnippetContext } from './eval' +import { SnippetSession } from './session' +import { normalizeSnippetString, shouldFormat } from './snippet' +import { SnippetString } from './string' +const logger = require('../util/logger')('snippets-manager') + +export class SnippetManager { + private sessionMap: Map = new Map() + private disposables: Disposable[] = [] + private statusItem: StatusBarItem + private highlight: boolean + private preferComplete: boolean + + constructor() { + events.on('InsertCharPre', () => { + // avoid update session when pumvisible + // Update may cause completion unexpected terminated. + this.session?.cancel() + }, null, this.disposables) + window.onDidChangeActiveTextEditor(e => { + if (!this.statusItem) return + let session = this.getSession(e.document.bufnr) + if (session) { + this.statusItem.show() + } else { + this.statusItem.hide() + } + }, null, this.disposables) + events.on('InsertEnter', async bufnr => { + let session = this.getSession(bufnr) + if (session) await session.checkPosition() + }, null, this.disposables) + workspace.onDidCloseTextDocument(e => { + let session = this.getSession(e.bufnr) + if (session) session.deactivate() + }, null, this.disposables) + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('suggest') || e.affectsConfiguration('coc.preferences')) { + this.init() + } + }, null, this.disposables) + } + + private get nvim(): Neovim { + return workspace.nvim + } + + public init(): void { + if (!this.statusItem) this.statusItem = window.createStatusBarItem(0) + let config = workspace.getConfiguration('coc.preferences') + this.statusItem.text = config.get('snippetStatusText', 'SNIP') + this.highlight = config.get('snippetHighlight', false) + let suggest = workspace.getConfiguration('suggest') + this.preferComplete = suggest.get('preferCompleteThanJumpPlaceholder', false) + } + + /** + * Insert snippet at current cursor position + */ + public async insertSnippet(snippet: string | SnippetString, select = true, range?: Range, insertTextMode?: InsertTextMode, ultisnip?: UltiSnippetOption): Promise { + let { bufnr } = workspace + let doc = workspace.getAttachedDocument(bufnr) + if (range && !rangeInRange(range, Range.create(0, 0, doc.lineCount + 1, 0))) { + throw new Error(`Unable to insert snippet, invalid range.`) + } + let context: UltiSnippetContext + if (events.pumvisible) this.nvim.call('coc#_cancel', [], true) + if (!range) { + let pos = await window.getCursorPosition() + range = Range.create(pos, pos) + } + const currentLine = doc.getline(range.start.line) + const snippetStr = SnippetString.isSnippetString(snippet) ? snippet.value : snippet + const inserted = await this.normalizeInsertText(doc.uri, snippetStr, currentLine, insertTextMode) + let session = this.getSession(bufnr) + if (session) session.cancel() + if (ultisnip != null) { + context = Object.assign({ range: deepClone(range), line: currentLine }, ultisnip) + if (!emptyRange(range) && inserted.includes('`!p')) { + // same behavior as Ultisnips + this.nvim.call('coc#cursor#move_to', [range.start.line, range.start.character], true) + await doc.applyEdits([{ range, newText: '' }]) + range.end = Position.create(range.start.line, range.start.character) + } + } + if (session) { + await session.forceSynchronize() + // current session could be canceled on synchronize. + session = this.getSession(bufnr) + } else { + await doc.patchChange(true) + } + if (!session) { + session = new SnippetSession(this.nvim, doc, this.highlight, this.preferComplete) + session.onCancel(() => { + this.sessionMap.delete(bufnr) + this.statusItem.hide() + }) + } + let isActive = await session.start(inserted, range, select, context) + if (isActive) { + this.statusItem.show() + this.sessionMap.set(bufnr, session) + } else { + this.statusItem.hide() + this.sessionMap.delete(bufnr) + } + return isActive + } + + public async selectCurrentPlaceholder(triggerAutocmd = true): Promise { + let { session } = this + if (session) return await session.selectCurrentPlaceholder(triggerAutocmd) + } + + public async nextPlaceholder(): Promise { + let { session } = this + if (session) { + await session.nextPlaceholder() + } else { + this.nvim.call('coc#snippet#disable', [], true) + this.statusItem.hide() + } + return '' + } + + public async previousPlaceholder(): Promise { + let { session } = this + if (session) { + await session.previousPlaceholder() + } else { + this.nvim.call('coc#snippet#disable', [], true) + this.statusItem.hide() + } + return '' + } + + public cancel(): void { + let session = this.getSession(workspace.bufnr) + if (session) return session.deactivate() + this.nvim.call('coc#snippet#disable', [], true) + if (this.statusItem) this.statusItem.hide() + } + + public get session(): SnippetSession { + return this.getSession(workspace.bufnr) + } + + public getSession(bufnr: number): SnippetSession { + return this.sessionMap.get(bufnr) + } + + public jumpable(): boolean { + let { session } = this + if (!session) return false + return session.placeholder != null && session.placeholder.index != 0 + } + + public async editsInsideSnippet(edits: TextEdit[]): Promise { + let session = this.getSession(workspace.bufnr) + if (!session || !session.snippet) return false + await session.forceSynchronize() + let range = session.snippet.range + if (edits.some(e => rangeOverlap(e.range, range))) { + return true + } + return false + } + + public async resolveSnippet(snippetString: string, ultisnip?: UltiSnippetOption): Promise { + if (ultisnip) { + let session = this.getSession(workspace.bufnr) + ultisnip.noPython = session != null && session.snippet.hasPython + } + return await SnippetSession.resolveSnippet(this.nvim, snippetString, ultisnip) + } + + public async normalizeInsertText(uri: string, snippetString: string, currentLine: string, insertTextMode: InsertTextMode): Promise { + let inserted = '' + if (insertTextMode === InsertTextMode.asIs || !shouldFormat(snippetString)) { + inserted = snippetString + } else { + const currentIndent = currentLine.match(/^\s*/)[0] + const formatOptions = window.activeTextEditor ? window.activeTextEditor.options : await workspace.getFormatOptions(uri) + inserted = normalizeSnippetString(snippetString, currentIndent, formatOptions) + } + return inserted + } + + public dispose(): void { + this.cancel() + for (let d of this.disposables) { + d.dispose() + } + } +} + +export default new SnippetManager() diff --git a/sources_non_forked/coc.nvim/src/snippets/parser.ts b/sources_non_forked/coc.nvim/src/snippets/parser.ts new file mode 100644 index 00000000..270db562 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/parser.ts @@ -0,0 +1,1776 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Neovim } from '@chemzqm/neovim' +import unidecode from 'unidecode' +import { groupBy } from '../util/array' +import { CharCode } from '../util/charCode' +import { getCharIndexes } from '../util/string' +import { convertRegex, evalCode, EvalKind, executePythonCode, getVariablesCode, prepareMatchCode, UltiSnippetContext } from './eval' +const logger = require('../util/logger')('snippets-parser') + +const knownRegexOptions = ['d', 'g', 'i', 'm', 's', 'u', 'y'] +export const enum TokenType { + Dollar, + Colon, + Comma, + CurlyOpen, + CurlyClose, + Backslash, + Forwardslash, + Pipe, + Int, + VariableName, + Format, + Plus, + Dash, + QuestionMark, + EOF, + OpenParen, + CloseParen, + BackTick, + ExclamationMark, +} + +export interface Token { + type: TokenType + pos: number + len: number +} + +export class Scanner { + + private static _table: { [ch: number]: TokenType } = { + [CharCode.DollarSign]: TokenType.Dollar, + [CharCode.Colon]: TokenType.Colon, + [CharCode.Comma]: TokenType.Comma, + [CharCode.OpenCurlyBrace]: TokenType.CurlyOpen, + [CharCode.CloseCurlyBrace]: TokenType.CurlyClose, + [CharCode.Backslash]: TokenType.Backslash, + [CharCode.Slash]: TokenType.Forwardslash, + [CharCode.Pipe]: TokenType.Pipe, + [CharCode.Plus]: TokenType.Plus, + [CharCode.Dash]: TokenType.Dash, + [CharCode.QuestionMark]: TokenType.QuestionMark, + [CharCode.OpenParen]: TokenType.OpenParen, + [CharCode.CloseParen]: TokenType.CloseParen, + [CharCode.BackTick]: TokenType.BackTick, + [CharCode.ExclamationMark]: TokenType.ExclamationMark, + } + + public static isDigitCharacter(ch: number): boolean { + return ch >= CharCode.Digit0 && ch <= CharCode.Digit9 + } + + public static isVariableCharacter(ch: number): boolean { + return ch === CharCode.Underline + || (ch >= CharCode.a && ch <= CharCode.z) + || (ch >= CharCode.A && ch <= CharCode.Z) + } + + public value: string + public pos: number + + constructor() { + this.text('') + } + + public text(value: string): void { + this.value = value + this.pos = 0 + } + + public tokenText(token: Token): string { + return this.value.substr(token.pos, token.len) + } + + public next(): Token { + + if (this.pos >= this.value.length) { + return { type: TokenType.EOF, pos: this.pos, len: 0 } + } + + let pos = this.pos + let len = 0 + let ch = this.value.charCodeAt(pos) + let type: TokenType + + // static types + type = Scanner._table[ch] + if (typeof type === 'number') { + this.pos += 1 + return { type, pos, len: 1 } + } + + // number + if (Scanner.isDigitCharacter(ch)) { + type = TokenType.Int + do { + len += 1 + ch = this.value.charCodeAt(pos + len) + } while (Scanner.isDigitCharacter(ch)) + + this.pos += len + return { type, pos, len } + } + + // variable name + if (Scanner.isVariableCharacter(ch)) { + type = TokenType.VariableName + do { + ch = this.value.charCodeAt(pos + (++len)) + } while (Scanner.isVariableCharacter(ch) || Scanner.isDigitCharacter(ch)) + + this.pos += len + return { type, pos, len } + } + + // format + type = TokenType.Format + do { + len += 1 + ch = this.value.charCodeAt(pos + len) + } while ( + !isNaN(ch) + && typeof Scanner._table[ch] === 'undefined' // not static token + && !Scanner.isDigitCharacter(ch) // not number + && !Scanner.isVariableCharacter(ch) // not variable + ) + + this.pos += len + return { type, pos, len } + } +} + +export abstract class Marker { + + public readonly _markerBrand: any + + public parent: Marker + protected _children: Marker[] = [] + + public appendChild(child: Marker): this { + if (child instanceof Text && this._children[this._children.length - 1] instanceof Text) { + // this and previous child are text -> merge them + (this._children[this._children.length - 1] as Text).value += child.value + } else { + // normal adoption of child + child.parent = this + this._children.push(child) + } + return this + } + + public setOnlyChild(child: Marker): void { + child.parent = this + this._children = [child] + } + + public replaceChildren(children: Marker[]): void { + for (const child of children) { + child.parent = this + } + this._children = children + } + + public get children(): Marker[] { + return this._children + } + + public get snippet(): TextmateSnippet | undefined { + // eslint-disable-next-line @typescript-eslint/no-this-alias + let candidate: Marker = this + // eslint-disable-next-line no-constant-condition + while (true) { + if (!candidate) { + return undefined + } + if (candidate instanceof TextmateSnippet) { + return candidate + } + candidate = candidate.parent + } + } + + public toString(): string { + return this.children.reduce((prev, cur) => prev + cur.toString(), '') + } + + public abstract toTextmateString(): string + + public len(): number { + return 0 + } + + public abstract clone(): Marker +} + +export class Text extends Marker { + + public static escape(value: string): string { + return value.replace(/\$|}|\\/g, '\\$&') + } + + constructor(public value: string) { + super() + } + public toString(): string { + return this.value + } + + public toTextmateString(): string { + return Text.escape(this.value) + } + public len(): number { + return this.value.length + } + public clone(): Text { + return new Text(this.value) + } +} + +export class CodeBlock extends Marker { + + private _value = '' + private _related: number[] = [] + + constructor(public code: string, public readonly kind: EvalKind, value?: string) { + super() + if (kind === 'python') { + let { _related } = this + let arr + let re = /\bt\[(\d+)\]/g + // eslint-disable-next-line no-constant-condition + while (true) { + arr = re.exec(code) + if (arr == null) break + let n = parseInt(arr[1], 10) + if (!_related.includes(n)) _related.push(n) + } + } + if (value !== undefined) this._value = value + } + + public get related(): number[] { + return this._related + } + + public update(map: Map): void { + if (this.kind !== 'python') return + let related: Set = new Set() + this.code = this.code.replace(/\bt\[(\d+)\]/g, (_, p1) => { + let idx = Number(p1) + let id = map.has(idx) ? map.get(idx) : idx + related.add(id) + return `t[${id}]` + }) + this._related = Array.from(related) + } + + public get index(): number | undefined { + if (this.parent instanceof Placeholder) { + return this.parent.index + } + return undefined + } + + public async resolve(nvim: Neovim): Promise { + if (!this.code.length) return + let res = await evalCode(nvim, this.kind, this.code, this._value) + if (res != null) this._value = res + } + + public len(): number { + return this._value.length + } + + public toString(): string { + return this._value + } + + public get value(): string { + return this._value + } + + public toTextmateString(): string { + let t = '' + if (this.kind == 'python') { + t = '!p ' + } else if (this.kind == 'shell') { + t = '' + } else if (this.kind == 'vim') { + t = '!v ' + } + return '`' + t + (this.code) + '`' + } + + public clone(): CodeBlock { + return new CodeBlock(this.code, this.kind, this.value) + } +} + +export abstract class TransformableMarker extends Marker { + public transform: Transform +} + +export class Placeholder extends TransformableMarker { + public primary = false + + constructor(public index: number) { + super() + } + + public get isFinalTabstop(): boolean { + return this.index === 0 + } + + public get choice(): Choice | undefined { + return this._children.length === 1 && this._children[0] instanceof Choice + ? this._children[0] as Choice + : undefined + } + + public toTextmateString(): string { + let transformString = '' + if (this.transform) { + transformString = this.transform.toTextmateString() + } + if (this.children.length === 0 && !this.transform) { + return `$${this.index}` + } else if (this.children.length === 0) { + return `\${${this.index}${transformString}}` + } else if (this.choice) { + return `\${${this.index}|${this.choice.toTextmateString()}|${transformString}}` + } else { + return `\${${this.index}:${this.children.map(child => child.toTextmateString()).join('')}${transformString}}` + } + } + + public clone(): Placeholder { + let ret = new Placeholder(this.index) + if (this.transform) { + ret.transform = this.transform.clone() + } + ret._children = this.children.map(child => child.clone()) + return ret + } +} + +export class Choice extends Marker { + + public readonly options: Text[] = [] + + public appendChild(marker: Marker): this { + if (marker instanceof Text) { + marker.parent = this + this.options.push(marker) + } + return this + } + + public toString(): string { + return this.options[0].value + } + + public toTextmateString(): string { + return this.options + .map(option => option.value.replace(/\||,/g, '\\$&')) + .join(',') + } + + public len(): number { + return this.options[0].len() + } + + public clone(): Choice { + let ret = new Choice() + for (let opt of this.options) { + ret.appendChild(opt as any) + } + return ret + } +} + +export class Transform extends Marker { + + public regexp: RegExp + public ascii = false + public ultisnip = false + + public resolve(value: string): string { + let didMatch = false + let ret = value.replace(this.regexp, (...args) => { + didMatch = true + return this._replace(args.slice(0, -2)) + }) + // when the regex didn't match and when the transform has + // else branches, then run those + if (!didMatch && this._children.some(child => child instanceof FormatString && Boolean(child.elseValue))) { + ret = this._replace([]) + } + return ret + } + + private _replace(groups: string[]): string { + let ret = '' + let backslashIndexes: number[] = [] + for (const marker of this._children) { + if (marker instanceof FormatString) { + let val = marker.resolve(groups[marker.index] || '') + if (this.ultisnip && val.indexOf('\\') !== -1) { + let s = ret.length + backslashIndexes.push(...getCharIndexes(val, '\\').map(i => i + s)) + } + ret += val + } else if (marker instanceof ConditionString) { + ret += marker.resolve(groups[marker.index]) + } else { + ret += marker.toString() + } + } + if (this.ascii) ret = unidecode(ret) + return this.ultisnip ? transformEscapes(ret, backslashIndexes) : ret + } + + public toString(): string { + return '' + } + + public toTextmateString(): string { + return `/${this.regexp.source}/${this.children.map(c => c.toTextmateString())}/${(this.regexp.ignoreCase ? 'i' : '') + (this.regexp.global ? 'g' : '')}` + } + + public clone(): Transform { + let ret = new Transform() + ret.regexp = new RegExp(this.regexp.source, '' + (this.regexp.ignoreCase ? 'i' : '') + (this.regexp.global ? 'g' : '')) + ret._children = this.children.map(child => child.clone()) + return ret + } + +} + +export class ConditionString extends Marker { + constructor( + public readonly index: number, + public readonly ifValue: string, + public readonly elseValue: string, + ) { + super() + } + + public resolve(value: string): string { + if (value) return this.ifValue + return this.elseValue + } + + public toTextmateString(): string { + return '(?' + this.index + ':' + this.ifValue + (this.elseValue ? ':' + this.elseValue : '') + ')' + } + + public clone(): ConditionString { + return new ConditionString(this.index, this.ifValue, this.elseValue) + } +} + +export class FormatString extends Marker { + + constructor( + public readonly index: number, + public readonly shorthandName?: string, + public readonly ifValue?: string, + public readonly elseValue?: string, + ) { + super() + } + + public resolve(value: string): string { + if (this.shorthandName === 'upcase') { + return !value ? '' : value.toLocaleUpperCase() + } else if (this.shorthandName === 'downcase') { + return !value ? '' : value.toLocaleLowerCase() + } else if (this.shorthandName === 'capitalize') { + return !value ? '' : (value[0].toLocaleUpperCase() + value.substr(1)) + } else if (this.shorthandName === 'pascalcase') { + return !value ? '' : this._toPascalCase(value) + } else if (Boolean(value) && typeof this.ifValue === 'string') { + return this.ifValue + } else if (!value && typeof this.elseValue === 'string') { + return this.elseValue + } else { + return value || '' + } + } + + private _toPascalCase(value: string): string { + const match = value.match(/[a-z]+/gi) + if (!match) { + return value + } + return match.map(word => word.charAt(0).toUpperCase() + + word.substr(1).toLowerCase()) + .join('') + } + + public toTextmateString(): string { + let value = '${' + value += this.index + if (this.shorthandName) { + value += `:/${this.shorthandName}` + + } else if (this.ifValue && this.elseValue) { + value += `:?${this.ifValue}:${this.elseValue}` + } else if (this.ifValue) { + value += `:+${this.ifValue}` + } else if (this.elseValue) { + value += `:-${this.elseValue}` + } + value += '}' + return value + } + + public clone(): FormatString { + let ret = new FormatString(this.index, this.shorthandName, this.ifValue, this.elseValue) + return ret + } +} + +export class Variable extends TransformableMarker { + private _resolved = false + + constructor(public name: string, resolved?: boolean) { + super() + if (typeof resolved === 'boolean') { + this._resolved = resolved + } + } + + public get resolved(): boolean { + return this._resolved + } + + public async resolve(resolver: VariableResolver): Promise { + let value = await resolver.resolve(this) + this._resolved = true + if (value && value.includes('\n')) { + // get indent from previous texts + let indent = '' + this.snippet.walk(m => { + if (m == this) { + return false + } + if (m instanceof Text) { + let lines = m.toString().split(/\r?\n/) + indent = lines[lines.length - 1].match(/^\s*/)[0] + } + return true + }) + let lines = value.split('\n') + let indents = lines.filter(s => s.length > 0).map(s => s.match(/^\s*/)[0]) + let minIndent = indents.length == 0 ? '' : + indents.reduce((p, c) => p.length < c.length ? p : c) + let newLines = lines.map((s, i) => i == 0 || s.length == 0 || !s.startsWith(minIndent) ? s : + indent + s.slice(minIndent.length)) + value = newLines.join('\n') + } + if (this.transform) { + value = this.transform.resolve(value || '') + } + if (value !== undefined) { + this._children = [new Text(value) as any] + return true + } + return false + } + + public toTextmateString(): string { + let transformString = '' + if (this.transform) { + transformString = this.transform.toTextmateString() + } + if (this.children.length === 0) { + return `\${${this.name}${transformString}}` + } else { + return `\${${this.name}:${this.children.map(child => child.toTextmateString()).join('')}${transformString}}` + } + } + + public clone(): Variable { + const ret = new Variable(this.name, this.resolved) + if (this.transform) { + ret.transform = this.transform.clone() + } + ret._children = this.children.map(child => child.clone()) + return ret + } +} + +export interface VariableResolver { + resolve(variable: Variable): Promise +} + +export interface PlaceholderInfo { + placeholders: Placeholder[] + variables: Variable[] + pyBlocks: CodeBlock[] + otherBlocks: CodeBlock[] +} + +function walk(marker: Marker[], visitor: (marker: Marker) => boolean): void { + const stack = [...marker] + while (stack.length > 0) { + const marker = stack.shift() + const recurse = visitor(marker) + if (!recurse) { + break + } + stack.unshift(...marker.children) + } +} + +export class TextmateSnippet extends Marker { + + public readonly ultisnip: boolean + private _placeholders?: PlaceholderInfo + private _values?: { [index: number]: string } + constructor(ultisnip?: boolean) { + super() + this.ultisnip = ultisnip === true + } + + public get hasPython(): boolean { + if (!this.ultisnip) return false + return this.pyBlocks.length > 0 + } + + public get hasCodeBlock(): boolean { + if (!this.ultisnip) return false + let { pyBlocks, otherBlocks } = this + return pyBlocks.length > 0 || otherBlocks.length > 0 + } + + /** + * Values for each placeholder index + */ + public get values(): { [index: number]: string } { + if (this._values) return this._values + let values: { [index: number]: string } = {} + let maxIndexNumber = 0 + this.placeholders.forEach(c => { + maxIndexNumber = Math.max(c.index, maxIndexNumber) + if (c.transform != null) return + if (c.primary || values[c.index] === undefined) values[c.index] = c.toString() + }) + for (let i = 0; i <= maxIndexNumber; i++) { + if (values[i] === undefined) values[i] = '' + } + this._values = values + return values + } + + public get orderedPyIndexBlocks(): CodeBlock[] { + let res: CodeBlock[] = [] + let filtered = this.pyBlocks.filter(o => typeof o.index === 'number') + if (filtered.length == 0) return res + let allIndexes = filtered.map(o => o.index) + let usedIndexes: number[] = [] + const checkBlock = (b: CodeBlock): boolean => { + let { related } = b + if (related.length == 0 + || related.every(idx => !allIndexes.includes(idx) || usedIndexes.includes(idx))) { + usedIndexes.push(b.index) + res.push(b) + return true + } + return false + } + while (filtered.length > 0) { + let c = false + for (let b of filtered) { + if (checkBlock(b)) { + c = true + } + } + if (!c) { + // recuisive dependencies detected + break + } + filtered = filtered.filter(o => !usedIndexes.includes(o.index)) + } + return res + } + + public async evalCodeBlocks(nvim: Neovim, prepareCodes: string[]): Promise { + let { pyBlocks, otherBlocks } = this + // update none python blocks + await Promise.all(otherBlocks.map(block => { + let pre = block.value + return block.resolve(nvim).then(() => { + if (block.parent instanceof Placeholder && pre !== block.value) { + // update placeholder with same index + this.onPlaceholderUpdate(block.parent) + } + }) + })) + if (pyBlocks.length) { + // run all python code by sequence + const variableCode = getVariablesCode(this.values) + await executePythonCode(nvim, [...prepareCodes, variableCode]) + for (let block of pyBlocks) { + let pre = block.value + await block.resolve(nvim) + if (pre === block.value) continue + if (block.parent instanceof Placeholder) { + // update placeholder with same index + this.onPlaceholderUpdate(block.parent) + await executePythonCode(nvim, [getVariablesCode(this.values)]) + } + } + for (let block of this.orderedPyIndexBlocks) { + await this.updatePyIndexBlock(nvim, block) + } + // update normal python block with related. + let filtered = pyBlocks.filter(o => o.index === undefined && o.related.length > 0) + for (let block of filtered) { + await block.resolve(nvim) + } + } + } + + /** + * Update python blocks after user change Placeholder with index + */ + public async updatePythonCodes(nvim: Neovim, marker: Marker): Promise { + let index: number | undefined + if (marker instanceof Placeholder) { + index = marker.index + } else { + while (marker.parent) { + if (marker instanceof Placeholder) { + index = marker.index + break + } + marker = marker.parent + } + } + if (index === undefined) return + // update related placeholders + let blocks = this.getDependentPyIndexBlocks(index) + await executePythonCode(nvim, [getVariablesCode(this.values)]) + for (let block of blocks) { + await this.updatePyIndexBlock(nvim, block) + } + // update normal py codes. + let filtered = this.pyBlocks.filter(o => o.index === undefined && o.related.length > 0) + for (let block of filtered) { + await block.resolve(nvim) + } + } + + private getDependentPyIndexBlocks(index: number): CodeBlock[] { + const res: CodeBlock[] = [] + const taken: number[] = [] + let filtered = this.pyBlocks.filter(o => typeof o.index === 'number') + const search = (idx: number) => { + let blocks = filtered.filter(o => !taken.includes(o.index) && o.related.includes(idx)) + if (blocks.length > 0) { + res.push(...blocks) + blocks.forEach(b => { + search(b.index) + }) + } + } + search(index) + return res + } + + /** + * Update single index block + */ + private async updatePyIndexBlock(nvim: Neovim, block: CodeBlock): Promise { + let pre = block.value + await block.resolve(nvim) + if (pre === block.value) return + if (block.parent instanceof Placeholder) { + this.onPlaceholderUpdate(block.parent) + } + await executePythonCode(nvim, [getVariablesCode(this.values)]) + } + + public get placeholderInfo(): PlaceholderInfo { + if (!this._placeholders) { + const variables = [] + const pyBlocks: CodeBlock[] = [] + const otherBlocks: CodeBlock[] = [] + // fill in placeholders + let placeholders: Placeholder[] = [] + this.walk(candidate => { + if (candidate instanceof Placeholder) { + placeholders.push(candidate) + } else if (candidate instanceof Variable) { + let first = candidate.name.charCodeAt(0) + // not jumpover for uppercase variable. + if (first < 65 || first > 90) { + variables.push(candidate) + } + } else if (candidate instanceof CodeBlock) { + if (candidate.kind === 'python') { + pyBlocks.push(candidate) + } else { + otherBlocks.push(candidate) + } + } + return true + }) + this._placeholders = { placeholders, pyBlocks, otherBlocks, variables } + } + return this._placeholders + } + + public get variables(): Variable[] { + return this.placeholderInfo.variables + } + + public get placeholders(): Placeholder[] { + return this.placeholderInfo.placeholders + } + + public get pyBlocks(): CodeBlock[] { + return this.placeholderInfo.pyBlocks + } + + public get otherBlocks(): CodeBlock[] { + return this.placeholderInfo.otherBlocks + } + + public get maxIndexNumber(): number { + let { placeholders } = this + return placeholders.reduce((curr, p) => Math.max(curr, p.index), 0) + } + + public get first(): Placeholder | Variable { + let { placeholders, variables } = this + let [normals, finals] = groupBy(placeholders.filter(p => !p.transform), v => v.index !== 0) + if (normals.length) { + let minIndex = Math.min.apply(null, normals.map(o => o.index)) + let arr = normals.filter(v => v.index == minIndex) + return arr.find(p => p.primary) ?? arr[0] + } + if (variables.length) return variables[0] + return finals.find(o => o.primary) ?? finals[0] + } + + public insertSnippet(snippet: string, marker: Placeholder | Variable, parts: [string, string], ultisnip?: UltiSnippetContext): Placeholder | Variable { + let index = marker instanceof Placeholder ? marker.index : this.maxIndexNumber + 1 + let [before, after] = parts + let matchCode = ultisnip ? prepareMatchCode(ultisnip) : undefined + let nested = new SnippetParser(!!ultisnip, matchCode).parse(snippet, true) + let maxIndexAdded = nested.maxIndexNumber + 1 + let changed: Map = new Map() + for (let p of nested.placeholders) { + let idx = p.index + if (p.isFinalTabstop) { + p.index = maxIndexAdded + index + } else { + p.index = p.index + index + } + changed.set(idx, p.index) + } + if (ultisnip) { + nested.pyBlocks.forEach(b => { + b.update(changed) + }) + } + let map: Map = new Map() + this.walk(m => { + if (m instanceof Placeholder && m.index > index) { + let idx = m.index + m.index = m.index + maxIndexAdded + map.set(idx, m.index) + } + return true + }) + if (this.hasPython) { + this.walk(m => { + if (m instanceof CodeBlock) { + m.update(map) + } + return true + }) + } + const select = nested.first + let children = nested.children.slice() + if (before) children.unshift(new Text(before)) + if (after) children.push(new Text(after)) + this.replace(marker, children) + return select + } + + public async update(nvim: Neovim, marker: Placeholder | Variable, value: string): Promise { + this.resetMarker(marker, value) + if (this.hasPython) { + await this.updatePythonCodes(nvim, marker) + } + } + + public deleteText(offset: number, length: number): boolean { + let pos = 0 + let marker: Text | undefined + let end = offset + length + let start = 0 + this.walk(candidate => { + let len = candidate.len() + if (candidate instanceof Text && offset >= pos && pos + len >= end) { + marker = candidate + start = offset - pos + return false + } + pos += len + return true + }) + if (!marker) return false + let parent = marker.parent + let text = marker.value + let value = text.slice(0, start) + text.slice(start + length) + let children = parent.children.slice() + let idx = children.indexOf(marker) + children.splice(idx, 1, new Text(value)) + parent.replaceChildren(children) + return true + } + + public resetMarker(marker: Placeholder | Variable, val: string): void { + let markers: (Placeholder | Variable)[] + if (marker instanceof Placeholder) { + markers = this.placeholders.filter(o => o.index == marker.index) + } else { + markers = this.variables.filter(o => o.name == marker.name) + } + for (let p of markers) { + let newText = p.transform ? p.transform.resolve(val) : val + p.setOnlyChild(new Text(newText || '')) + } + this.synchronizeParents(markers) + this.reset() + } + + /** + * Reflact changes for related markers. + */ + public onPlaceholderUpdate(marker: Placeholder | Variable): void { + let val = marker.toString() + let markers: Placeholder[] | Variable[] + if (marker instanceof Placeholder) { + this.values[marker.index] = val + markers = this.placeholders.filter(o => o.index == marker.index) + } else { + markers = this.variables.filter(o => o.name == marker.name) + } + for (let p of markers) { + if (p === marker) continue + let newText = p.transform ? p.transform.resolve(val) : val + p.setOnlyChild(new Text(newText || '')) + } + this.synchronizeParents(markers) + } + + public synchronizeParents(markers: Marker[]): void { + let arr: Placeholder[] = [] + markers.forEach(m => { + let p = m.parent + if (p instanceof Placeholder && !arr.includes(p)) { + arr.push(p) + } + }) + arr.forEach(p => { + this.onPlaceholderUpdate(p) + }) + } + + public offset(marker: Marker): number { + let pos = 0 + let found = false + this.walk(candidate => { + if (candidate === marker) { + found = true + return false + } + pos += candidate.len() + return true + }) + + if (!found) { + return -1 + } + return pos + } + + public fullLen(marker: Marker): number { + let ret = 0 + walk([marker], marker => { + ret += marker.len() + return true + }) + return ret + } + + public getTextBefore(marker: Marker, parent: Placeholder): string { + let res = '' + const calc = (m: Marker): void => { + let p = m.parent + if (!p) return + let s = '' + for (let b of p.children) { + if (b === m) break + s = s + b.toString() + } + res = s + res + if (p == parent) return + calc(p) + } + calc(marker) + return res + } + + public enclosingPlaceholders(placeholder: Placeholder | Variable): Placeholder[] { + let ret: Placeholder[] = [] + let { parent } = placeholder + while (parent) { + if (parent instanceof Placeholder) { + ret.push(parent) + } + parent = parent.parent + } + return ret + } + + public async resolveVariables(resolver: VariableResolver): Promise { + let items: Variable[] = [] + this.walk(candidate => { + if (candidate instanceof Variable && !candidate.resolved) { + items.push(candidate) + } + return true + }) + if (items.length) { + await Promise.all(items.map(o => o.resolve(resolver))) + this.synchronizeParents(items) + } + } + + public appendChild(child: Marker): this { + this.reset() + return super.appendChild(child) + } + + public replace(marker: Marker, children: Marker[]): void { + marker.replaceChildren(children) + if (marker instanceof Placeholder || marker instanceof Variable) { + this.onPlaceholderUpdate(marker) + } + this.reset() + } + + /** + * Used on replace happens. + */ + public reset(): void { + this._placeholders = undefined + this._values = undefined + } + + public toTextmateString(): string { + return this.children.reduce((prev, cur) => prev + cur.toTextmateString(), '') + } + + public clone(): TextmateSnippet { + let ret = new TextmateSnippet(this.ultisnip) + ret._children = this.children.map(child => child.clone()) + return ret + } + + public walk(visitor: (marker: Marker) => boolean): void { + walk(this.children, visitor) + } +} + +export class SnippetParser { + constructor( + private ultisnip?: boolean, + private matchCode?: string + ) { + } + + public static escape(value: string): string { + return value.replace(/\$|}|\\/g, '\\$&') + } + + public static isPlainText(value: string): boolean { + let s = new SnippetParser().parse(value.replace(/\$0$/, ''), false) + return s.children.length == 1 && s.children[0] instanceof Text + } + + private _scanner = new Scanner() + private _token: Token + + public text(value: string): string { + return this.parse(value, false).toString() + } + + public parse(value: string, insertFinalTabstop?: boolean): TextmateSnippet { + + this._scanner.text(value) + this._token = this._scanner.next() + + const snippet = new TextmateSnippet(this.ultisnip) + while (this._parse(snippet)) { + // nothing + } + + // fill in values for placeholders. the first placeholder of an index + // that has a value defines the value for all placeholders with that index + const defaultValues = new Map() + const incompletePlaceholders: Placeholder[] = [] + let complexPlaceholders: Placeholder[] = [] + let hasFinal = false + snippet.walk(marker => { + if (marker instanceof Placeholder) { + if (marker.index == 0) hasFinal = true + if (marker.children.some(o => o instanceof Placeholder)) { + complexPlaceholders.push(marker) + } else if (!defaultValues.has(marker.index) && marker.children.length > 0) { + marker.primary = true + defaultValues.set(marker.index, marker.toString()) + } else { + incompletePlaceholders.push(marker) + } + } + return true + }) + + const complexIndexes = complexPlaceholders.map(p => p.index) + for (const placeholder of incompletePlaceholders) { + // avoid transform and replace since no value exists. + if (defaultValues.has(placeholder.index)) { + let val = defaultValues.get(placeholder.index) + let text = new Text(placeholder.transform ? placeholder.transform.resolve(val) : val) + placeholder.setOnlyChild(text) + } else if (!complexIndexes.includes(placeholder.index)) { + if (placeholder.transform) { + let text = new Text(placeholder.transform.resolve('')) + placeholder.setOnlyChild(text) + } else { + placeholder.primary = true + defaultValues.set(placeholder.index, '') + } + } + } + const resolveComplex = () => { + let resolved: Set = new Set() + for (let p of complexPlaceholders) { + if (p.children.every(o => !(o instanceof Placeholder) || defaultValues.has(o.index))) { + let val = p.toString() + defaultValues.set(p.index, val) + for (let placeholder of incompletePlaceholders.filter(o => o.index == p.index)) { + let text = new Text(placeholder.transform ? placeholder.transform.resolve(val) : val) + placeholder.setOnlyChild(text) + } + resolved.add(p.index) + } + } + complexPlaceholders = complexPlaceholders.filter(p => !resolved.has(p.index)) + if (complexPlaceholders.length == 0 || !resolved.size) return + resolveComplex() + } + resolveComplex() + + if (!hasFinal && insertFinalTabstop) { + // the snippet uses placeholders but has no + // final tabstop defined -> insert at the end + snippet.appendChild(new Placeholder(0)) + } + + return snippet + } + + private _accept(type?: TokenType): boolean + private _accept(type: TokenType | undefined, value: true): string + private _accept(type: TokenType, value?: boolean): boolean | string { + if (type === undefined || this._token.type === type) { + let ret = !value ? true : this._scanner.tokenText(this._token) + this._token = this._scanner.next() + return ret + } + return false + } + + private _backTo(token: Token): false { + this._scanner.pos = token.pos + token.len + this._token = token + return false + } + + private _until(type: TokenType, checkBackSlash = false): false | string { + if (this._token.type === TokenType.EOF) { + return false + } + let start = this._token + let pre: Token + while (this._token.type !== type || (checkBackSlash && pre?.type === TokenType.Backslash)) { + if (checkBackSlash) pre = this._token + this._token = this._scanner.next() + if (this._token.type === TokenType.EOF) { + return false + } + } + let value = this._scanner.value.substring(start.pos, this._token.pos) + this._token = this._scanner.next() + return value + } + + private _parse(marker: Marker): boolean { + return this._parseEscaped(marker) + || this._parseCodeBlock(marker) + || this._parseTabstopOrVariableName(marker) + || this._parseComplexPlaceholder(marker) + || this._parseComplexVariable(marker) + || this._parseAnything(marker) + } + + // \$, \\, \} -> just text + private _parseEscaped(marker: Marker): boolean { + let value: string + // eslint-disable-next-line no-cond-assign + if (value = this._accept(TokenType.Backslash, true)) { + // saw a backslash, append escaped token or that backslash + value = this._accept(TokenType.Dollar, true) + || this._accept(TokenType.CurlyClose, true) + || this._accept(TokenType.Backslash, true) + || (this.ultisnip && this._accept(TokenType.CurlyOpen, true)) + || (this.ultisnip && this._accept(TokenType.BackTick, true)) + || value + + marker.appendChild(new Text(value)) + return true + } + return false + } + + // $foo -> variable, $1 -> tabstop + private _parseTabstopOrVariableName(parent: Marker): boolean { + let value: string + const token = this._token + const match = this._accept(TokenType.Dollar) + && (value = this._accept(TokenType.VariableName, true) || this._accept(TokenType.Int, true)) + + if (!match) { + return this._backTo(token) + } + + parent.appendChild(/^\d+$/.test(value) + ? new Placeholder(Number(value)) + : new Variable(value) + ) + return true + } + + // ${1:}, ${1} -> placeholder + private _parseComplexPlaceholder(parent: Marker): boolean { + let index: string + const token = this._token + const match = this._accept(TokenType.Dollar) + && this._accept(TokenType.CurlyOpen) + && (index = this._accept(TokenType.Int, true)) + + if (!match) { + return this._backTo(token) + } + + const placeholder = new Placeholder(Number(index)) + + if (this._accept(TokenType.Colon)) { + // ${1:} + // eslint-disable-next-line no-constant-condition + while (true) { + + // ...} -> done + if (this._accept(TokenType.CurlyClose)) { + parent.appendChild(placeholder) + return true + } + + if (this._parse(placeholder)) { + continue + } + + // fallback + parent.appendChild(new Text('${' + index + ':')) + placeholder.children.forEach(parent.appendChild, parent) + return true + } + } else if (placeholder.index > 0 && this._accept(TokenType.Pipe)) { + // ${1|one,two,three|} + const choice = new Choice() + + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._parseChoiceElement(choice)) { + + if (this._accept(TokenType.Comma)) { + // opt, -> more + continue + } + + if (this._accept(TokenType.Pipe)) { + placeholder.appendChild(choice) + if (this._accept(TokenType.CurlyClose)) { + // ..|} -> done + parent.appendChild(placeholder) + return true + } + } + } + + this._backTo(token) + return false + } + + } else if (this._accept(TokenType.Forwardslash)) { + // ${1///} + if (this._parseTransform(placeholder)) { + parent.appendChild(placeholder) + return true + } + + this._backTo(token) + return false + + } else if (this._accept(TokenType.CurlyClose)) { + // ${1} + parent.appendChild(placeholder) + return true + + } else { + // ${1 <- missing curly or colon + return this._backTo(token) + } + } + + private _parseChoiceElement(parent: Choice): boolean { + const token = this._token + const values: string[] = [] + + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._token.type === TokenType.Comma || this._token.type === TokenType.Pipe) { + break + } + let value: string + // eslint-disable-next-line no-cond-assign + if (value = this._accept(TokenType.Backslash, true)) { + // \, \|, or \\ + value = this._accept(TokenType.Comma, true) + || this._accept(TokenType.Pipe, true) + || this._accept(TokenType.Backslash, true) + || value + } else { + value = this._accept(undefined, true) + } + if (!value) { + // EOF + this._backTo(token) + return false + } + values.push(value) + } + + if (values.length === 0) { + this._backTo(token) + return false + } + + parent.appendChild(new Text(values.join(''))) + return true + } + + // ${foo:}, ${foo} -> variable + private _parseComplexVariable(parent: Marker): boolean { + let name: string + const token = this._token + const match = this._accept(TokenType.Dollar) + && this._accept(TokenType.CurlyOpen) + && (name = this._accept(TokenType.VariableName, true)) + + if (!match) { + return this._backTo(token) + } + + const variable = new Variable(name) + if (this._accept(TokenType.Colon)) { + // ${foo:} + // eslint-disable-next-line no-constant-condition + while (true) { + + // ...} -> done + if (this._accept(TokenType.CurlyClose)) { + parent.appendChild(variable) + return true + } + + if (this._parse(variable)) { + continue + } + + // fallback + parent.appendChild(new Text('${' + name + ':')) + variable.children.forEach(parent.appendChild, parent) + return true + } + + } else if (this._accept(TokenType.Forwardslash)) { + // ${foo///} + if (this._parseTransform(variable)) { + parent.appendChild(variable) + return true + } + + this._backTo(token) + return false + + } else if (this._accept(TokenType.CurlyClose)) { + // ${foo} + parent.appendChild(variable) + return true + + } else { + // ${foo <- missing curly or colon + return this._backTo(token) + } + } + + private _parseTransform(parent: TransformableMarker): boolean { + // ...//} + + let transform = new Transform() + transform.ultisnip = this.ultisnip === true + let regexValue = '' + let regexOptions = '' + + // (1) /regex + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._accept(TokenType.Forwardslash)) { + break + } + + let escaped: string + // eslint-disable-next-line no-cond-assign + if (escaped = this._accept(TokenType.Backslash, true)) { + escaped = this._accept(TokenType.Forwardslash, true) || escaped + regexValue += escaped + continue + } + + if (this._token.type !== TokenType.EOF) { + regexValue += this._accept(undefined, true) + continue + } + return false + } + + // (2) /format + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._accept(TokenType.Forwardslash)) { + break + } + + let escaped: string + // eslint-disable-next-line no-cond-assign + if (escaped = this._accept(TokenType.Backslash, true)) { + escaped = this._accept(TokenType.Forwardslash, true) || escaped + transform.appendChild(new Text(escaped)) + continue + } + if (this._parseFormatString(transform) || this._parseConditionString(transform) || this._parseAnything(transform)) { + continue + } + return false + } + + let ascii = false + // (3) /option + // eslint-disable-next-line no-constant-condition + while (true) { + if (this._accept(TokenType.CurlyClose)) { + break + } + if (this._token.type !== TokenType.EOF) { + let c = this._accept(undefined, true) + if (c == 'a') { + ascii = true + } else { + if (!knownRegexOptions.includes(c)) { + logger.error(`Unknown regex option: ${c}`) + } + regexOptions += c + } + continue + } + return false + } + + try { + if (ascii) transform.ascii = true + if (this.ultisnip) regexValue = convertRegex(regexValue) + transform.regexp = new RegExp(regexValue, regexOptions) + } catch (e) { + return false + } + + parent.transform = transform + return true + } + + private _parseConditionString(parent: Transform): boolean { + if (!this.ultisnip) return false + const token = this._token + // (?1:foo:bar) + if (!this._accept(TokenType.OpenParen)) { + return false + } + if (!this._accept(TokenType.QuestionMark)) { + this._backTo(token) + return false + } + let index = this._accept(TokenType.Int, true) + if (!index) { + this._backTo(token) + return false + } + if (!this._accept(TokenType.Colon)) { + this._backTo(token) + return false + } + let text = this._until(TokenType.CloseParen, true) + if (text) { + let i = 0 + while (i < text.length) { + let t = text[i] + if (t == ':' && text[i - 1] != '\\') { + break + } + i++ + } + let ifValue = text.slice(0, i) + let elseValue = text.slice(i + 1) + parent.appendChild(new ConditionString(Number(index), ifValue, elseValue)) + return true + } + this._backTo(token) + return false + } + + private _parseFormatString(parent: Transform): boolean { + + const token = this._token + if (!this._accept(TokenType.Dollar)) { + return false + } + + let complex = false + if (this._accept(TokenType.CurlyOpen)) { + complex = true + } + + let index = this._accept(TokenType.Int, true) + + if (!index) { + this._backTo(token) + return false + + } else if (!complex) { + // $1 + parent.appendChild(new FormatString(Number(index))) + return true + + } else if (this._accept(TokenType.CurlyClose)) { + // ${1} + parent.appendChild(new FormatString(Number(index))) + return true + + } else if (!this._accept(TokenType.Colon)) { + this._backTo(token) + return false + } + if (this.ultisnip) { + this._backTo(token) + return false + } + + if (this._accept(TokenType.Forwardslash)) { + // ${1:/upcase} + let shorthand = this._accept(TokenType.VariableName, true) + if (!shorthand || !this._accept(TokenType.CurlyClose)) { + this._backTo(token) + return false + } else { + parent.appendChild(new FormatString(Number(index), shorthand)) + return true + } + + } else if (this._accept(TokenType.Plus)) { + // ${1:+} + let ifValue = this._until(TokenType.CurlyClose) + if (ifValue) { + parent.appendChild(new FormatString(Number(index), undefined, ifValue, undefined)) + return true + } + + } else if (this._accept(TokenType.Dash)) { + // ${2:-} + let elseValue = this._until(TokenType.CurlyClose) + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue)) + return true + } + + } else if (this._accept(TokenType.QuestionMark)) { + // ${2:?:} + let ifValue = this._until(TokenType.Colon) + if (ifValue) { + let elseValue = this._until(TokenType.CurlyClose) + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, ifValue, elseValue)) + return true + } + } + + } else { + let elseValue = this._until(TokenType.CurlyClose) + if (elseValue) { + parent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue)) + return true + } + } + + this._backTo(token) + return false + } + + private _parseCodeBlock(parent: Marker): boolean { + if (!this.ultisnip) return false + const token = this._token + if (!this._accept(TokenType.BackTick)) { + return false + } + let text = this._until(TokenType.BackTick, true) + // `shell code` `!v` `!p` + if (text) { + if (!text.startsWith('!')) { + let marker = new CodeBlock(text.trim(), 'shell') + parent.appendChild(marker) + return true + } + if (text.startsWith('!v')) { + let marker = new CodeBlock(text.slice(2).trim(), 'vim') + parent.appendChild(marker) + return true + } + if (text.startsWith('!p')) { + let code = text.slice(2) + let pre = this.matchCode ? this.matchCode + '\n' : '' + if (code.indexOf('\n') == -1) { + let marker = new CodeBlock(pre + code.trim(), 'python') + parent.appendChild(marker) + } else { + let codes = code.split(/\r?\n/) + codes = codes.filter(s => !/^\s*$/.test(s)) + // format multi line code + let ind = codes[0] ? codes[0].match(/^\s*/)[0] : '' + if (ind.length && codes.every(s => s.startsWith(ind))) { + codes = codes.map(s => s.slice(ind.length)) + } + if (ind == ' ' && codes[0].startsWith(ind)) codes[0] = codes[0].slice(1) + let marker = new CodeBlock(pre + codes.join('\n'), 'python') + parent.appendChild(marker) + } + return true + } + } + this._backTo(token) + return false + } + + private _parseAnything(marker: Marker): boolean { + if (this._token.type !== TokenType.EOF) { + let text = this._scanner.tokenText(this._token) + marker.appendChild(new Text(text)) + this._accept(undefined) + return true + } + return false + } +} + +const escapedCharacters = [':', '(', ')', '{', '}'] +export function transformEscapes(input: string, backslashIndexes = []): string { + let res = '' + let len = input.length + let i = 0 + let toUpper = false + let toLower = false + while (i < len) { + let ch = input[i] + if (ch.charCodeAt(0) === CharCode.Backslash && !backslashIndexes.includes(i)) { + let next = input[i + 1] + if (escapedCharacters.includes(next)) { + i++ + continue + } + if (next == 'u' || next == 'l') { + // Uppercase/Lowercase next letter + let follow = input[i + 2] + if (follow) res = res + (next == 'u' ? follow.toUpperCase() : follow.toLowerCase()) + i = i + 3 + continue + } + if (next == 'U' || next == 'L') { + // Uppercase/Lowercase to \E + if (next == 'U') { + toUpper = true + } else { + toLower = true + } + i = i + 2 + continue + } + if (next == 'E') { + toUpper = false + toLower = false + i = i + 2 + continue + } + if (next == 'n') { + res += '\n' + i = i + 2 + continue + } + if (next == 't') { + res += '\t' + i = i + 2 + continue + } + } + if (toUpper) { + ch = ch.toUpperCase() + } else if (toLower) { + ch = ch.toLowerCase() + } + res += ch + i++ + } + return res +} diff --git a/sources_non_forked/coc.nvim/src/snippets/session.ts b/sources_non_forked/coc.nvim/src/snippets/session.ts new file mode 100644 index 00000000..e7959fd6 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/session.ts @@ -0,0 +1,383 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Emitter, Event, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import events from '../events' +import Document from '../model/document' +import { LinesTextDocument } from '../model/textdocument' +import { TextDocumentContentChange, UltiSnippetOption } from '../types' +import { Mutex } from '../util/mutex' +import { equals } from '../util/object' +import { comparePosition, emptyRange, getEnd, isSingleLine, positionInRange, rangeInRange } from '../util/position' +import { byteLength } from '../util/string' +import window from '../window' +import workspace from '../workspace' +import { UltiSnippetContext } from './eval' +import { Marker, Placeholder } from './parser' +import { checkContentBefore, checkCursor, CocSnippet, CocSnippetPlaceholder, getEndPosition, getParts, reduceTextEdit } from "./snippet" +import { SnippetVariableResolver } from "./variableResolve" +const logger = require('../util/logger')('snippets-session') +const NAME_SPACE = 'snippets' + +interface DocumentChange { + version: number + change: TextDocumentContentChange +} + +export class SnippetSession { + private current: Marker + private textDocument: LinesTextDocument + private tokenSource: CancellationTokenSource + private disposable: Disposable + private mutex = new Mutex() + private _applying = false + private _isActive = false + private _snippet: CocSnippet = null + private _onCancelEvent = new Emitter() + public readonly onCancel: Event = this._onCancelEvent.event + + constructor( + private nvim: Neovim, + public readonly document: Document, + private enableHighlight = false, + private preferComplete = false + ) { + this.disposable = document.onDocumentChange(async e => { + if (this._applying || !this._isActive) return + let changes = e.contentChanges + if (changes.length === 0) return + await this.synchronize({ version: e.textDocument.version, change: changes[0] }) + }) + } + + public async start(inserted: string, range: Range, select = true, context?: UltiSnippetContext): Promise { + const { document } = this + const placeholder = this.getReplacePlaceholder(range) + const edits: TextEdit[] = [] + if (placeholder) { + // update all snippet. + let r = this.snippet.range + let previous = document.textDocument.getText(r) + let parts = getParts(placeholder.value, placeholder.range, range) + this.current = await this.snippet.insertSnippet(placeholder, inserted, parts, context) + let edit = reduceTextEdit({ + range: r, + newText: this.snippet.text + }, previous) + edits.push(edit) + } else { + const resolver = new SnippetVariableResolver(this.nvim, workspace.workspaceFolderControl) + let snippet = new CocSnippet(inserted, range.start, this.nvim, resolver) + await snippet.init(context) + this._snippet = snippet + this.current = snippet.firstPlaceholder?.marker + edits.push(TextEdit.replace(range, snippet.text)) + // try fix indent of remain text + if (inserted.replace(/\$0$/, '').endsWith('\n')) { + const currentLine = document.getline(range.start.line) + const remain = currentLine.slice(range.end.character) + if (remain.length) { + let s = range.end.character + let l = remain.match(/^\s*/)[0].length + let r = Range.create(range.end.line, s, range.end.line, s + l) + edits.push(TextEdit.replace(r, currentLine.match(/^\s*/)[0])) + } + } + } + await this.applyEdits(edits) + this.textDocument = document.textDocument + this.activate() + if (select && this.current) { + let placeholder = this.snippet.getPlaceholderByMarker(this.current) + await this.selectPlaceholder(placeholder, true) + } + return this._isActive + } + + private async applyEdits(edits: TextEdit[]): Promise { + this._applying = true + await this.document.applyEdits(edits) + this._applying = false + } + + /** + * Get valid placeholder to insert + */ + private getReplacePlaceholder(range: Range): CocSnippetPlaceholder | undefined { + if (!this.snippet) return undefined + let placeholder = this.findPlaceholder(range) + if (!placeholder || placeholder.index == 0) return undefined + return placeholder + } + + private activate(): void { + if (this._isActive) return + this._isActive = true + this.nvim.call('coc#snippet#enable', [this.preferComplete ? 1 : 0], true) + } + + public deactivate(): void { + this.cancel() + if (!this._isActive) return + this.disposable.dispose() + this._isActive = false + this.current = null + this.nvim.call('coc#snippet#disable', [], true) + if (this.enableHighlight) this.nvim.call('coc#highlight#clear_highlight', [this.bufnr, NAME_SPACE, 0, -1], true) + this._onCancelEvent.fire(void 0) + logger.debug(`session ${this.bufnr} cancelled`) + } + + public get isActive(): boolean { + return this._isActive + } + + public get bufnr(): number { + return this.document.bufnr + } + + public async nextPlaceholder(): Promise { + await this.forceSynchronize() + let curr = this.placeholder + if (!curr) return + let next = this.snippet.getNextPlaceholder(curr.index) + if (next) await this.selectPlaceholder(next) + } + + public async previousPlaceholder(): Promise { + await this.forceSynchronize() + let curr = this.placeholder + if (!curr) return + let prev = this.snippet.getPrevPlaceholder(curr.index) + if (prev) await this.selectPlaceholder(prev) + + } + + public async selectCurrentPlaceholder(triggerAutocmd = true): Promise { + await this.forceSynchronize() + if (!this.snippet) return + let placeholder = this.snippet.getPlaceholderByMarker(this.current) + if (placeholder) await this.selectPlaceholder(placeholder, triggerAutocmd) + } + + public async selectPlaceholder(placeholder: CocSnippetPlaceholder, triggerAutocmd = true): Promise { + let { nvim, document } = this + if (!document || !placeholder) return + let { start, end } = placeholder.range + const len = end.character - start.character + const col = byteLength(document.getline(start.line).slice(0, start.character)) + 1 + let marker = this.current = placeholder.marker + if (marker instanceof Placeholder && marker.choice && marker.choice.options.length) { + let arr = marker.choice.options.map(o => o.value) + await nvim.call('coc#snippet#show_choices', [start.line + 1, col, len, arr]) + if (triggerAutocmd) nvim.call('coc#util#do_autocmd', ['CocJumpPlaceholder'], true) + } else { + let finalCount = this.snippet.finalCount + await this.select(placeholder, triggerAutocmd) + this.highlights(placeholder) + if (placeholder.index == 0) { + if (finalCount == 1) { + logger.info('Jump to final placeholder, cancelling snippet session') + this.deactivate() + } else { + nvim.call('coc#snippet#disable', [], true) + } + } + } + } + + private highlights(placeholder: CocSnippetPlaceholder, redrawVim = true): void { + if (!this.enableHighlight) return + // this.checkPosition + let buf = this.document.buffer + this.nvim.pauseNotification() + buf.clearNamespace(NAME_SPACE) + let ranges = this.snippet.getRanges(placeholder) + if (ranges.length) { + buf.highlightRanges(NAME_SPACE, 'CocSnippetVisual', ranges) + } + this.nvim.resumeNotification(redrawVim, true) + } + + private async select(placeholder: CocSnippetPlaceholder, triggerAutocmd = true): Promise { + let { range, value } = placeholder + let { nvim } = this + if (value.length > 0) { + await nvim.call('coc#snippet#select', [range.start, range.end, value]) + } else { + await nvim.call('coc#snippet#move', [range.start]) + } + if (triggerAutocmd) nvim.call('coc#util#do_autocmd', ['CocJumpPlaceholder'], true) + nvim.redrawVim() + } + + public async checkPosition(): Promise { + if (!this.isActive) return + let position = await window.getCursorPosition() + if (this.snippet && positionInRange(position, this.snippet.range) != 0) { + logger.info('Cursor insert out of range, cancelling snippet session') + this.deactivate() + } + } + + public findPlaceholder(range: Range): CocSnippetPlaceholder | null { + let { placeholder } = this + if (placeholder && rangeInRange(range, placeholder.range)) return placeholder + return this.snippet.getPlaceholderByRange(range) || null + } + + public async synchronize(change?: DocumentChange): Promise { + this.cancel() + await this.mutex.use(() => { + let version = this.textDocument ? this.textDocument.version : -1 + if (change && (this.document.version != change.version || change.version - version !== 1)) { + // can't be used any more + change = undefined + } + return this._synchronize(change ? change.change : undefined) + }) + } + + public async _synchronize(change?: TextDocumentContentChange): Promise { + let { document, textDocument } = this + if (!document.attached || !this._isActive) return + let start = Date.now() + let d = document.textDocument + if (d.version == textDocument.version || equals(textDocument.lines, d.lines)) return + let { range, text } = this.snippet + if (change && !rangeInRange(change.range, range)) change = undefined + let end = getEndPosition(range.end, textDocument, d) + if (!end) { + logger.info('Content change after snippet, cancel snippet session') + this.deactivate() + return + } + let checked = checkContentBefore(range.start, textDocument, d) + if (!checked) { + let content = d.getText(Range.create(Position.create(0, 0), end)) + if (content.endsWith(text)) { + let pos = d.positionAt(content.length - text.length) + this.snippet.resetStartPosition(pos) + this.textDocument = d + logger.info('Content change before snippet, reset snippet position') + return + } + logger.info('Before and snippet body changed, cancel snippet session') + this.deactivate() + return + } + let tokenSource = this.tokenSource = new CancellationTokenSource() + let cursor = await window.getCursorPosition() + if (tokenSource.token.isCancellationRequested || document.hasChanged) return + let placeholder: CocSnippetPlaceholder + let newText: string | undefined + let inserted = d.getText(Range.create(range.start, end)) + let curr = this.placeholder + if (change) { + for (let p of this.snippet.getSortedPlaceholders(curr)) { + if (rangeInRange(change.range, p.range)) { + placeholder = p + newText = this.snippet.getNewText(p, inserted) + break + } + } + // Check Text delete + if (!placeholder && change.text.length == 0 && !emptyRange(change.range) && isSingleLine(change.range)) { + let length = change.range.end.character - change.range.start.character + let offset = d.getText(Range.create(range.start, change.range.start)).length + if (this.snippet.removeText(offset, length)) { + this.textDocument = d + return + } + } + } else { + for (let p of this.snippet.getSortedPlaceholders(curr)) { + if (comparePosition(cursor, p.range.start) < 0) continue + newText = this.snippet.getNewText(p, inserted) + // p.range.start + newText + if (newText != null && checkCursor(p.range.start, cursor, newText)) { + placeholder = p + break + } + } + } + if (!placeholder && inserted.endsWith(text)) { + let pos = getEnd(range.start, inserted.slice(0, - text.length)) + this.snippet.resetStartPosition(pos) + this.textDocument = d + logger.info('Content change before snippet, reset snippet position') + return + } + if (!placeholder) { + logger.info('Unable to find changed placeholder, cancel snippet session') + this.deactivate() + return + } + let res = await this.snippet.updatePlaceholder(placeholder, cursor, newText, tokenSource.token) + if (res == null || tokenSource.token.isCancellationRequested) return + if (shouldCancel(document, res.delta)) { + tokenSource.cancel() + tokenSource.dispose() + return + } + tokenSource.dispose() + this.current = placeholder.marker + if (res.text !== inserted) { + let edit = reduceTextEdit({ + range: Range.create(this.snippet.start, end), + newText: res.text + }, inserted) + await this.applyEdits([edit]) + let { delta } = res + if (delta.line != 0 || delta.character != 0) { + this.nvim.call(`coc#cursor#move_to`, [cursor.line + delta.line, cursor.character + delta.character], true) + } + this.highlights(placeholder, false) + this.nvim.redrawVim() + } else { + this.highlights(placeholder) + } + logger.debug('update cost:', Date.now() - start, res.delta) + this.textDocument = this.document.textDocument + } + + public async forceSynchronize(): Promise { + this.cancel() + await this.document.patchChange() + let release = await this.mutex.acquire() + release() + } + + public cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource.dispose() + this.tokenSource = null + } + } + + public get placeholder(): CocSnippetPlaceholder | undefined { + if (!this.snippet || !this.current) return undefined + return this.snippet.getPlaceholderByMarker(this.current) + } + + public get snippet(): CocSnippet { + return this._snippet + } + + public static async resolveSnippet(nvim: Neovim, snippetString: string, ultisnip?: UltiSnippetOption): Promise { + let position = await window.getCursorPosition() + let line = await nvim.line + let context: UltiSnippetContext + if (ultisnip) context = Object.assign({ range: Range.create(position, position), line }, ultisnip) + const resolver = new SnippetVariableResolver(nvim, workspace.workspaceFolderControl) + let snippet = new CocSnippet(snippetString, position, nvim, resolver) + await snippet.init(context, true) + return snippet.text + } +} + +export function shouldCancel(document: Document, delta: Position): boolean { + if (document.hasChanged) return true + if (events.pumvisible && (delta.line != 0 || delta.character != 0)) return true + return false +} diff --git a/sources_non_forked/coc.nvim/src/snippets/snippet.ts b/sources_non_forked/coc.nvim/src/snippets/snippet.ts new file mode 100644 index 00000000..e6249e9e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/snippet.ts @@ -0,0 +1,458 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { LinesTextDocument } from '../model/textdocument' +import { emptyRange, getEnd, positionInRange, rangeInRange } from '../util/position' +import { getChangedPosition } from '../util/textedit' +import { prepareMatchCode, preparePythonCodes, UltiSnippetContext } from './eval' +import * as Snippets from "./parser" +import { VariableResolver } from './parser' +const logger = require('../util/logger')('snippets-snipet') + +export interface CocSnippetPlaceholder { + index: number | undefined + marker: Snippets.Placeholder | Snippets.Variable + value: string + primary: boolean + transform: boolean + // range in current buffer + range: Range + // snippet text before + before: string + // snippet text after + after: string +} + +export class CocSnippet { + private _placeholders: CocSnippetPlaceholder[] + private _text: string | undefined + public tmSnippet: Snippets.TextmateSnippet + + constructor(private snippetString: string, + private position: Position, + private nvim: Neovim, + private resolver?: VariableResolver, + ) { + } + + public async init(ultisnip?: UltiSnippetContext, isResolve = false): Promise { + const matchCode = ultisnip ? prepareMatchCode(ultisnip) : undefined + const parser = new Snippets.SnippetParser(!!ultisnip, matchCode) + const snippet = parser.parse(this.snippetString, true) + this.tmSnippet = snippet + await this.resolve(ultisnip) + this.synchronize() + if (!isResolve) { + this.nvim.call('coc#compat#del_var', ['coc_selected_text'], true) + this.nvim.call('coc#compat#del_var', ['coc_last_placeholder'], true) + } + } + + private async resolve(ultisnip?: UltiSnippetContext): Promise { + let { snippet } = this.tmSnippet + let { resolver, nvim } = this + if (resolver) { + await snippet.resolveVariables(resolver) + } + if (ultisnip && ultisnip.noPython !== true) { + let pyCodes: string[] = [] + if (snippet.hasPython) pyCodes = preparePythonCodes(ultisnip) + await snippet.evalCodeBlocks(nvim, pyCodes) + } + } + + public getRanges(placeholder: CocSnippetPlaceholder): Range[] { + let marker = placeholder.marker + if (placeholder.value.length == 0) return [] + let placeholders = this._placeholders.filter(o => o.index == placeholder.index) + let ranges = placeholders.map(o => o.range) + let parents = this.tmSnippet.enclosingPlaceholders(marker) + let markers: Snippets.Marker[] + let p = marker.parent + if (marker instanceof Snippets.Placeholder) { + let index = marker.index + markers = this.tmSnippet.placeholders.filter(o => o.index == index && o.parent == p) + } else { + let name = marker.name + markers = this.tmSnippet.variables.filter(o => o.name == name && o.parent == p) + } + parents.forEach(p => { + let arr = this._placeholders.filter(o => o.index == p.index && o.marker !== p) + if (!arr.length) return + for (let m of markers) { + let before = this.tmSnippet.getTextBefore(m, p) + arr.forEach(item => { + if (item.transform) { + ranges.push(item.range) + } else { + let s = item.range.start + ranges.push(Range.create(getEnd(s, before), getEnd(s, before + m.toString()))) + } + }) + } + }) + return ranges.filter(r => !emptyRange(r)) + } + + public getSortedPlaceholders(curr?: CocSnippetPlaceholder | undefined): CocSnippetPlaceholder[] { + let res = curr ? [curr] : [] + let arr = this._placeholders.filter(o => o !== curr && !o.transform) + arr.sort((a, b) => { + if (a.primary !== b.primary) return a.primary ? -1 : 1 + if (a.index == 0 || b.index == 0) return a.index == 0 ? 1 : -1 + return a.index - b.index + }) + res.push(...arr) + return res + } + + public get hasPython(): boolean { + return this.tmSnippet.pyBlocks.length > 0 + } + + public resetStartPosition(pos: Position): void { + this.position = pos + this.synchronize() + } + + public get start(): Position { + return Object.assign({}, this.position) + } + + public get range(): Range { + return Range.create(this.position, getEnd(this.position, this._text)) + } + + public get text(): string { + return this._text + } + + public get finalCount(): number { + return this._placeholders.filter(o => o.index == 0).length + } + + public get placeholders(): ReadonlyArray { + return this._placeholders.map(o => o.marker) + } + + public get firstPlaceholder(): CocSnippetPlaceholder | undefined { + let index = 0 + for (let p of this._placeholders) { + if (p.index == 0 || p.transform) continue + if (index == 0 || p.index < index) { + index = p.index + } + } + return this.getPlaceholder(index) + } + + public getPlaceholderByMarker(marker: Snippets.Marker): CocSnippetPlaceholder { + return this._placeholders.find(o => o.marker === marker) + } + + public getPlaceholder(index: number): CocSnippetPlaceholder { + let filtered = this._placeholders.filter(o => o.index == index && !o.transform) + let find = filtered.find(o => o.primary) || filtered[0] + return find ?? filtered[0] + } + + public getPrevPlaceholder(index: number): CocSnippetPlaceholder | undefined { + if (index <= 1) return undefined + let placeholders = this._placeholders.filter(o => o.index < index && o.index != 0 && !o.transform) + let find: CocSnippetPlaceholder + while (index > 1) { + index = index - 1 + let arr = placeholders.filter(o => o.index == index) + if (arr.length) { + find = arr.find(o => o.primary) || arr[0] + break + } + } + return find + } + + public getNextPlaceholder(index: number): CocSnippetPlaceholder | undefined { + let placeholders = this._placeholders.filter(o => !o.transform) + let find: CocSnippetPlaceholder + let indexes = placeholders.map(o => o.index) + let max = Math.max.apply(null, indexes) + for (let i = index + 1; i <= max + 1; i++) { + let idx = i == max + 1 ? 0 : i + let arr = placeholders.filter(o => o.index == idx) + if (arr.length) { + find = arr.find(o => o.primary) || arr[0] + break + } + } + return find + } + + public getPlaceholderByRange(range: Range): CocSnippetPlaceholder { + return this._placeholders.find(o => rangeInRange(range, o.range)) + } + + public async insertSnippet(placeholder: CocSnippetPlaceholder, snippet: string, parts: [string, string], ultisnip?: UltiSnippetContext): Promise { + if (ultisnip) { + let { start, end } = placeholder.range + this.nvim.setVar('coc_last_placeholder', { + current_text: placeholder.value, + start: { line: start.line, col: start.character, character: start.character }, + end: { line: end.line, col: end.character, character: end.character } + }, true) + } + let select = this.tmSnippet.insertSnippet(snippet, placeholder.marker, parts, ultisnip) + await this.resolve(ultisnip) + this.synchronize() + return select + } + + /** + * Check newText for placeholder. + */ + public getNewText(placeholder: CocSnippetPlaceholder, inserted: string): string | undefined { + let { before, after } = placeholder + if (!inserted.startsWith(before)) return undefined + if (inserted.length < before.length + after.length) return undefined + if (!inserted.endsWith(after)) return undefined + if (!after.length) return inserted.slice(before.length) + return inserted.slice(before.length, - after.length) + } + + public async updatePlaceholder(placeholder: CocSnippetPlaceholder, cursor: Position, newText: string, token: CancellationToken): Promise<{ text: string; delta: Position } | undefined> { + let start = this.position + let { marker, before } = placeholder + let cloned = this.tmSnippet.clone() + token.onCancellationRequested(() => { + this.tmSnippet = cloned + this.synchronize() + }) + // range before placeholder + let r = Range.create(start, getEnd(start, before)) + await this.tmSnippet.update(this.nvim, marker, newText) + if (token.isCancellationRequested) return undefined + this.synchronize() + let p = this._placeholders.find(o => o.marker == marker) + let after = p ? p.before : before + return { text: this._text, delta: getChangedPosition(cursor, TextEdit.replace(r, after)) } + } + + public removeText(offset: number, length: number): boolean { + let succeed = this.tmSnippet.deleteText(offset, length) + if (succeed) this.synchronize() + return succeed + } + + private synchronize(): void { + const snippet = this.tmSnippet + const { line, character } = this.position + const document = TextDocument.create('untitled:/1', 'snippet', 0, snippet.toString()) + let { placeholders, variables, maxIndexNumber } = snippet + const variableIndexMap: Map = new Map() + let variableIndex = maxIndexNumber + 1 + + this._placeholders = [...placeholders, ...variables].map(p => { + const offset = snippet.offset(p) + const position = document.positionAt(offset) + const start: Position = { + line: line + position.line, + character: position.line == 0 ? character + position.character : position.character + } + let index: number + if (p instanceof Snippets.Variable) { + let key = p.name + if (variableIndexMap.has(key)) { + index = variableIndexMap.get(key) + } else { + variableIndexMap.set(key, variableIndex) + index = variableIndex + variableIndex = variableIndex + 1 + } + } else { + index = p.index + } + const value = p.toString() + const end = getEnd(position, value) + let res: CocSnippetPlaceholder = { + index, + value, + marker: p, + transform: !!p.transform, + range: Range.create(start, getEnd(start, value)), + before: document.getText(Range.create(Position.create(0, 0), position)), + after: document.getText(Range.create(end, Position.create(document.lineCount, 0))), + primary: p instanceof Snippets.Placeholder && p.primary === true + } + return res + }) + this._text = this.tmSnippet.toString() + } +} + +/** + * Current line text before marker + */ +export function getContentBefore(marker: Snippets.Marker): string { + let res = '' + const calc = (m: Snippets.Marker): void => { + let p = m.parent + if (!p) return + let s = '' + for (let b of p.children) { + if (b === m) break + s = s + b.toString() + } + if (s.indexOf('\n') !== -1) { + let arr = s.split(/\n/) + res = arr[arr.length - 1] + res + return + } + res = s + res + calc(p) + } + calc(marker) + return res +} + +/* + * Avoid change unnecessary range of text. + */ +export function reduceTextEdit(edit: TextEdit, oldText: string): TextEdit { + let { range, newText } = edit + let ol = oldText.length + let nl = newText.length + if (ol === 0 || nl === 0) return edit + let { start, end } = range + let bo = 0 + for (let i = 1; i <= Math.min(nl, ol); i++) { + if (newText[i - 1] === oldText[i - 1]) { + bo = i + } else { + break + } + } + let eo = 0 + let t = Math.min(nl - bo, ol - bo) + if (t > 0) { + for (let i = 1; i <= t; i++) { + if (newText[nl - i] === oldText[ol - i]) { + eo = i + } else { + break + } + } + } + let text = eo == 0 ? newText.slice(bo) : newText.slice(bo, -eo) + if (bo > 0) start = getEnd(start, newText.slice(0, bo)) + if (eo > 0) end = getEnd(range.start, oldText.slice(0, -eo)) + return TextEdit.replace(Range.create(start, end), text) +} + +/* + * Check if cursor inside + */ +export function checkCursor(start: Position, cursor: Position, newText: string): boolean { + let r = Range.create(start, getEnd(start, newText)) + return positionInRange(cursor, r) == 0 +} + +/* + * Check if textDocument have same text before position. + */ +export function checkContentBefore(position: Position, oldTextDocument: LinesTextDocument, textDocument: LinesTextDocument): boolean { + let lines = textDocument.lines + if (lines.length < position.line) return false + let checked = true + for (let i = position.line; i >= 0; i--) { + let newLine = textDocument.lines[i] ?? '' + if (i === position.line) { + let before = oldTextDocument.lines[i].slice(0, position.character) + if (!newLine.startsWith(before)) { + checked = false + break + } + } else if (newLine !== oldTextDocument.lines[i]) { + checked = false + break + } + } + return checked +} + +/** + * Get new end position by old end position and new TextDocument + */ +export function getEndPosition(position: Position, oldTextDocument: LinesTextDocument, textDocument: LinesTextDocument): Position | undefined { + let total = oldTextDocument.lines.length + if (textDocument.lines.length < total - position.line) return undefined + let end: Position + let cl = textDocument.lines.length - total + for (let i = position.line; i < total; i++) { + let newLine = textDocument.lines[i + cl] + if (i == position.line) { + let text = oldTextDocument.lines[i].slice(position.character) + if (text.length && !newLine.endsWith(text)) break + end = Position.create(i + cl, newLine.length - text.length) + } else if (newLine !== oldTextDocument.lines[i]) { + end = undefined + break + } + } + return end +} + +/* + * r in range + */ +export function getParts(text: string, range: Range, r: Range): [string, string] { + let before: string[] = [] + let after: string[] = [] + let lines = text.split('\n') + let d = r.start.line - range.start.line + for (let i = 0; i <= d; i++) { + let s = lines[i] ?? '' + if (i == d) { + before.push(i == 0 ? s.substring(0, r.start.character - range.start.character) : s.substring(0, r.start.character)) + } else { + before.push(s) + } + } + d = range.end.line - r.end.line + for (let i = 0; i <= d; i++) { + let s = lines[r.end.line - range.start.line + i] ?? '' + if (i == 0) { + if (d == 0) { + after.push(range.end.character == r.end.character ? '' : s.slice(r.end.character - range.end.character)) + } else { + after.push(s.substring(r.end.character)) + } + } else { + after.push(s) + } + } + return [before.join('\n'), after.join('\n')] +} + +export function normalizeSnippetString(snippet: string, indent: string, opts: { tabSize: number, insertSpaces: boolean }): string { + let lines = snippet.split(/\r?\n/) + let ind = opts.insertSpaces ? ' '.repeat(opts.tabSize) : '\t' + let tabSize = opts.tabSize || 2 + lines = lines.map((line, idx) => { + let space = line.match(/^\s*/)[0] + let pre = space + let isTab = space.startsWith('\t') + if (isTab && opts.insertSpaces) { + pre = ind.repeat(space.length) + } else if (!isTab && !opts.insertSpaces) { + pre = ind.repeat(space.length / tabSize) + } + return (idx == 0 || line.length == 0 ? '' : indent) + pre + line.slice(space.length) + }) + return lines.join('\n') +} + +export function shouldFormat(snippet: string): boolean { + if (/^\s/.test(snippet)) return true + if (snippet.indexOf('\n') !== -1) return true + return false +} diff --git a/sources_non_forked/coc.nvim/src/snippets/string.ts b/sources_non_forked/coc.nvim/src/snippets/string.ts new file mode 100644 index 00000000..24e6ba3e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/string.ts @@ -0,0 +1,103 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export class SnippetString { + public static isSnippetString(thing: any): thing is SnippetString { + if (thing instanceof SnippetString) { + return true + } + if (!thing) { + return false + } + return typeof thing.value === 'string' + } + + private static _escape(value: string): string { + return value.replace(/\$|}|\\/g, '\\$&') + } + + private _tabstop = 1 + + public value: string + + constructor(value?: string) { + this.value = value || '' + } + + public appendText(str: string): SnippetString { + this.value += SnippetString._escape(str) + return this + } + + public appendTabstop(num: number = this._tabstop++): SnippetString { + this.value += '$' + this.value += num + return this + } + + public appendPlaceholder( + value: string | ((snippet: SnippetString) => any), + num: number = this._tabstop++ + ): SnippetString { + if (typeof value === 'function') { + const nested = new SnippetString() + nested._tabstop = this._tabstop + value(nested) + this._tabstop = nested._tabstop + value = nested.value + } else { + value = SnippetString._escape(value) + } + + this.value += '${' + this.value += num + this.value += ':' + this.value += value + this.value += '}' + + return this + } + + public appendChoice( + values: string[], + num: number = this._tabstop++ + ): SnippetString { + const value = values.map(s => s.replace(/\$|}|\\|,/g, '\\$&')).join(',') + + this.value += '${' + this.value += num + this.value += '|' + this.value += value + this.value += '|}' + + return this + } + + public appendVariable( + name: string, + defaultValue?: string | ((snippet: SnippetString) => any) + ): SnippetString { + if (typeof defaultValue === 'function') { + const nested = new SnippetString() + nested._tabstop = this._tabstop + defaultValue(nested) + this._tabstop = nested._tabstop + defaultValue = nested.value + } else if (typeof defaultValue === 'string') { + defaultValue = defaultValue.replace(/\$|}/g, '\\$&') + } + + this.value += '${' + this.value += name + if (defaultValue) { + this.value += ':' + this.value += defaultValue + } + this.value += '}' + + return this + } +} diff --git a/sources_non_forked/coc.nvim/src/snippets/variableResolve.ts b/sources_non_forked/coc.nvim/src/snippets/variableResolve.ts new file mode 100644 index 00000000..910a0031 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/snippets/variableResolve.ts @@ -0,0 +1,164 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import path from 'path' +import { Variable, VariableResolver } from "./parser" +import WorkspaceFolderController from '../core/workspaceFolder' +import { v4 as uuid } from 'uuid' +import { URI } from 'vscode-uri' +const logger = require('../util/logger')('snippets-variable') + +function padZero(n: number): string { + return n < 10 ? '0' + n : n.toString() +} + +export function parseComments(comments: string): { start?: string, end?: string, single?: string } { + let start: string + let end: string + let single: string + let parts = comments.split(',') + for (let s of parts) { + if (start && end && single) break + if (!s.includes(':')) continue + let [flag, str] = s.split(':') + if (flag.includes('s')) { + start = str + } else if (flag.includes('e')) { + end = str + } else if (!single && flag == '') { + single = str + } + } + return { start, end, single } +} + +/* + * Get single line comment text + */ +export function parseCommentstring(commentstring: string): string | undefined { + if (commentstring.endsWith('%s')) return commentstring.slice(0, -2).trim() + return undefined +} + +export class SnippetVariableResolver implements VariableResolver { + private _variableToValue: { [key: string]: string } = {} + + constructor(private nvim: Neovim, private workspaceFolder: WorkspaceFolderController) { + const currentDate = new Date() + const fullyear = currentDate.getFullYear().toString() + Object.assign(this._variableToValue, { + CURRENT_YEAR: fullyear, + CURRENT_YEAR_SHORT: fullyear.slice(-2), + CURRENT_MONTH: padZero(currentDate.getMonth() + 1), + CURRENT_DATE: padZero(currentDate.getDate()), + CURRENT_HOUR: padZero(currentDate.getHours()), + CURRENT_MINUTE: padZero(currentDate.getMinutes()), + CURRENT_SECOND: padZero(currentDate.getSeconds()), + CURRENT_DAY_NAME: currentDate.toLocaleString("en-US", { weekday: "long" }), + CURRENT_DAY_NAME_SHORT: currentDate.toLocaleString("en-US", { weekday: "short" }), + CURRENT_MONTH_NAME: currentDate.toLocaleString("en-US", { month: "long" }), + CURRENT_MONTH_NAME_SHORT: currentDate.toLocaleString("en-US", { month: "short" }), + TM_FILENAME: null, + TM_FILENAME_BASE: null, + TM_DIRECTORY: null, + TM_FILEPATH: null, + YANK: null, + TM_LINE_INDEX: null, + TM_LINE_NUMBER: null, + TM_CURRENT_LINE: null, + TM_CURRENT_WORD: null, + TM_SELECTED_TEXT: null, + VISUAL: null, + CLIPBOARD: null, + RELATIVE_FILEPATH: null, + RANDOM: null, + RANDOM_HEX: null, + UUID: null, + BLOCK_COMMENT_START: null, + BLOCK_COMMENT_END: null, + LINE_COMMENT: null, + WORKSPACE_NAME: null, + WORKSPACE_FOLDER: null + }) + } + + private async resolveValue(name: string): Promise { + let { nvim } = this + if (['TM_FILENAME', 'TM_FILENAME_BASE', 'TM_DIRECTORY', 'TM_FILEPATH'].includes(name)) { + let filepath = await nvim.eval('expand("%:p")') as string + if (name === 'TM_FILENAME') return path.basename(filepath) + if (name === 'TM_FILENAME_BASE') return path.basename(filepath, path.extname(filepath)) + if (name === 'TM_DIRECTORY') return path.dirname(filepath) + if (name === 'TM_FILEPATH') return filepath + } + if (name === 'YANK') { + return await nvim.call('getreg', ['""']) as string + } + if (name === 'TM_LINE_INDEX') { + let lnum = await nvim.call('line', ['.']) as number + return (lnum - 1).toString() + } + if (name === 'TM_LINE_NUMBER') { + let lnum = await nvim.call('line', ['.']) as number + return lnum.toString() + } + if (name === 'TM_CURRENT_LINE') { + return await nvim.call('getline', ['.']) as string + } + if (name === 'TM_CURRENT_WORD') { + return await nvim.eval(`expand('')`) as string + } + if (name === 'TM_SELECTED_TEXT' || name == 'VISUAL') { + return await nvim.eval(`get(g:,'coc_selected_text', v:null)`) as string + } + if (name === 'CLIPBOARD') { + return await nvim.eval('@*') as string + } + if (name === 'RANDOM') { + return Math.random().toString().slice(-6) + } + if (name === 'RANDOM_HEX') { + return Math.random().toString(16).slice(-6) + } + if (name === 'UUID') { + return uuid() + } + if (['RELATIVE_FILEPATH', 'WORKSPACE_NAME', 'WORKSPACE_FOLDER'].includes(name)) { + let filepath = await nvim.eval('expand("%:p")') as string + let folder = this.workspaceFolder.getWorkspaceFolder(URI.file(filepath)) + if (name === 'RELATIVE_FILEPATH') return this.workspaceFolder.getRelativePath(filepath) + if (name === 'WORKSPACE_NAME') return folder.name + if (name === 'WORKSPACE_FOLDER') return URI.parse(folder.uri).fsPath + } + if (name === 'LINE_COMMENT') { + let commentstring = await nvim.eval('&commentstring') as string + let s = parseCommentstring(commentstring) + if (s) return s + let comments = await nvim.eval('&comments') as string + let { single } = parseComments(comments) + return single ?? '' + } + if (['BLOCK_COMMENT_START', 'BLOCK_COMMENT_END'].includes(name)) { + let comments = await nvim.eval('&comments') as string + let { start, end } = parseComments(comments) + if (name === 'BLOCK_COMMENT_START') return start ?? '' + if (name === 'BLOCK_COMMENT_END') return end ?? '' + } + } + + public async resolve(variable: Variable): Promise { + const name = variable.name + let resolved = this._variableToValue[name] + if (resolved != null) return resolved.toString() + // resolve known value + if (this._variableToValue.hasOwnProperty(name)) { + let value = await this.resolveValue(name) + if (!value && variable.children.length) { + return variable.toString() + } + return value == null ? '' : value.toString() + } + if (variable.children.length) return variable.toString() + // VSCode behavior + return name + } +} diff --git a/sources_non_forked/coc.nvim/src/sources/index.ts b/sources_non_forked/coc.nvim/src/sources/index.ts new file mode 100644 index 00000000..d7cadb3c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/index.ts @@ -0,0 +1,421 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import path from 'path' +import util from 'util' +import { CompletionItemKind, Disposable, DocumentSelector } from 'vscode-languageserver-protocol' +import events from '../events' +import extensions from '../extensions' +import { CompletionItemProvider } from '../provider' +import { CompleteOption, ExtendedCompleteItem, ISource, SourceConfig, SourceStat, SourceType } from '../types' +import { disposeAll, getUri } from '../util' +import { intersect } from '../util/array' +import { statAsync } from '../util/fs' +import { byteSlice } from '../util/string' +import BufferSync from '../model/bufferSync' +import KeywordsBuffer from './keywords' +import window from '../window' +import workspace from '../workspace' +import Source from './source' +import LanguageSource, { CompleteConfig } from './source-language' +import VimSource from './source-vim' +const logger = require('../util/logger')('sources') + +export class Sources { + private sourceMap: Map = new Map() + private disposables: Disposable[] = [] + private remoteSourcePaths: string[] = [] + private keywords: BufferSync + private completeConfig: CompleteConfig + + public init(): void { + this.loadCompleteConfig() + this.keywords = workspace.registerBufferSync(doc => { + return new KeywordsBuffer(doc) + }) + workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('suggest')) { + this.loadCompleteConfig() + } + }, null, this.disposables) + this.createNativeSources() + this.createRemoteSources() + events.on('InsertLeave', () => { + for (let item of this.keywords.items) { + item.parse() + } + }, this, this.disposables) + events.on('BufEnter', this.onDocumentEnter, this, this.disposables) + workspace.onDidRuntimePathChange(newPaths => { + for (let p of newPaths) { + if (p) void this.createVimSources(p) + } + }, null, this.disposables) + } + + private loadCompleteConfig(): void { + let suggest = workspace.getConfiguration('suggest') + let labels = suggest.get<{ [key: string]: string }>('completionItemKindLabels', {}) + let map = new Map([ + [CompletionItemKind.Text, labels['text'] || 'v'], + [CompletionItemKind.Method, labels['method'] || 'f'], + [CompletionItemKind.Function, labels['function'] || 'f'], + [CompletionItemKind.Constructor, typeof labels['constructor'] == 'function' ? 'f' : labels['con' + 'structor']], + [CompletionItemKind.Field, labels['field'] || 'm'], + [CompletionItemKind.Variable, labels['variable'] || 'v'], + [CompletionItemKind.Class, labels['class'] || 'C'], + [CompletionItemKind.Interface, labels['interface'] || 'I'], + [CompletionItemKind.Module, labels['module'] || 'M'], + [CompletionItemKind.Property, labels['property'] || 'm'], + [CompletionItemKind.Unit, labels['unit'] || 'U'], + [CompletionItemKind.Value, labels['value'] || 'v'], + [CompletionItemKind.Enum, labels['enum'] || 'E'], + [CompletionItemKind.Keyword, labels['keyword'] || 'k'], + [CompletionItemKind.Snippet, labels['snippet'] || 'S'], + [CompletionItemKind.Color, labels['color'] || 'v'], + [CompletionItemKind.File, labels['file'] || 'F'], + [CompletionItemKind.Reference, labels['reference'] || 'r'], + [CompletionItemKind.Folder, labels['folder'] || 'F'], + [CompletionItemKind.EnumMember, labels['enumMember'] || 'm'], + [CompletionItemKind.Constant, labels['constant'] || 'v'], + [CompletionItemKind.Struct, labels['struct'] || 'S'], + [CompletionItemKind.Event, labels['event'] || 'E'], + [CompletionItemKind.Operator, labels['operator'] || 'O'], + [CompletionItemKind.TypeParameter, labels['typeParameter'] || 'T'], + ]) + let floatEnable = suggest.get('floatEnable', true) + let detailField = suggest.get('detailField', 'preview') + if (detailField == 'preview' && (!floatEnable || !workspace.floatSupported)) { + detailField = 'menu' + } + this.completeConfig = Object.assign(this.completeConfig || {}, { + labels: map, + floatEnable, + detailField, + defaultKindText: labels['default'] || '', + priority: suggest.get('languageSourcePriority', 99), + snippetsSupport: suggest.get('snippetsSupport', true), + detailMaxLength: suggest.get('detailMaxLength', 100), + invalidInsertCharacters: suggest.get('invalidInsertCharacters', ['(', '<', '{', '[', '\r', '\n']), + }) + } + + private get nvim(): Neovim { + return workspace.nvim + } + + private createNativeSources(): void { + this.disposables.push((require('./native/around')).regist(this.sourceMap, this.keywords)) + this.disposables.push((require('./native/buffer')).regist(this.sourceMap, this.keywords)) + this.disposables.push((require('./native/file')).regist(this.sourceMap)) + } + + public createLanguageSource( + name: string, + shortcut: string, + selector: DocumentSelector | null, + provider: CompletionItemProvider, + triggerCharacters: string[], + priority?: number | undefined, + allCommitCharacters?: string[] + ): Disposable { + let source = new LanguageSource( + name, + shortcut, + provider, + selector, + triggerCharacters || [], + allCommitCharacters || [], + priority, + this.completeConfig) + logger.debug('created service source', name) + this.sourceMap.set(name, source) + return { + dispose: () => { + this.sourceMap.delete(name) + } + } + } + + private async createVimSourceExtension(nvim: Neovim, filepath: string): Promise { + let name = path.basename(filepath, '.vim') + try { + await nvim.command(`source ${filepath}`) + let fns = await nvim.call('coc#util#remote_fns', name) as string[] + for (let fn of ['init', 'complete']) { + if (!fns.includes(fn)) { + window.showMessage(`${fn} not found for source ${name}`, 'error') + return null + } + } + let props = await nvim.call(`coc#source#${name}#init`, []) + let packageJSON = { + name: `coc-source-${name}`, + engines: { + coc: ">= 0.0.1" + }, + activationEvents: props.filetypes ? props.filetypes.map(f => `onLanguage:${f}`) : ['*'], + contributes: { + configuration: { + properties: { + [`coc.source.${name}.enable`]: { + type: 'boolean', + default: true + }, + [`coc.source.${name}.firstMatch`]: { + type: 'boolean', + default: !!props.firstMatch + }, + [`coc.source.${name}.triggerCharacters`]: { + type: 'number', + default: props.triggerCharacters || [] + }, + [`coc.source.${name}.priority`]: { + type: 'number', + default: props.priority || 9 + }, + [`coc.source.${name}.shortcut`]: { + type: 'string', + default: props.shortcut || name.slice(0, 3).toUpperCase(), + description: 'Shortcut text shown in complete menu.' + }, + [`coc.source.${name}.disableSyntaxes`]: { + type: 'array', + default: [], + items: { + type: 'string' + } + }, + [`coc.source.${name}.filetypes`]: { + type: 'array', + default: props.filetypes || null, + description: 'Enabled filetypes.', + items: { + type: 'string' + } + } + } + } + } + } + let source = new VimSource({ + name, + filepath, + sourceType: SourceType.Remote, + optionalFns: fns.filter(n => !['init', 'complete'].includes(n)) + }) + let isActive = false + let extension: any = { + id: packageJSON.name, + packageJSON, + exports: void 0, + extensionPath: filepath, + activate: () => { + isActive = true + this.addSource(source) + return Promise.resolve() + } + } + Object.defineProperty(extension, 'isActive', { + get: () => isActive + }) + extensions.registerExtension(extension, () => { + isActive = false + this.removeSource(source) + }) + } catch (e) { + window.showMessage(`Error on create vim source ${name}: ${e}`, 'error') + } + } + + private createRemoteSources(): void { + let { runtimepath } = workspace.env + let paths = runtimepath.split(',') + for (let path of paths) { + this.createVimSources(path).logError() + } + } + + private async createVimSources(pluginPath: string): Promise { + if (this.remoteSourcePaths.includes(pluginPath)) return + this.remoteSourcePaths.push(pluginPath) + let folder = path.join(pluginPath, 'autoload/coc/source') + let stat = await statAsync(folder) + if (stat && stat.isDirectory()) { + let arr = await util.promisify(fs.readdir)(folder) + arr = arr.filter(s => s.endsWith('.vim')) + let files = arr.map(s => path.join(folder, s)) + if (files.length == 0) return + await Promise.all(files.map(p => this.createVimSourceExtension(this.nvim, p))) + } + } + + public get names(): string[] { + return Array.from(this.sourceMap.keys()) + } + + public get sources(): ISource[] { + return Array.from(this.sourceMap.values()) + } + + public has(name): boolean { + return this.names.findIndex(o => o == name) != -1 + } + + public getSource(name: string): ISource | null { + if (!name) return null + return this.sourceMap.get(name) || null + } + + public shouldCommit(item: ExtendedCompleteItem, commitCharacter: string): boolean { + if (!item || !item.source) return false + let source = this.getSource(item.source) + if (source && source.sourceType == SourceType.Service && typeof source.shouldCommit === 'function') { + return source.shouldCommit(item, commitCharacter) + } + return false + } + + public getCompleteSources(opt: CompleteOption): ISource[] { + let { filetype, disabled } = opt + let pre = byteSlice(opt.line, 0, opt.colnr - 1) + let isTriggered = opt.input == '' && !!opt.triggerCharacter + let uri = getUri(opt.filepath, opt.bufnr, '', workspace.env.isCygwin) + disabled = Array.isArray(disabled) ? disabled : [] + if (isTriggered) return this.getTriggerSources(pre, filetype, uri, disabled) + return this.getNormalSources(opt.filetype, uri, disabled) + } + + /** + * Get sources should be used without trigger. + * + * @param {string} filetype + * @returns {ISource[]} + */ + public getNormalSources(filetype: string, uri: string, disabled: ReadonlyArray = []): ISource[] { + let languageIds = filetype.split('.') + return this.sources.filter(source => { + let { filetypes, triggerOnly, name, documentSelector, enable } = source + if (disabled.includes(name)) { + return false + } + if (!enable || triggerOnly || (filetypes && !intersect(filetypes, languageIds))) { + return false + } + if (documentSelector && languageIds.every(filetype => workspace.match(documentSelector, { uri, languageId: filetype }) == 0)) { + return false + } + return true + }) + } + + private checkTrigger(source: ISource, pre: string, character: string): boolean { + let { triggerCharacters, triggerPatterns } = source + if (triggerCharacters?.length > 0 && triggerCharacters.includes(character)) { + return true + } + if (triggerPatterns?.length > 0 && triggerPatterns.findIndex(p => p.test(pre)) !== -1) { + return true + } + return false + } + + public shouldTrigger(pre: string, filetype: string, uri: string): boolean { + return this.getTriggerSources(pre, filetype, uri).length > 0 + } + + public getTriggerSources(pre: string, filetype: string, uri: string, disabled: ReadonlyArray = []): ISource[] { + if (!pre) return [] + let character = pre[pre.length - 1] + let languageIds = filetype.split('.') + return this.sources.filter(source => { + let { filetypes, enable, documentSelector, name } = source + if (disabled.includes(name)) return false + if (!enable || (filetypes && !intersect(filetypes, languageIds))) { + return false + } + if (documentSelector && languageIds.every(languageId => workspace.match(documentSelector, { uri, languageId }) == 0)) { + return false + } + return this.checkTrigger(source, pre, character) + }) + } + + public addSource(source: ISource): Disposable { + let { name } = source + if (this.names.includes(name)) { + logger.warn(`Recreate source ${name}`) + } + this.sourceMap.set(name, source) + return Disposable.create(() => { + this.sourceMap.delete(name) + }) + } + + public removeSource(source: ISource | string): void { + let name = typeof source == 'string' ? source : source.name + this.sourceMap.delete(name) + } + + public async refresh(name?: string): Promise { + for (let source of this.sources) { + if (!name || source.name == name) { + if (typeof source.refresh === 'function') { + await Promise.resolve(source.refresh()) + } + } + } + } + + public toggleSource(name: string): void { + if (!name) return + let source = this.getSource(name) + if (!source) return + if (typeof source.toggle === 'function') { + source.toggle() + } + } + + public sourceStats(): SourceStat[] { + let res: SourceStat[] = [] + let items = this.sources + for (let item of items) { + res.push({ + name: item.name, + priority: item.priority, + triggerCharacters: item.triggerCharacters || [], + shortcut: item.shortcut || '', + filetypes: item.filetypes || [], + filepath: item.filepath || '', + type: item.sourceType == SourceType.Native + ? 'native' : item.sourceType == SourceType.Remote + ? 'remote' : 'service', + disabled: !item.enable + }) + } + return res + } + + private onDocumentEnter(bufnr: number): void { + let { sources } = this + for (let s of sources) { + if (s.enable && typeof s.onEnter == 'function') { + s.onEnter(bufnr) + } + } + } + + public createSource(config: SourceConfig): Disposable { + if (!config.name || !config.doComplete) { + throw new Error(`name and doComplete required for createSource`) + } + let source = new Source(Object.assign({ sourceType: SourceType.Service } as any, config)) + return this.addSource(source) + } + + public dispose(): void { + disposeAll(this.disposables) + } +} + +export default new Sources() diff --git a/sources_non_forked/coc.nvim/src/sources/keywords.ts b/sources_non_forked/coc.nvim/src/sources/keywords.ts new file mode 100644 index 00000000..431ada5c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/keywords.ts @@ -0,0 +1,75 @@ +'use strict' +import { CancellationTokenSource } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import events from '../events' +import { SyncItem } from '../model/bufferSync' +import Document from '../model/document' +import { DidChangeTextDocumentParams } from '../types' +import { isGitIgnored } from '../util/fs' +const logger = require('../util/logger')('sources-keywords') +const MAX_LENGTH = 10 * 1024 // 10KB + +export default class KeywordsBuffer implements SyncItem { + private _words: Set = new Set() + private _gitIgnored = false + private version: number + private lineCount: number + private tokenSource: CancellationTokenSource + constructor(private doc: Document) { + this.parse() + let uri = URI.parse(doc.uri) + if (uri.scheme === 'file') { + void isGitIgnored(uri.fsPath).then(ignored => { + this._gitIgnored = ignored + }) + } + } + + public get bufnr(): number { + return this.doc.bufnr + } + + public get gitIgnored(): boolean { + return this._gitIgnored + } + + public get words(): Set { + return this._words + } + + public parse(): void { + if (!this.doc.attached || events.completing) return + let { textDocument } = this.doc + let { version, lineCount } = textDocument + if (this.version === version) return + if (events.insertMode + && this.lineCount == lineCount + && textDocument.length > MAX_LENGTH) return + this.cancel() + let tokenSource = this.tokenSource = new CancellationTokenSource() + void this.doc.matchWords(tokenSource.token).then(res => { + if (res != null) { + this._words = res + this.lineCount = lineCount + this.version = version + } + }) + } + + private cancel(): void { + if (this.tokenSource) { + this.tokenSource.cancel() + this.tokenSource = null + } + } + + public onChange(e: DidChangeTextDocumentParams): void { + if (e.contentChanges.length == 0) return + this.parse() + } + + public dispose(): void { + this.cancel() + this._words.clear() + } +} diff --git a/sources_non_forked/coc.nvim/src/sources/native/around.ts b/sources_non_forked/coc.nvim/src/sources/native/around.ts new file mode 100644 index 00000000..fe4189c3 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/native/around.ts @@ -0,0 +1,99 @@ +'use strict' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import BufferSync from '../../model/bufferSync' +import { CompleteOption, CompleteResult, ISource } from '../../types' +import { waitImmediate } from '../../util' +import { fuzzyMatch, getCharCodes } from '../../util/fuzzy' +import KeywordsBuffer from '../keywords' +import Source from '../source' +const logger = require('../../util/logger')('sources-around') + +export default class Around extends Source { + constructor(private keywords: BufferSync) { + super({ + name: 'around', + filepath: __filename + }) + } + + /** + * Filter words that too short or doesn't match input + */ + private async filterWords(words: Set, opt: CompleteOption, token: CancellationToken, res: string[]): Promise { + let isIncomplete = false + let { input } = opt + let cword = opt.word + let first = input[0] + let fuzzy = input.length > 1 + let min = opt.input.length + let code = first.charCodeAt(0) + let ignoreCase = code >= 97 && code <= 122 + let needle = fuzzy ? getCharCodes(input) : [] + let checkInput = true + let checkCword = true + let ts = Date.now() + for (let word of words) { + let len = word.length + if (len < min) continue + if (checkInput && len == min && word === input) { + checkInput = false + continue + } + if (checkCword && len == cword.length && word === cword) { + checkCword = false + continue + } + if (Date.now() - ts > 15) { + await waitImmediate() + if (token.isCancellationRequested) return undefined + ts = Date.now() + } + let ch = ignoreCase ? word[0].toLowerCase() : word[0] + if (fuzzy) { + if (ch.charCodeAt(0) === code && fuzzyMatch(needle, word)) { + res.push(word) + if (res.length == 100) { + isIncomplete = true + break + } + } + } else { + if (ch.charCodeAt(0) === code) { + res.push(word) + if (res.length == 100) { + isIncomplete = true + break + } + } + } + } + return isIncomplete + } + + public async doComplete(opt: CompleteOption, token: CancellationToken): Promise { + let { bufnr, input } = opt + if (input.length === 0) return null + await waitImmediate() + if (token.isCancellationRequested) return null + let item = this.keywords.getItem(bufnr) + let words = item?.words + if (!words) return null + let arr = [] + let isIncomplete = await this.filterWords(words, opt, token, arr) + if (token.isCancellationRequested) return null + return { + isIncomplete, + items: arr.map(word => ({ + word, + menu: this.menu + })) + } + } +} + +export function regist(sourceMap: Map, keywords: BufferSync): Disposable { + sourceMap.set('around', new Around(keywords)) + return Disposable.create(() => { + sourceMap.delete('around') + }) +} diff --git a/sources_non_forked/coc.nvim/src/sources/native/buffer.ts b/sources_non_forked/coc.nvim/src/sources/native/buffer.ts new file mode 100644 index 00000000..f9aa09d6 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/native/buffer.ts @@ -0,0 +1,88 @@ +'use strict' +import { CancellationToken, Disposable } from 'vscode-languageserver-protocol' +import BufferSync from '../../model/bufferSync' +import { CompleteOption, CompleteResult, ISource } from '../../types' +import { waitImmediate } from '../../util' +import { fuzzyMatch, getCharCodes } from '../../util/fuzzy' +import KeywordsBuffer from '../keywords' +import Source from '../source' +const logger = require('../../util/logger')('sources-buffer') + +export default class Buffer extends Source { + constructor(private keywords: BufferSync) { + super({ + name: 'buffer', + filepath: __filename + }) + } + + public get ignoreGitignore(): boolean { + return this.getConfig('ignoreGitignore', true) + } + + private async getWords(bufnr: number, opt: CompleteOption, token: CancellationToken, words: Set): Promise { + let { ignoreGitignore } = this + let isIncomplete = false + let first = opt.input[0] + let min = opt.input.length + let fuzzy = min > 1 + let code = first.charCodeAt(0) + let ignoreCase = code >= 97 && code <= 122 + let needle = fuzzy ? getCharCodes(opt.input) : [] + let ts = Date.now() + for (let item of this.keywords.items) { + if (words.size == 100) break + if (item.bufnr === bufnr || (ignoreGitignore && item.gitIgnored)) continue + for (let w of item.words) { + if (Date.now() - ts > 15) { + await waitImmediate() + if (token.isCancellationRequested) return undefined + ts = Date.now() + } + if (w.length < min) continue + let ch = ignoreCase ? w[0].toLowerCase() : w[0] + if (fuzzy) { + if (ch.charCodeAt(0) === code && fuzzyMatch(needle, w)) { + words.add(w) + if (words.size == 100) { + isIncomplete = true + break + } + } + } else { + if (ch.charCodeAt(0) === code) { + words.add(w) + if (words.size == 100) { + isIncomplete = true + break + } + } + } + } + } + return isIncomplete + } + + public async doComplete(opt: CompleteOption, token: CancellationToken): Promise { + let { bufnr, input } = opt + if (input.length == 0) return null + await waitImmediate() + if (token.isCancellationRequested) return null + let words: Set = new Set() + let isIncomplete = await this.getWords(bufnr, opt, token, words) + return { + isIncomplete, + items: Array.from(words).map(word => ({ + word, + menu: this.menu + })) + } + } +} + +export function regist(sourceMap: Map, keywords: BufferSync): Disposable { + sourceMap.set('buffer', new Buffer(keywords)) + return Disposable.create(() => { + sourceMap.delete('buffer') + }) +} diff --git a/sources_non_forked/coc.nvim/src/sources/native/file.ts b/sources_non_forked/coc.nvim/src/sources/native/file.ts new file mode 100644 index 00000000..c9bbbc51 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/native/file.ts @@ -0,0 +1,160 @@ +'use strict' +import fs from 'fs' +import minimatch from 'minimatch' +import path from 'path' +import util from 'util' +import { Disposable } from 'vscode-languageserver-protocol' +import Source from '../source' +import { CompleteOption, CompleteResult, ISource, VimCompleteItem } from '../../types' +import { statAsync } from '../../util/fs' +import { byteSlice } from '../../util/string' +import { isWindows } from '../../util/platform' +import workspace from '../../workspace' +const logger = require('../../util/logger')('sources-file') +const pathRe = /(?:\.{0,2}|~|\$HOME|([\w]+)|[a-zA-Z]:|)(\/|\\+)(?:[\u4E00-\u9FA5\u00A0-\u024F\w .@()-]+(\/|\\+))*(?:[\u4E00-\u9FA5\u00A0-\u024F\w .@()-])*$/ + +interface PathOption { + pathstr: string + part: string + startcol: number + input: string +} + +export default class File extends Source { + constructor() { + super({ + name: 'file', + filepath: __filename + }) + } + + public get triggerCharacters(): string[] { + let characters = this.getConfig('triggerCharacters', []) + return isWindows ? characters : characters.filter(s => s != '\\') + } + + private resolveEnvVariables(str: string): string { + let replaced = str + // windows + replaced = replaced.replace(/%([^%]+)%/g, (_, n) => process.env[n]) + // linux and mac + replaced = replaced.replace( + /\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/gi, + (_, a, b) => process.env[a || b] + ) + return replaced + } + + private getPathOption(opt: CompleteOption): PathOption | null { + let { line, colnr } = opt + let part = byteSlice(line, 0, colnr - 1) + part = this.resolveEnvVariables(part) + if (!part || part.endsWith('//')) return null + let ms = part.match(pathRe) + if (ms && ms.length) { + const pathstr = workspace.expand(ms[0]) + let input = ms[0].match(/[^/\\]*$/)[0] + return { pathstr, part: ms[1], startcol: colnr - input.length - 1, input } + } + return null + } + + private async getFileItem(root: string, filename: string): Promise { + let f = path.join(root, filename) + let stat = await statAsync(f) + if (stat) { + let abbr = stat.isDirectory() ? filename + '/' : filename + let word = filename + return { word, abbr } + } + return null + } + + public filterFiles(files: string[]): string[] { + let ignoreHidden = this.getConfig('ignoreHidden', true) + let ignorePatterns = this.getConfig('ignorePatterns', []) + return files.filter(f => { + if (f == null) return false + if (ignoreHidden && f.startsWith(".")) return false + for (let p of ignorePatterns) { + if (minimatch(f, p, { dot: true })) return false + } + return true + }) + } + + public async getItemsFromRoot(pathstr: string, root: string): Promise { + let res = [] + let part = /[\\/]$/.test(pathstr) ? pathstr : path.dirname(pathstr) + let dir = path.isAbsolute(pathstr) ? part : path.join(root, part) + try { + let stat = await statAsync(dir) + if (stat && stat.isDirectory()) { + let files = await util.promisify(fs.readdir)(dir) + files = this.filterFiles(files) + let items = await Promise.all(files.map(filename => this.getFileItem(dir, filename))) + res = res.concat(items) + } + res = res.filter(item => item != null) + return res + } catch (e) { + logger.error(`Error on list files:`, e) + return res + } + } + + public get trimSameExts(): string[] { + return this.getConfig('trimSameExts', []) + } + + public async doComplete(opt: CompleteOption): Promise { + let { col, filepath } = opt + let option = this.getPathOption(opt) + if (!option) return null + let { pathstr, part, startcol, input } = option + if (startcol < opt.col) return null + let startPart = opt.col == startcol ? '' : byteSlice(opt.line, opt.col, startcol) + let dirname = path.dirname(filepath) + let ext = path.extname(path.basename(filepath)) + let cwd = await this.nvim.call('getcwd', []) + let root + if (pathstr.startsWith(".")) { + root = filepath ? path.dirname(filepath) : cwd + } else if (isWindows && /^\w+:/.test(pathstr)) { + root = /[\\/]$/.test(pathstr) ? pathstr : path.dirname(pathstr) + } else if (!isWindows && pathstr.startsWith("/")) { + root = pathstr.endsWith("/") ? pathstr : path.dirname(pathstr) + } else if (part) { + if (fs.existsSync(path.join(dirname, part))) { + root = dirname + } else if (fs.existsSync(path.join(cwd, part))) { + root = cwd + } + } else { + root = cwd + } + if (!root) return null + let items = await this.getItemsFromRoot(pathstr, root) + let trimExt = this.trimSameExts.includes(ext) + let first = input[0] + if (first && col == startcol) items = items.filter(o => o.word[0] === first) + return { + items: items.map(item => { + let ex = path.extname(item.word) + item.word = trimExt && ex === ext ? item.word.replace(ext, '') : item.word + return { + word: `${startPart}${item.word}`, + abbr: `${startPart}${item.abbr}`, + menu: this.menu + } + }) + } + } +} + +export function regist(sourceMap: Map): Disposable { + sourceMap.set('file', new File()) + return Disposable.create(() => { + sourceMap.delete('file') + }) +} diff --git a/sources_non_forked/coc.nvim/src/sources/source-language.ts b/sources_non_forked/coc.nvim/src/sources/source-language.ts new file mode 100644 index 00000000..6c6f69a1 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/source-language.ts @@ -0,0 +1,353 @@ +'use strict' +import { CancellationToken, CompletionItem, CompletionItemKind, CompletionTriggerKind, DocumentSelector, InsertReplaceEdit, InsertTextFormat, Position, Range, TextEdit } from 'vscode-languageserver-protocol' +import commands from '../commands' +import Document from '../model/document' +import { CompletionItemProvider } from '../provider' +import snippetManager from '../snippets/manager' +import { SnippetParser } from '../snippets/parser' +import { CompleteOption, CompleteResult, ExtendedCompleteItem, ISource, SourceType } from '../types' +import { fuzzyMatch, getCharCodes } from '../util/fuzzy' +import { byteIndex, byteLength, byteSlice, characterIndex } from '../util/string' +import window from '../window' +import workspace from '../workspace' +const logger = require('../util/logger')('source-language') + +export interface CompleteConfig { + labels: Map + snippetsSupport: boolean + defaultKindText: string + priority: number + detailMaxLength: number + detailField: string + invalidInsertCharacters: string[] + floatEnable: boolean +} + +export default class LanguageSource implements ISource { + public priority: number + public sourceType: SourceType.Service + private _enabled = true + private filetype: string + private completeItems: CompletionItem[] = [] + constructor( + public readonly name: string, + public readonly shortcut: string, + private provider: CompletionItemProvider, + public readonly documentSelector: DocumentSelector, + public readonly triggerCharacters: string[], + public readonly allCommitCharacters: string[], + priority: number | undefined, + private readonly completeConfig: CompleteConfig, + ) { + this.priority = typeof priority === 'number' ? priority : completeConfig.priority + } + + public get enable(): boolean { + return this._enabled + } + + public toggle(): void { + this._enabled = !this._enabled + } + + public shouldCommit?(item: ExtendedCompleteItem, character: string): boolean { + let completeItem = this.completeItems[item.index] + if (!completeItem) return false + let commitCharacters = [...this.allCommitCharacters, ...(completeItem.commitCharacters || [])] + return commitCharacters.includes(character) + } + + public async doComplete(opt: CompleteOption, token: CancellationToken): Promise { + let { triggerCharacter, input, bufnr } = opt + this.filetype = opt.filetype + this.completeItems = [] + let triggerKind: CompletionTriggerKind = this.getTriggerKind(opt) + let position = this.getPosition(opt) + let context: any = { triggerKind, option: opt } + if (triggerKind == CompletionTriggerKind.TriggerCharacter) context.triggerCharacter = triggerCharacter + let doc = workspace.getAttachedDocument(bufnr) + let result = await Promise.resolve(this.provider.provideCompletionItems(doc.textDocument, position, token, context)) + if (!result || token.isCancellationRequested) return null + let completeItems = Array.isArray(result) ? result : result.items + if (!completeItems || completeItems.length == 0) return null + this.completeItems = completeItems + let startcol = getStartColumn(opt.line, completeItems) + let option: CompleteOption = Object.assign({}, opt) + let prefix: string + let isIncomplete = typeof result['isIncomplete'] === 'boolean' ? result['isIncomplete'] : false + if (startcol == null && input.length > 0 && this.triggerCharacters.includes(opt.triggerCharacter)) { + if (!completeItems.every(item => (item.insertText ?? item.label).startsWith(opt.input))) { + startcol = opt.col + byteLength(opt.input) + } + } + if (startcol != null) { + prefix = startcol < option.col ? byteSlice(opt.line, startcol, option.col) : '' + option.col = startcol + } + let items: ExtendedCompleteItem[] = completeItems.map((o, index) => { + let item = this.convertVimCompleteItem(o, this.shortcut, option, prefix) + item.index = index + return item + }) + return { startcol, isIncomplete, items } + } + + public async onCompleteResolve(item: ExtendedCompleteItem, token: CancellationToken): Promise { + let { index } = item + let completeItem = this.completeItems[index] + if (!completeItem || item.resolved) return + let hasResolve = typeof this.provider.resolveCompletionItem === 'function' + if (hasResolve) { + let resolved = await Promise.resolve(this.provider.resolveCompletionItem(completeItem, token)) + if (token.isCancellationRequested || !resolved) return + Object.assign(completeItem, resolved) + } + if (typeof item.documentation === 'undefined') { + let { documentation, detail } = completeItem + if (!documentation && !detail) return + let docs = [] + if (detail && !item.detailShown && detail != item.word) { + detail = detail.replace(/\n\s*/g, ' ') + if (detail.length) { + let isText = /^[\w-\s.,\t\n]+$/.test(detail) + docs.push({ filetype: isText ? 'txt' : this.filetype, content: detail }) + } + } + if (documentation) { + if (typeof documentation == 'string') { + docs.push({ filetype: 'txt', content: documentation }) + } else if (documentation.value) { + docs.push({ + filetype: documentation.kind == 'markdown' ? 'markdown' : 'txt', + content: documentation.value + }) + } + } + item.resolved = true + item.documentation = docs + } + } + + public async onCompleteDone(vimItem: ExtendedCompleteItem, opt: CompleteOption): Promise { + let item = this.completeItems[vimItem.index] + if (!item) return + if (typeof vimItem.line === 'string') Object.assign(opt, { line: vimItem.line }) + let doc = workspace.getAttachedDocument(opt.bufnr) + await doc.patchChange(true) + let additionalEdits = Array.isArray(item.additionalTextEdits) && item.additionalTextEdits.length > 0 + if (additionalEdits) { + let shouldCancel = await snippetManager.editsInsideSnippet(item.additionalTextEdits) + if (shouldCancel) snippetManager.cancel() + } + let version = doc.version + let isSnippet = await this.applyTextEdit(doc, additionalEdits, item, vimItem.word, opt) + if (additionalEdits) { + // move cursor after edit + await doc.applyEdits(item.additionalTextEdits, doc.version != version, !isSnippet) + if (isSnippet) await snippetManager.selectCurrentPlaceholder() + } + if (item.command) { + if (commands.has(item.command.command)) { + await commands.execute(item.command) + } else { + logger.warn(`Command "${item.command.command}" not registered to coc.nvim`) + } + } + } + + private async applyTextEdit(doc: Document, additionalEdits: boolean, item: CompletionItem, word: string, option: CompleteOption): Promise { + let { line, linenr, colnr, col } = option + let pos = await window.getCursorPosition() + if (pos.line != linenr - 1) return + let { textEdit } = item + let currline = doc.getline(linenr - 1) + // before CompleteDone + let beginIdx = characterIndex(line, colnr - 1) + if (!textEdit && item.insertText) { + textEdit = { + range: Range.create(pos.line, characterIndex(line, col), pos.line, beginIdx), + newText: item.insertText + } + } + if (!textEdit) return false + let newText = textEdit.newText + let range = InsertReplaceEdit.is(textEdit) ? textEdit.replace : textEdit.range + // adjust range by indent + let n = fixIndent(line, currline, range) + if (n) beginIdx += n + // attempt to fix range from textEdit, range should include trigger position + if (range.end.character < beginIdx) range.end.character = beginIdx + // fix range by count cursor moved to replace insernt word on complete done. + if (pos.character > beginIdx) range.end.character += pos.character - beginIdx + let isSnippet = item.insertTextFormat === InsertTextFormat.Snippet + if (isSnippet && this.completeConfig.snippetsSupport === false) { + // could be wrong, but maybe best we can do. + isSnippet = false + newText = word + } + if (isSnippet) { + let opts = item.data?.ultisnip === true ? {} : item.data?.ultisnip + return await snippetManager.insertSnippet(newText, !additionalEdits, range, item.insertTextMode, opts ? opts : undefined) + } + await doc.applyEdits([TextEdit.replace(range, newText)], false, pos) + return false + } + + private getTriggerKind(opt: CompleteOption): CompletionTriggerKind { + let { triggerCharacters } = this + let isTrigger = triggerCharacters.includes(opt.triggerCharacter) + let triggerKind: CompletionTriggerKind = CompletionTriggerKind.Invoked + if (opt.triggerForInComplete) { + triggerKind = CompletionTriggerKind.TriggerForIncompleteCompletions + } else if (isTrigger) { + triggerKind = CompletionTriggerKind.TriggerCharacter + } + return triggerKind + } + + private convertVimCompleteItem(item: CompletionItem, shortcut: string, opt: CompleteOption, prefix: string): ExtendedCompleteItem { + let { detailMaxLength, invalidInsertCharacters, detailField, labels, defaultKindText } = this.completeConfig + let hasAdditionalEdit = item.additionalTextEdits != null && item.additionalTextEdits.length > 0 + let isSnippet = item.insertTextFormat === InsertTextFormat.Snippet || hasAdditionalEdit + let label = item.label.trim() + let obj: ExtendedCompleteItem = { + word: getWord(item, opt, invalidInsertCharacters), + abbr: label, + menu: `[${shortcut}]`, + kind: getKindString(item.kind, labels, defaultKindText), + sortText: item.sortText || null, + sourceScore: item['score'] || null, + filterText: item.filterText || label, + isSnippet, + dup: item.data && item.data.dup == 0 ? 0 : 1 + } + if (prefix) { + if (!obj.filterText.startsWith(prefix)) { + if (item.textEdit && fuzzyMatch(getCharCodes(prefix), item.textEdit.newText)) { + obj.filterText = item.textEdit.newText.replace(/\r?\n/g, '') + } + } + if (!item.textEdit && !obj.word.startsWith(prefix)) { + // fix possible wrong word + obj.word = `${prefix}${obj.word}` + } + } + if (item && item.detail && detailField != 'preview') { + let detail = item.detail.replace(/\n\s*/g, ' ') + if (byteLength(detail) < detailMaxLength) { + if (detailField == 'menu') { + obj.menu = `${detail} ${obj.menu}` + } else if (detailField == 'abbr') { + obj.abbr = `${obj.abbr} - ${detail}` + } + obj.detailShown = 1 + } + } + if (item.documentation) { + obj.info = typeof item.documentation == 'string' ? item.documentation : item.documentation.value + } else { + obj.info = '' + } + if (obj.word == '') obj.empty = 1 + obj.line = opt.line + if (item.kind == CompletionItemKind.Folder && !obj.abbr.endsWith('/')) { + obj.abbr = obj.abbr + '/' + } + if (item.preselect) obj.preselect = true + if (item.data?.optional) obj.abbr = obj.abbr + '?' + return obj + } + + private getPosition(opt: CompleteOption): Position { + let { line, linenr, colnr } = opt + let part = byteSlice(line, 0, colnr - 1) + return { + line: linenr - 1, + character: part.length + } + } +} + +/* + * Check new startcol by check start characters. + */ +export function getStartColumn(line: string, items: CompletionItem[]): number | undefined { + let first = items[0] + if (first.textEdit == null) return undefined + let range = InsertReplaceEdit.is(first.textEdit) ? first.textEdit.replace : first.textEdit.range + let { character } = range.start + for (let i = 1; i < Math.min(10, items.length); i++) { + let o = items[i] + if (!o.textEdit) return undefined + let r = InsertReplaceEdit.is(o.textEdit) ? o.textEdit.replace : o.textEdit.range + if (r.start.character !== character) return undefined + } + return byteIndex(line, character) +} + +export function getKindString(kind: CompletionItemKind, map: Map, defaultValue = ''): string { + return map.get(kind) || defaultValue +} + +export function getWord(item: CompletionItem, opt: CompleteOption, invalidInsertCharacters: string[]): string { + let { label, data, insertTextFormat, insertText, textEdit } = item + let word: string + let newText: string + if (data && typeof data.word === 'string') return data.word + if (textEdit) { + let range = InsertReplaceEdit.is(textEdit) ? textEdit.replace : textEdit.range + newText = textEdit.newText + if (range && range.start.line == range.end.line) { + let { line, col, colnr } = opt + let character = characterIndex(line, col) + if (range.start.character > character) { + let before = line.slice(character, range.start.character) + newText = before + newText + } else { + let start = line.slice(range.start.character, character) + if (start.length && newText.startsWith(start)) { + newText = newText.slice(start.length) + } + } + character = characterIndex(line, colnr - 1) + if (range.end.character > character) { + let end = line.slice(character, range.end.character) + if (newText.endsWith(end)) { + newText = newText.slice(0, - end.length) + } + } + } + } else if (insertText) { + newText = insertText + } + if (insertTextFormat == InsertTextFormat.Snippet && newText && newText.includes('$')) { + let parser = new SnippetParser() + let text = parser.text(newText) + word = text ? getValidWord(text, invalidInsertCharacters) : label + } else { + word = getValidWord(newText, invalidInsertCharacters) || label + } + return word || '' +} + +export function getValidWord(text: string, invalidChars: string[], start = 2): string { + if (!text) return '' + if (!invalidChars.length) return text + for (let i = start; i < text.length; i++) { + let c = text[i] + if (invalidChars.includes(c)) { + return text.slice(0, i) + } + } + return text +} + +export function fixIndent(line: string, currline: string, range: Range): number { + let oldIndent = line.match(/^\s*/)[0] + let newIndent = currline.match(/^\s*/)[0] + if (oldIndent == newIndent) return + let d = newIndent.length - oldIndent.length + range.start.character += d + range.end.character += d + return d +} diff --git a/sources_non_forked/coc.nvim/src/sources/source-vim.ts b/sources_non_forked/coc.nvim/src/sources/source-vim.ts new file mode 100644 index 00000000..11939df5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/source-vim.ts @@ -0,0 +1,98 @@ +'use strict' +import { CancellationToken } from 'vscode-languageserver-protocol' +import { CompleteOption, CompleteResult, ExtendedCompleteItem } from '../types' +import { fuzzyChar } from '../util/fuzzy' +import { byteSlice } from '../util/string' +import workspace from '../workspace' +import window from '../window' +import Source from './source' +const logger = require('../util/logger')('sources-source-vim') + +export default class VimSource extends Source { + + private async callOptionalFunc(fname: string, args: any[]): Promise { + let exists = this.optionalFns.includes(fname) + if (!exists) return null + let name = `coc#source#${this.name}#${fname}` + let res + try { + res = await this.nvim.call(name, args) + } catch (e) { + window.showMessage(`Vim error from source ${this.name}: ${e}`, 'error') + return null + } + return res + } + + public async shouldComplete(opt: CompleteOption): Promise { + let shouldRun = await super.shouldComplete(opt) + if (!shouldRun) return false + if (!this.optionalFns.includes('should_complete')) return true + let res = await this.callOptionalFunc('should_complete', [opt]) + return !!res + } + + public async refresh(): Promise { + await this.callOptionalFunc('refresh', []) + } + + public async onCompleteDone(item: ExtendedCompleteItem, _opt: CompleteOption): Promise { + if (!this.optionalFns.includes('on_complete')) return + await this.callOptionalFunc('on_complete', [item]) + } + + public onEnter(bufnr: number): void { + if (!this.optionalFns.includes('on_enter')) return + let doc = workspace.getDocument(bufnr) + if (!doc) return + let { filetypes } = this + if (filetypes && !filetypes.includes(doc.filetype)) return + this.callOptionalFunc('on_enter', [{ + bufnr, + uri: doc.uri, + languageId: doc.filetype + }]).logError() + } + + public async doComplete(opt: CompleteOption, token: CancellationToken): Promise { + let { col, input, line, colnr } = opt + let startcol: number | null = await this.callOptionalFunc('get_startcol', [opt]) + if (token.isCancellationRequested) return + if (startcol) { + if (startcol < 0) return null + startcol = Number(startcol) + // invalid startcol + if (isNaN(startcol) || startcol < 0) startcol = col + if (startcol !== col) { + input = byteSlice(line, startcol, colnr - 1) + opt = Object.assign({}, opt, { + col: startcol, + changed: col - startcol, + input + }) + } + } + let items: ExtendedCompleteItem[] = await this.nvim.callAsync('coc#util#do_complete', [this.name, opt]) + if (!items || items.length == 0 || token.isCancellationRequested) return null + if (this.firstMatch && input.length) { + let ch = input[0] + items = items.filter(item => { + let cfirst = item.filterText ? item.filterText[0] : item.word[0] + return fuzzyChar(ch, cfirst) + }) + } + items = items.map(item => { + if (typeof item == 'string') { + return { word: item, menu: this.menu, isSnippet: this.isSnippet } + } + let menu = item.menu ? item.menu + ' ' : '' + item.menu = `${menu}${this.menu}` + item.isSnippet = this.isSnippet + delete item.user_data + return item + }) + let res: CompleteResult = { items } + if (startcol) res.startcol = startcol + return res + } +} diff --git a/sources_non_forked/coc.nvim/src/sources/source.ts b/sources_non_forked/coc.nvim/src/sources/source.ts new file mode 100644 index 00000000..456ac4aa --- /dev/null +++ b/sources_non_forked/coc.nvim/src/sources/source.ts @@ -0,0 +1,151 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationToken } from 'vscode-languageserver-protocol' +import { CompleteOption, CompleteResult, ISource, SourceConfig, SourceType, VimCompleteItem } from '../types' +import { byteSlice } from '../util/string' +import workspace from '../workspace' +const logger = require('../util/logger')('sources-source') + +export default class Source implements ISource { + public readonly name: string + public readonly filepath: string + public readonly sourceType: SourceType + public readonly isSnippet: boolean + protected readonly nvim: Neovim + private _disabled = false + private defaults: any + constructor(option: SourceConfig) { + this.nvim = workspace.nvim + // readonly properties + this.name = option.name + this.filepath = option.filepath || '' + this.sourceType = option.sourceType || SourceType.Native + this.isSnippet = !!option.isSnippet + this.defaults = option + } + + /** + * Priority of source, higher priority makes items lower index. + */ + public get priority(): number { + return this.getConfig('priority', 1) + } + + /** + * When triggerOnly is true, not trigger completion on keyword character insert. + */ + public get triggerOnly(): boolean { + let triggerOnly = this.defaults['triggerOnly'] + if (typeof triggerOnly == 'boolean') return triggerOnly + if (!this.triggerCharacters && !this.triggerPatterns) return false + return Array.isArray(this.triggerPatterns) && this.triggerPatterns.length != 0 + } + + public get triggerCharacters(): string[] { + return this.getConfig('triggerCharacters', null) + } + + // exists opitonnal function names for remote source + public get optionalFns(): string[] { + return this.defaults['optionalFns'] || [] + } + + public get triggerPatterns(): RegExp[] | null { + let patterns = this.getConfig('triggerPatterns', null) + if (!patterns || patterns.length == 0) return null + return patterns.map(s => (typeof s === 'string') ? new RegExp(s + '$') : s) + } + + public get shortcut(): string { + let shortcut = this.getConfig('shortcut', '') + return shortcut ? shortcut : this.name.slice(0, 3) + } + + public get enable(): boolean { + if (this._disabled) return false + return this.getConfig('enable', true) + } + + public get filetypes(): string[] | null { + return this.getConfig('filetypes', null) + } + + public get disableSyntaxes(): string[] { + return this.getConfig('disableSyntaxes', []) + } + + public getConfig(key: string, defaultValue?: T): T | null { + let config = workspace.getConfiguration(`coc.source.${this.name}`) + defaultValue = this.defaults.hasOwnProperty(key) ? this.defaults[key] : defaultValue + return config.get(key, defaultValue) + } + + public toggle(): void { + this._disabled = !this._disabled + } + + public get firstMatch(): boolean { + return this.getConfig('firstMatch', true) + } + + public get menu(): string { + let { shortcut } = this + return shortcut ? `[${shortcut}]` : '' + } + + /** + * fix start column for new valid characters + * + * @protected + * @param {CompleteOption} opt + * @param {string[]} valids - valid charscters + * @returns {number} + */ + protected fixStartcol(opt: CompleteOption, valids: string[]): number { + let { col, input, line, bufnr } = opt + let start = byteSlice(line, 0, col) + let document = workspace.getDocument(bufnr) + if (!document) return col + let { chars } = document + for (let i = start.length - 1; i >= 0; i--) { + let c = start[i] + if (!chars.isKeywordChar(c) && !valids.includes(c)) { + break + } + input = `${c}${input}` + col = col - 1 + } + opt.col = col + opt.input = input + return col + } + + public async shouldComplete(opt: CompleteOption): Promise { + let { disableSyntaxes } = this + if (opt.synname && disableSyntaxes && disableSyntaxes.length) { + let synname = (opt.synname || '').toLowerCase() + if (disableSyntaxes.findIndex(s => synname.includes(s.toLowerCase())) !== -1) { + return false + } + } + let fn = this.defaults['shouldComplete'] + if (typeof fn === 'function') return await Promise.resolve(fn.call(this, opt)) + return true + } + + public async refresh(): Promise { + let fn = this.defaults['refresh'] + if (typeof fn === 'function') await Promise.resolve(fn.call(this)) + } + + public async onCompleteDone(item: VimCompleteItem, opt: CompleteOption): Promise { + let fn = this.defaults['onCompleteDone'] + if (typeof fn === 'function') await Promise.resolve(fn.call(this, item, opt)) + } + + public async doComplete(opt: CompleteOption, token: CancellationToken): Promise { + let fn = this.defaults['doComplete'] + if (typeof fn === 'function') return await Promise.resolve(fn.call(this, opt, token)) + return null + } +} diff --git a/sources_non_forked/coc.nvim/src/tree/BasicDataProvider.ts b/sources_non_forked/coc.nvim/src/tree/BasicDataProvider.ts new file mode 100644 index 00000000..e29f8faf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/tree/BasicDataProvider.ts @@ -0,0 +1,262 @@ +'use strict' +import { v4 as uuid } from 'uuid' +import { CancellationToken, MarkupContent, Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import commandsManager from '../commands' +import { ProviderResult } from '../provider' +import { disposeAll } from '../util' +import { TreeDataProvider, TreeItemAction } from './index' +import { TreeItem, TreeItemCollapsibleState, TreeItemIcon, TreeItemLabel } from './TreeItem' + +export interface TreeNode { + label: string + key?: string + tooltip?: string | MarkupContent + description?: string + deprecated?: boolean + icon?: TreeItemIcon + children?: this[] +} + +export interface ProviderOptions { + provideData: () => ProviderResult + expandLevel?: number + onDispose?: () => void + handleClick?: (item: T) => ProviderResult + resolveIcon?: (item: T) => TreeItemIcon | undefined + resolveItem?: (item: TreeItem, element: T, token: CancellationToken) => ProviderResult + resolveActions?(item: TreeItem, element: T): ProviderResult[]> +} + +function isIcon(obj: any): obj is TreeItemIcon { + if (!obj) return false + return typeof obj.text === 'string' && typeof obj.hlGroup === 'string' +} + +/** + * Check label and key, children not checked. + */ +function sameTreeNode(one: T, two: T): boolean { + if (one.label === two.label + && one.deprecated === two.deprecated + && one.key === two.key) { + return true + } + return false +} + +/** + * Check changes of nodes array, children not checked. + */ +function sameTreeNodes(one: T[], two: T[]): boolean { + if (one.length !== two.length) return false + return one.every((v, idx) => sameTreeNode(v, two[idx])) +} + +/** + * Tree data provider for resolved tree with children. + * Use update() to update data. + */ +export default class BasicDataProvider implements TreeDataProvider { + private disposables: Disposable[] = [] + private invokeCommand: string + private data: T[] | undefined + // only fired for change of exists TreeNode + private _onDidChangeTreeData = new Emitter() + public onDidChangeTreeData: Event = this._onDidChangeTreeData.event + public resolveActions: (item: TreeItem, element: T) => ProviderResult[]> + // data is shared with TreeView + constructor(private opts: ProviderOptions) { + this.invokeCommand = `_invoke_${uuid()}` + this.disposables.push(commandsManager.registerCommand(this.invokeCommand, async (node: T) => { + if (typeof opts.handleClick === 'function') { + await opts.handleClick(node) + } else { + console.error('Handler not found') + } + }, null, true)) + if (typeof opts.resolveActions === 'function') { + this.resolveActions = opts.resolveActions.bind(this) + } + } + + private iterate(node: T, parentNode: T | undefined, level: number, fn: (node: T, parentNode: T | undefined, level: number) => void | boolean): void | boolean { + let res = fn(node, parentNode, level) + if (res === false) return false + if (Array.isArray(node.children)) { + for (let element of node.children) { + let res = this.iterate(element, node, level + 1, fn) + if (res === false) return false + } + } + return res + } + + /** + * Change old array to new nodes in place, keep old reference when possible. + */ + private updateNodes(old: T[], data: T[], parentNode: T | undefined, fireEvent = true): void { + let sameNodes = sameTreeNodes(old, data) + const applyNode = (previous: T, curr: T, fireEvent: boolean): void => { + let changed = false + for (let key of Object.keys(curr)) { + if (['children', 'key'].includes(key)) continue + previous[key] = curr[key] + } + if (previous.children?.length && !curr.children?.length) { + // removed children + delete previous.children + changed = true + } + if (!previous.children?.length && curr.children?.length) { + // new children + previous.children = curr.children + changed = true + } + if (changed) { + if (fireEvent) this._onDidChangeTreeData.fire(previous) + return + } + if (previous.children?.length && curr.children?.length) { + this.updateNodes(previous.children, curr.children, previous, fireEvent) + } + } + if (sameNodes) { + for (let i = 0; i < old.length; i++) { + applyNode(old[i], data[i], fireEvent) + } + } else { + let oldNodes = old.splice(0, old.length) + let used: Set = new Set() + for (let i = 0; i < data.length; i++) { + let curr = data[i] + let findIndex: number + if (curr.key) { + findIndex = oldNodes.findIndex((o, i) => !used.has(i) && o.key == curr.key) + } else { + findIndex = oldNodes.findIndex((o, i) => !used.has(i) && o.label == curr.label) + } + if (findIndex === -1) { + old[i] = curr + } else { + used.add(findIndex) + let previous = oldNodes[findIndex] + applyNode(previous, curr, false) + old[i] = previous + } + } + if (fireEvent) { + this._onDidChangeTreeData.fire(parentNode) + } + } + } + + /** + * Update with new data, fires change event when necessary. + */ + public update(data: T[], reset?: boolean): ReadonlyArray { + if (!this.data) return + if (reset) { + this.data = data || [] + this._onDidChangeTreeData.fire(undefined) + } else { + this.updateNodes(this.data, data || [], undefined) + } + return this.data + } + + public getTreeItem(node: T): TreeItem { + let label: string | TreeItemLabel = node.label + let { expandLevel } = this.opts + let item: TreeItem + if (!node.children?.length) { + item = new TreeItem(label) + } else { + if (expandLevel && expandLevel > 0) { + let level = this.getLevel(node) + let state = level && level <= expandLevel ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed + item = new TreeItem(label, state) + } else { + item = new TreeItem(label, TreeItemCollapsibleState.Collapsed) + } + } + item.description = node.description + if (node.deprecated) item.deprecated = true + if (node.tooltip) item.tooltip = node.tooltip + if (isIcon(node.icon)) { + item.icon = node.icon + } else if (typeof this.opts.resolveIcon === 'function') { + let res = this.opts.resolveIcon(node) + if (res) item.icon = res + } + return item + } + + public async getChildren(element?: T): Promise { + if (element) return element.children || [] + if (this.data) return this.data + let data = await Promise.resolve(this.opts.provideData()) + if (!Array.isArray(data)) throw new Error(`Unable to fetch data`) + this.data = data + return data + } + + /** + * Use reference check + */ + public getParent(element: T): T | undefined { + if (!this.data) return undefined + let find: T + for (let item of this.data) { + let res = this.iterate(item, null, 0, (node, parentNode) => { + if (node === element) { + find = parentNode + return false + } + }) + if (res === false) break + } + return find + } + + private getLevel(element: T): number { + if (!this.data) return undefined + let level = 0 + for (let item of this.data) { + let res = this.iterate(item, null, 1, (node, _parentNode, l) => { + if (node === element) { + level = l + return false + } + }) + if (res === false) break + } + return level + } + + /** + * Resolve command and tooltip + */ + public async resolveTreeItem(item: TreeItem, element: T, token: CancellationToken): Promise { + if (typeof this.opts.resolveItem === 'function') { + let res = await Promise.resolve(this.opts.resolveItem(item, element, token)) + if (res) Object.assign(item, res) + } + if (!item.command) { + item.command = { + title: `invoke ${element.label}`, + command: this.invokeCommand, + arguments: [element] + } + } + return item + } + + public dispose(): void { + this.data = [] + this._onDidChangeTreeData.dispose() + if (typeof this.opts.onDispose === 'function') { + this.opts.onDispose() + } + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/tree/TreeItem.ts b/sources_non_forked/coc.nvim/src/tree/TreeItem.ts new file mode 100644 index 00000000..792ec309 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/tree/TreeItem.ts @@ -0,0 +1,63 @@ +'use strict' +import { Command, MarkupContent } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import path from 'path' + +export interface TreeItemLabel { + label: string + highlights?: [number, number][] +} + +// eslint-disable-next-line no-redeclare +export namespace TreeItemLabel { + export function is(obj: any): obj is TreeItemLabel { + return typeof obj.label == 'string' + } +} + +export interface TreeItemIcon { + text: string + hlGroup: string +} + +/** + * Collapsible state of the tree item + */ +export enum TreeItemCollapsibleState { + /** + * Determines an item can be neither collapsed nor expanded. Implies it has no children. + */ + None = 0, + /** + * Determines an item is collapsed + */ + Collapsed = 1, + /** + * Determines an item is expanded + */ + Expanded = 2 +} + +export class TreeItem { + public label: string | TreeItemLabel + public id?: string + public description?: string + public icon?: TreeItemIcon + public resourceUri?: URI + public command?: Command + public tooltip?: string | MarkupContent + public deprecated?: boolean + + constructor(label: string | TreeItemLabel, collapsibleState?: TreeItemCollapsibleState) + // eslint-disable-next-line @typescript-eslint/unified-signatures + constructor(resourceUri: URI, collapsibleState?: TreeItemCollapsibleState) + constructor(label: string | TreeItemLabel | URI, public collapsibleState: TreeItemCollapsibleState = TreeItemCollapsibleState.None) { + if (URI.isUri(label)) { + this.resourceUri = label + this.label = path.basename(label.path) + this.id = label.toString() + } else { + this.label = label + } + } +} diff --git a/sources_non_forked/coc.nvim/src/tree/TreeView.ts b/sources_non_forked/coc.nvim/src/tree/TreeView.ts new file mode 100644 index 00000000..7cce33a5 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/tree/TreeView.ts @@ -0,0 +1,1031 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import { CancellationTokenSource, Disposable, Emitter, Event, MarkupContent, MarkupKind, Range } from 'vscode-languageserver-protocol' +import commandManager from '../commands' +import events from '../events' +import FloatFactory from '../model/floatFactory' +import { ConfigurationChangeEvent, Documentation, HighlightItem, LocalMode } from '../types' +import { disposeAll } from '../util' +import { groupPositions, hasMatch, positions, score } from '../util/fzy' +import { Mutex } from '../util/mutex' +import { equals } from '../util/object' +import { byteLength, byteSlice } from '../util/string' +import window from '../window' +import workspace from '../workspace' +import Filter, { sessionKey } from './filter' +import { LineState, TreeDataProvider, TreeItemData, TreeView, TreeViewExpansionEvent, TreeViewKeys, TreeViewOptions, TreeViewSelectionChangeEvent, TreeViewVisibilityChangeEvent } from './index' +import { TreeItem, TreeItemCollapsibleState, TreeItemLabel } from './TreeItem' +const logger = require('../util/logger')('BasicTreeView') +const highlightNamespace = 'tree' +const signOffset = 3000 +let globalId = 1 + +interface TreeViewConfig { + openedIcon: string + closedIcon: string +} + +interface RenderedItem { + line: string + level: number + node: T +} + +interface ExtendedItem extends RenderedItem { + index: number + score: number + highlights: HighlightItem[] +} + +/** + * Basic TreeView implementation + */ +export default class BasicTreeView implements TreeView { + private bufnr: number | undefined + private bufname: string | undefined + private winid: number | undefined + private config: TreeViewConfig + private keys: TreeViewKeys + private _targetBufnr: number + private _targetWinId: number + private _targetTabId: number | undefined + private _creating: boolean + private _selection: T[] = [] + private _onDispose = new Emitter() + private _onDidRefrash = new Emitter() + private _onDidExpandElement = new Emitter>() + private _onDidCollapseElement = new Emitter>() + private _onDidChangeSelection = new Emitter>() + private _onDidChangeVisibility = new Emitter() + public readonly onDidRefrash: Event = this._onDidRefrash.event + public readonly onDispose: Event = this._onDispose.event + public readonly onDidExpandElement: Event> = this._onDidExpandElement.event + public readonly onDidCollapseElement: Event> = this._onDidCollapseElement.event + public readonly onDidChangeSelection: Event> = this._onDidChangeSelection.event + public readonly onDidChangeVisibility: Event = this._onDidChangeVisibility.event + public message: string | undefined + public title: string + public description: string | undefined + private retryTimers = 0 + private renderedItems: RenderedItem[] = [] + public provider: TreeDataProvider + private nodesMap: Map = new Map() + private mutex: Mutex = new Mutex() + private timer: NodeJS.Timer + private disposables: Disposable[] = [] + private tooltipFactory: FloatFactory + private resolveTokenSource: CancellationTokenSource | undefined + private lineState: LineState = { titleCount: 0, messageCount: 0 } + private filter: Filter | undefined + private filterText: string | undefined + private itemsToFilter: T[] | undefined + private readonly leafIndent: boolean + private readonly winfixwidth: boolean + private readonly autoWidth: boolean + constructor(private viewId: string, private opts: TreeViewOptions) { + this.loadConfiguration() + workspace.onDidChangeConfiguration(this.loadConfiguration, this, this.disposables) + if (opts.enableFilter) { + this.filter = new Filter(this.nvim, [this.keys.selectNext, this.keys.selectPrevious, this.keys.invoke]) + } + this.tooltipFactory = new FloatFactory(workspace.nvim) + this.provider = opts.treeDataProvider + this.leafIndent = opts.disableLeafIndent !== true + this.winfixwidth = opts.winfixwidth !== false + this.autoWidth = opts.autoWidth === true + let message: string | undefined + Object.defineProperty(this, 'message', { + set: (msg: string | undefined) => { + message = msg ? msg.replace(/\r?\n/g, ' ') : undefined + this.updateHeadLines() + }, + get: () => { + return message + } + }) + let title = viewId.replace(/\r?\n/g, ' ') + Object.defineProperty(this, 'title', { + set: (newTitle: string) => { + title = newTitle ? newTitle.replace(/\r?\n/g, ' ') : undefined + this.updateHeadLines() + }, + get: () => { + return title + } + }) + let description: string | undefined + Object.defineProperty(this, 'description', { + set: (desc: string | undefined) => { + description = desc ? desc.replace(/\r?\n/g, ' ') : undefined + this.updateHeadLines() + }, + get: () => { + return description + } + }) + let filterText: string | undefined + Object.defineProperty(this, 'filterText', { + set: (text: string | undefined) => { + let { titleCount, messageCount } = this.lineState + let start = titleCount + messageCount + if (text != null) { + let highlights: HighlightItem[] = [{ + lnum: start, + colStart: byteLength(text), + colEnd: byteLength(text) + 1, + hlGroup: 'Cursor' + }] + this.renderedItems = [] + this.updateUI([text + ' '], highlights, start, -1, true) + void this.doFilter(text) + } else if (filterText != null) { + this.updateUI([], [], start, start + 1) + } + filterText = text + }, + get: () => { + return filterText + } + }) + if (this.provider.onDidChangeTreeData) { + this.provider.onDidChangeTreeData(this.onDataChange, this, this.disposables) + } + events.on('BufUnload', bufnr => { + if (bufnr != this.bufnr) return + let isVisible = this.winid != null + this.winid = undefined + this.bufnr = undefined + if (isVisible) this._onDidChangeVisibility.fire({ visible: false }) + this.dispose() + }, null, this.disposables) + events.on('WinClosed', winid => { + if (this.winid == winid) { + this.winid = undefined + this._onDidChangeVisibility.fire({ visible: false }) + } + }, null, this.disposables) + // switched to another buffer + events.on('BufWinLeave', (bufnr: number, winid: number) => { + if (bufnr == this.bufnr && winid == this.winid) { + this.winid = undefined + this._onDidChangeVisibility.fire({ visible: false }) + } + }, null, this.disposables) + window.onDidTabClose(id => { + if (this._targetTabId === id) { + this.dispose() + } + }, null, this.disposables) + events.on('CursorHold', async bufnr => { + if (bufnr != this.bufnr) return + await this.onHover() + }, null, this.disposables) + events.on(['CursorMoved', 'BufEnter'], () => { + this.cancelResolve() + }, null, this.disposables) + events.on('WinEnter', winid => { + if (winid != this.windowId || !this.filter?.activated) return + let buf = this.nvim.createBuffer(this.bufnr) + let line = this.startLnum - 1 + let len = this.filterText ? this.filterText.length : 0 + let range = Range.create(line, len, line, len + 1) + buf.highlightRanges(highlightNamespace, 'Cursor', [range]) + this.nvim.call('coc#prompt#start_prompt', [sessionKey], true) + this.redraw() + }, null, this.disposables) + events.on('WinLeave', winid => { + if (winid != this.windowId || !this.filter?.activated) return + let buf = this.nvim.createBuffer(this.bufnr) + this.nvim.call('coc#prompt#stop_prompt', [sessionKey], true) + buf.clearNamespace(highlightNamespace, this.startLnum - 1, this.startLnum) + }, null, this.disposables) + this.disposables.push(this._onDidChangeVisibility, this._onDidChangeSelection, this._onDidCollapseElement, this._onDidExpandElement) + if (this.filter) { + this.filter.onDidExit(node => { + this.nodesMap.clear() + this.filterText = undefined + this.itemsToFilter = undefined + if (node && typeof this.provider.getParent === 'function') { + this.renderedItems = [] + void this.reveal(node, { focus: true }) + } else { + this.clearSelection() + void this.render() + } + }) + this.filter.onDidUpdate(text => { + this.filterText = text + }) + this.filter.onDidKeyPress(async character => { + let items = this.renderedItems + if (!items?.length) return + let curr = this.selection[0] + if (character == '' || character == this.keys.selectPrevious) { + let idx = items.findIndex(o => o.node == curr) + let index = idx == -1 || idx == 0 ? items.length - 1 : idx - 1 + let node = items[index]?.node + if (node) this.selectItem(node, true) + } + if (character == '' || character == this.keys.selectNext) { + let idx = items.findIndex(o => o.node == curr) + let index = idx == -1 || idx == items.length - 1 ? 0 : idx + 1 + let node = items[index]?.node + if (node) this.selectItem(node, true) + } + if (character == '' || character == this.keys.invoke) { + if (!curr) return + await this.invokeCommand(curr) + this.filter.deactivate(curr) + } + }) + } + } + + public get windowId(): number | undefined { + return this.winid + } + + public get targetTabnr(): number | undefined { + return window.getTabNumber(this._targetTabId) + } + + public get targetWinId(): number | undefined { + return this._targetWinId + } + + public get targetBufnr(): number | undefined { + return this._targetBufnr + } + + private get startLnum(): number { + let filterCount = this.filterText == null ? 0 : 1 + return this.lineState.messageCount + this.lineState.titleCount + filterCount + } + + private get nvim(): Neovim { + return workspace.nvim + } + + private loadConfiguration(e?: ConfigurationChangeEvent): void { + if (!e || e.affectsConfiguration('tree')) { + let config = workspace.getConfiguration('tree') + this.config = { + openedIcon: config.get('openedIcon', ' '), + closedIcon: config.get('closedIcon', ' ') + } + this.keys = { + close: config.get('key.close'), + invoke: config.get('key.invoke'), + toggle: config.get('key.toggle'), + actions: config.get('key.actions'), + collapseAll: config.get('key.collapseAll'), + toggleSelection: config.get('key.toggleSelection'), + activeFilter: config.get('key.activeFilter'), + selectNext: config.get('key.selectNext'), + selectPrevious: config.get('key.selectPrevious') + } + if (e) { + void this.render() + } + } + } + + private async doFilter(text: string): Promise { + let items: ExtendedItem[] = [] + let index = 0 + let release = await this.mutex.acquire() + try { + if (!this.itemsToFilter) { + let itemsToFilter: T[] = [] + const addNodes = async (nodes: T[]): Promise => { + for (let n of nodes) { + itemsToFilter.push(n) + let arr = await Promise.resolve(this.provider.getChildren(n)) + if (arr?.length) await addNodes(arr) + } + } + let nodes = await Promise.resolve(this.provider.getChildren()) + await addNodes(nodes) + this.itemsToFilter = itemsToFilter + } + for (let n of this.itemsToFilter) { + let item = await this.getTreeItem(n) + let label = TreeItemLabel.is(item.label) ? item.label.label : item.label + if (!text || hasMatch(text, label)) { + let idxs = text ? positions(text, label) : [] + item.collapsibleState = TreeItemCollapsibleState.None + item.label = { label, highlights: text ? groupPositions(idxs) : [] } + let { line, highlights } = this.getRenderedLine(item, index, 0) + items.push({ + level: 0, + node: n, + line, + index, + score: text ? score(text, label) : 0, + highlights + }) + index += 1 + } + } + items.sort((a, b) => { + if (a.score != b.score) return b.score - a.score + return a.index - b.index + }) + let lnum = this.startLnum + let highlights: HighlightItem[] = [] + let renderedItems = this.renderedItems = items.map((o, idx) => { + highlights.push(...o.highlights.map(h => { + h.lnum = lnum + idx + return h + })) + delete o.index + delete o.score + delete o.highlights + return o + }) + this.updateUI(renderedItems.map(o => o.line), highlights, lnum, -1, true) + if (renderedItems.length) { + this.selectItem(renderedItems[0].node, true) + } else { + this.clearSelection() + } + this.redraw() + release() + } catch (e) { + release() + logger.error(`Error on tree filter:`, e) + } + } + + private async onHover(): Promise { + let { nvim } = this + let lnum = await nvim.call('line', ['.']) + let element = this.getElementByLnum(lnum - 1) + if (!element) return + let obj = this.nodesMap.get(element) + if (!obj) return + let item = obj.item + if (!obj.resolved) { + item = await this.resolveItem(element, item) + if (!item) return + } + if (!item.tooltip || !this.bufnr) return + let isMarkdown = MarkupContent.is(item.tooltip) && item.tooltip.kind == MarkupKind.Markdown + let doc: Documentation = { + filetype: isMarkdown ? 'markdown' : 'txt', + content: MarkupContent.is(item.tooltip) ? item.tooltip.value : item.tooltip + } + await this.tooltipFactory.show([doc], { modes: ['n'] }) + } + + private async onClick(element: T): Promise { + let { nvim } = this + let [line, col] = await nvim.eval(`[getline('.'),col('.')]`) as [string, number] + let pre = byteSlice(line, 0, col - 1) + let character = line[pre.length] + if (!character) return + let { openedIcon, closedIcon } = this.config + if (/^\s*$/.test(pre) && [openedIcon, closedIcon].includes(character)) { + await this.toggleExpand(element) + } else { + await this.invokeCommand(element) + } + } + + private async invokeCommand(element: T): Promise { + let obj = this.nodesMap.get(element) + if (!obj) return + this.selectItem(element) + let item = obj.item + if (!item.command) { + item = await this.resolveItem(element, item) + if (!item) return + } + if (!item.command) throw new Error(`Failed to resolve command from TreeItem.`) + await commandManager.execute(item.command) + } + + private async invokeActions(element: T): Promise { + this.selectItem(element) + if (typeof this.provider.resolveActions !== 'function') { + await window.showWarningMessage('No actions') + return + } + let obj = this.nodesMap.get(element) + let actions = await Promise.resolve(this.provider.resolveActions(obj.item, element)) + if (!actions || actions.length == 0) { + await window.showWarningMessage('No actions available') + return + } + let keys = actions.map(o => o.title) + let res = await window.showMenuPicker(keys, 'Choose action') + if (res == -1) return + await Promise.resolve(actions[res].handler(element)) + } + + private async onDataChange(node: T | undefined): Promise { + if (this.filter?.activated) { + this.itemsToFilter = undefined + await this.doFilter(this.filterText) + return + } + this.clearSelection() + if (!node) { + await this.render() + return + } + let release = await this.mutex.acquire() + try { + let items = this.renderedItems + let idx = items.findIndex(o => o.node === node) + if (idx != -1 && this.bufnr) { + let obj = items[idx] + let level = obj.level + let removeCount = 0 + for (let i = idx; i < items.length; i++) { + let o = items[i] + if (i == idx || o && o.level > level) { + removeCount += 1 + } + } + let appendItems: RenderedItem[] = [] + let highlights: HighlightItem[] = [] + let start = idx + this.startLnum + await this.appendTreeNode(node, level, start, appendItems, highlights) + items.splice(idx, removeCount, ...appendItems) + this.updateUI(appendItems.map(o => o.line), highlights, start, start + removeCount) + } + release() + } catch (e) { + let errMsg = `Error on tree refresh: ${e}` + logger.error(errMsg, e) + this.nvim.errWriteLine('[coc.nvim] ' + errMsg) + release() + } + } + + private async resolveItem(element: T, item: TreeItem): Promise { + if (typeof this.provider.resolveTreeItem === 'function') { + let tokenSource = this.resolveTokenSource = new CancellationTokenSource() + let token = tokenSource.token + item = await Promise.resolve(this.provider.resolveTreeItem(item, element, token)) + tokenSource.dispose() + this.resolveTokenSource = undefined + if (token.isCancellationRequested) return undefined + } + this.nodesMap.set(element, { item, resolved: true }) + return item + } + + public get visible(): boolean { + if (!this.bufnr) return false + return this.winid != null + } + + public get valid(): boolean { + return typeof this.bufnr === 'number' + } + + public get selection(): T[] { + return this._selection.slice() + } + + public async checkLines(): Promise { + if (!this.bufnr) return + let buf = this.nvim.createBuffer(this.bufnr) + let curr = await buf.lines + let { titleCount, messageCount } = this.lineState + curr = curr.slice(titleCount + messageCount) + let lines = this.renderedItems.map(o => o.line) + return equals(curr, lines) + } + + /** + * Expand/collapse TreeItem. + */ + private async toggleExpand(element: T): Promise { + let o = this.nodesMap.get(element) + if (!o) return + let treeItem = o.item + let lnum = this.getItemLnum(element) + let nodeIdx = lnum - this.startLnum + let obj = this.renderedItems[nodeIdx] + if (!obj || treeItem.collapsibleState == TreeItemCollapsibleState.None) { + if (typeof this.provider.getParent === 'function') { + let node = await Promise.resolve(this.provider.getParent(element)) + if (node) { + await this.toggleExpand(node) + this.focusItem(node) + } + } + return + } + // remove lines + let removeCount = 0 + if (treeItem.collapsibleState == TreeItemCollapsibleState.Expanded) { + let level = obj.level + for (let i = nodeIdx + 1; i < this.renderedItems.length; i++) { + let o = this.renderedItems[i] + if (!o || o.level <= level) break + removeCount += 1 + } + treeItem.collapsibleState = TreeItemCollapsibleState.Collapsed + } else if (treeItem.collapsibleState == TreeItemCollapsibleState.Collapsed) { + treeItem.collapsibleState = TreeItemCollapsibleState.Expanded + } + let newItems: RenderedItem[] = [] + let newHighlights: HighlightItem[] = [] + await this.appendTreeNode(obj.node, obj.level, lnum, newItems, newHighlights) + this.renderedItems.splice(nodeIdx, removeCount + 1, ...newItems) + this.updateUI(newItems.map(o => o.line), newHighlights, lnum, lnum + removeCount + 1) + this.refreshSigns() + if (treeItem.collapsibleState == TreeItemCollapsibleState.Collapsed) { + this._onDidCollapseElement.fire({ element }) + } else { + this._onDidExpandElement.fire({ element }) + } + } + + private toggleSelection(element: T): void { + let idx = this._selection.findIndex(o => o === element) + if (idx !== -1) { + this.unselectItem(idx) + } else { + this.selectItem(element) + } + } + + private clearSelection(): void { + if (!this.bufnr) return + this._selection = [] + let buf = this.nvim.createBuffer(this.bufnr) + buf.unplaceSign({ group: 'CocTree' }) + this._onDidChangeSelection.fire({ selection: [] }) + } + + private selectItem(item: T, forceSingle?: boolean, noRedraw?: boolean): void { + let { nvim } = this + if (!this.bufnr || !workspace.env.sign) return + let row = this.getItemLnum(item) + if (row == null) return + let buf = nvim.createBuffer(this.bufnr) + let exists = this._selection.includes(item) + if (!this.opts.canSelectMany || forceSingle) { + this._selection = [item] + } else if (!exists) { + this._selection.push(item) + } + nvim.pauseNotification() + if (!this.opts.canSelectMany || forceSingle) { + buf.unplaceSign({ group: 'CocTree' }) + } + nvim.call('coc#compat#execute', [this.winid, `normal! ${row + 1}G`], true) + buf.placeSign({ id: signOffset + row, lnum: row + 1, name: 'CocTreeSelected', group: 'CocTree' }) + if (!noRedraw) this.redraw() + nvim.resumeNotification(false, true) + if (!exists) this._onDidChangeSelection.fire({ selection: this._selection }) + } + + private unselectItem(idx: number): void { + let item = this._selection[idx] + let row = this.getItemLnum(item) + if (row == null || !this.bufnr || !workspace.env.sign) return + this._selection.splice(idx, 1) + let buf = this.nvim.createBuffer(this.bufnr) + buf.unplaceSign({ group: 'CocTree', id: signOffset + row }) + this._onDidChangeSelection.fire({ selection: this._selection }) + } + + public focusItem(element: T): void { + if (!this.winid) return + let lnum = this.getItemLnum(element) + if (lnum == null) return + this.nvim.call('coc#compat#execute', [this.winid, `exe ${lnum + 1}`], true) + } + + private getElementByLnum(lnum: number): T | undefined { + let item = this.renderedItems[lnum - this.startLnum] + return item ? item.node : undefined + } + + private getItemLnum(item: T): number | undefined { + let idx = this.renderedItems.findIndex(o => o.node === item) + if (idx == -1) return undefined + return this.startLnum + idx + } + + private async getTreeItem(element: T): Promise { + let exists: TreeItem + let resolved = false + let obj = this.nodesMap.get(element) + if (obj != null) { + exists = obj.item + resolved = obj.resolved + } + let item = await Promise.resolve(this.provider.getTreeItem(element)) + if (item.id && !exists) { + for (let obj of this.nodesMap.values()) { + if (obj.item.id === item.id) { + resolved = obj.resolved + exists = obj.item + break + } + } + } + if (exists + && exists.collapsibleState != TreeItemCollapsibleState.None + && item.collapsibleState != TreeItemCollapsibleState.None) { + item.collapsibleState = exists.collapsibleState + } + this.nodesMap.set(element, { item, resolved }) + return item + } + + private getRenderedLine(treeItem: TreeItem, lnum: number, level: number): { line: string, highlights: HighlightItem[] } { + let { openedIcon, closedIcon } = this.config + const highlights: HighlightItem[] = [] + const { label, deprecated, description } = treeItem + let prefix = ' '.repeat(level) + const addHighlight = (text: string, hlGroup: string) => { + let colStart = byteLength(prefix) + highlights.push({ + lnum, + hlGroup, + colStart, + colEnd: colStart + byteLength(text), + }) + } + switch (treeItem.collapsibleState) { + case TreeItemCollapsibleState.Expanded: { + addHighlight(openedIcon, 'CocTreeOpenClose') + prefix += openedIcon + ' ' + break + } + case TreeItemCollapsibleState.Collapsed: { + addHighlight(closedIcon, 'CocTreeOpenClose') + prefix += closedIcon + ' ' + break + } + default: + prefix += this.leafIndent ? ' ' : '' + } + if (treeItem.icon) { + let { text, hlGroup } = treeItem.icon + addHighlight(text, hlGroup) + prefix += text + ' ' + } + if (TreeItemLabel.is(label) && Array.isArray(label.highlights)) { + let colStart = byteLength(prefix) + for (let o of label.highlights) { + highlights.push({ + lnum, + hlGroup: 'CocSearch', + colStart: colStart + o[0], + colEnd: colStart + o[1] + }) + } + } + let labelText = typeof label === 'string' ? label : label.label + if (deprecated) { + addHighlight(labelText, 'CocDeprecatedHighlight') + } + prefix += labelText + if (description && description.indexOf('\n') == -1) { + prefix += ' ' + addHighlight(description, 'CocTreeDescription') + prefix += description + } + return { line: prefix, highlights } + } + + private async appendTreeNode(element: T, level: number, lnum: number, items: RenderedItem[], highlights: HighlightItem[]): Promise { + let takes = 1 + let treeItem = await this.getTreeItem(element) + let res = this.getRenderedLine(treeItem, lnum, level) + highlights.push(...res.highlights) + items.push({ level, line: res.line, node: element }) + if (treeItem.collapsibleState == TreeItemCollapsibleState.Expanded) { + let l = level + 1 + let children = await Promise.resolve(this.provider.getChildren(element)) || [] + for (let el of children) { + let n = await this.appendTreeNode(el, l, lnum + takes, items, highlights) + takes = takes + n + } + } + return takes + } + + private updateUI(lines: string[], highlights: HighlightItem[], start = 0, end = -1, noRedraw = false): void { + if (!this.bufnr) return + let { nvim, winid } = this + let buf = nvim.createBuffer(this.bufnr) + nvim.pauseNotification() + buf.setOption('modifiable', true, true) + void buf.setLines(lines, { start, end, strictIndexing: false }, true) + if (this.autoWidth) this.nvim.call('coc#window#adjust_width', [winid], true) + if (highlights.length) { + let highlightEnd = end == -1 ? -1 : start + lines.length + nvim.call('coc#highlight#update_highlights', [this.bufnr, highlightNamespace, highlights, start, highlightEnd], true) + } + buf.setOption('modifiable', false, true) + if (!noRedraw) this.redraw() + nvim.resumeNotification(false, true) + } + + public async reveal(element: T, options: { select?: boolean; focus?: boolean; expand?: number | boolean } = {}): Promise { + if (this.filter?.activated) return + let isShown = this.getItemLnum(element) != null + let { select, focus, expand } = options + let curr = element + if (typeof this.provider.getParent !== 'function') { + throw new Error('missing getParent function from provider for reveal.') + } + if (!isShown) { + while (curr) { + let parentNode = await Promise.resolve(this.provider.getParent(curr)) + if (parentNode) { + let item = await this.getTreeItem(parentNode) + item.collapsibleState = TreeItemCollapsibleState.Expanded + curr = parentNode + } else { + break + } + } + } + if (expand) { + let item = await this.getTreeItem(element) + if (item.collapsibleState == TreeItemCollapsibleState.None) return + item.collapsibleState = TreeItemCollapsibleState.Expanded + if (typeof expand === 'number' && expand > 1) { + let curr = Math.min(expand, 2) + let nodes = await Promise.resolve(this.provider.getChildren(element)) + while (nodes?.length > 0) { + let arr: T[] = [] + for (let n of nodes) { + let item = await this.getTreeItem(n) + if (item.collapsibleState == TreeItemCollapsibleState.None) continue + item.collapsibleState = TreeItemCollapsibleState.Expanded + if (curr > 1) { + let res = await Promise.resolve(this.provider.getChildren(n)) + arr.push(...res) + } + } + nodes = arr + curr = curr - 1 + } + } + } + if (!isShown || expand) { + await this.render() + } + if (select !== false) this.selectItem(element) + if (focus) this.focusItem(element) + } + + private updateHeadLines(initialize = false): void { + let { titleCount, messageCount } = this.lineState + let end = initialize ? -1 : titleCount + messageCount + let lines: string[] = [] + let highlights: HighlightItem[] = [] + try { + if (this.message) { + highlights.push({ hlGroup: 'MoreMsg', colStart: 0, colEnd: byteLength(this.message), lnum: 0 }) + lines.push(this.message) + lines.push('') + } + if (this.title) { + highlights.push({ hlGroup: 'CocTreeTitle', colStart: 0, colEnd: byteLength(this.title), lnum: lines.length }) + if (this.description) { + let colStart = byteLength(this.title) + 1 + highlights.push({ hlGroup: 'Comment', colStart, colEnd: colStart + byteLength(this.description), lnum: lines.length }) + } + lines.push(this.title + (this.description ? ' ' + this.description : '')) + } + this.lineState.messageCount = this.message ? 2 : 0 + this.lineState.titleCount = this.title ? 1 : 0 + this.updateUI(lines, highlights, 0, end) + if (!initialize) { + this.refreshSigns() + } + } catch (e) { + this.nvim.echoError(e) + } + } + + /** + * Update signs after collapse/expand or head change + */ + private refreshSigns(): void { + let { selection, nvim, bufnr } = this + if (!selection.length || !bufnr || !workspace.env.sign) return + let buf = nvim.createBuffer(bufnr) + nvim.pauseNotification() + buf.unplaceSign({ group: 'CocTree' }) + for (let n of selection) { + let row = this.getItemLnum(n) + if (row == null) continue + buf.placeSign({ id: signOffset + row, lnum: row + 1, name: 'CocTreeSelected', group: 'CocTree' }) + } + nvim.resumeNotification(false, true) + } + + // Render all tree items + public async render(): Promise { + if (!this.bufnr) return + let release = await this.mutex.acquire() + try { + let lines: string[] = [] + let highlights: HighlightItem[] = [] + let { startLnum } = this + let nodes = await Promise.resolve(this.provider.getChildren()) + let level = 0 + let lnum = startLnum + let renderedItems: RenderedItem[] = [] + if (!nodes?.length) { + this.message = 'No results' + } else { + if (this.message == 'No results') this.message = '' + for (let node of nodes) { + let n = await this.appendTreeNode(node, level, lnum, renderedItems, highlights) + lnum += n + } + } + lines.push(...renderedItems.map(o => o.line)) + this.renderedItems = renderedItems + let delta = this.startLnum - startLnum + if (delta) highlights.forEach(o => o.lnum = o.lnum + delta) + this.updateUI(lines, highlights, this.startLnum, -1) + this._onDidRefrash.fire() + this.retryTimers = 0 + release() + } catch (e) { + this.renderedItems = [] + this.nodesMap.clear() + this.lineState = { titleCount: 0, messageCount: 1 } + release() + let errMsg = `${e}`.replace(/\r?\n/g, ' ') + this.updateUI([errMsg], [{ hlGroup: 'WarningMsg', colStart: 0, colEnd: byteLength(errMsg), lnum: 0 }]) + if (this.retryTimers == 5) return + this.timer = setTimeout(() => { + this.retryTimers = this.retryTimers + 1 + void this.render() + }, 500) + } + } + + public async show(splitCommand = 'belowright 30vs'): Promise { + if (this._creating) return false + this._creating = true + let { nvim } = this + let oldWinId = this.winid + let [bufnr, windowId, tabnr, loaded] = await nvim.eval(`[bufnr("%"),win_getid(),tabpagenr(),bufloaded(${this.bufnr || -1})]`) as [number, number, number, number] + this._targetBufnr = bufnr + this._targetWinId = windowId + this._targetTabId = window.getTabId(tabnr) + if (!loaded) this.bufnr = undefined + let winid = await nvim.call('coc#window#find', ['cocViewId', this.viewId]) + if (this.bufnr && winid !== -1) { + let bufnr = await nvim.call('winbufnr', [winid]) + if (bufnr == this.bufnr) { + this._creating = false + return + } + } + nvim.pauseNotification() + if (this.bufnr) { + if (winid != -1) { + nvim.call('win_gotoid', [winid], true) + nvim.command(`b ${this.bufnr}`, true) + } else { + nvim.command(`silent keepalt ${splitCommand} ${this.bufname}`, true) + } + } else { + let id = globalId + globalId = globalId + 1 + if (winid != -1) { + nvim.call('win_gotoid', [winid], true) + nvim.command(`silent edit +setl\\ buftype=nofile CocTree${id}`, true) + } else { + nvim.command(`silent keepalt ${splitCommand} +setl\\ buftype=nofile CocTree${id}`, true) + } + } + nvim.command(`setl bufhidden=${this.opts.bufhidden || 'wipe'} nolist nonumber norelativenumber foldcolumn=0`, true) + nvim.command(`setl signcolumn=${this.opts.canSelectMany ? 'yes' : 'no'}${this.winfixwidth ? ' winfixwidth' : ''}`, true) + nvim.command('setl nocursorline nobuflisted wrap undolevels=-1 filetype=coctree nomodifiable noswapfile', true) + nvim.command(`let w:cocViewId = "${this.viewId.replace(/"/g, '\\"')}"`, true) + nvim.call('bufname', ['%'], true) + nvim.call('bufnr', ['%'], true) + nvim.call('win_getid', [], true) + let res = await nvim.resumeNotification() + if (!this.bufnr) this.registerKeymaps() + let arr = res[0] + this.bufname = arr[arr.length - 3] as string + this.bufnr = arr[arr.length - 2] as number + this.winid = arr[arr.length - 1] as number + if (!oldWinId) this._onDidChangeVisibility.fire({ visible: true }) + if (oldWinId && oldWinId !== this.winid) { + nvim.call('coc#window#close', [oldWinId], true) + } + this._creating = false + this.updateHeadLines(true) + void this.render() + return true + } + + public registerLocalKeymap(mode: LocalMode, key: string, fn: (element: T | undefined) => Promise, notify = false): void { + this.disposables.push(workspace.registerLocalKeymap(mode, key, async () => { + let lnum = await this.nvim.call('line', ['.']) + let element = this.getElementByLnum(lnum - 1) + await Promise.resolve(fn(element)) + }, notify)) + } + + private registerKeymaps(): void { + let { toggleSelection, actions, close, invoke, toggle, collapseAll, activeFilter } = this.keys + let { nvim } = this + const regist = (mode: LocalMode, key: string, fn: (element: T | undefined) => Promise) => { + this.registerLocalKeymap(mode, key, async (element: T | undefined) => { + if (element && !this.nodesMap.has(element)) return + await Promise.resolve(fn(element)) + }, true) + } + this.disposables.push(workspace.registerLocalKeymap('n', '', () => { + nvim.call('win_gotoid', [this._targetWinId], true) + }, true)) + regist('n', '', async element => { + if (element) await this.onClick(element) + }) + this.filter && activeFilter && regist('n', activeFilter, async () => { + this.nvim.command(`exe ${this.startLnum}`, true) + this.filter.active() + this.filterText = '' + }) + toggleSelection && regist('n', toggleSelection, async element => { + if (element) this.toggleSelection(element) + }) + invoke && regist('n', invoke, async element => { + if (element) await this.invokeCommand(element) + }) + actions && regist('n', actions, async element => { + if (element) await this.invokeActions(element) + }) + toggle && regist('n', toggle, async element => { + if (element) await this.toggleExpand(element) + }) + collapseAll && regist('n', collapseAll, async () => { + for (let obj of this.nodesMap.values()) { + let item = obj.item + if (item.collapsibleState == TreeItemCollapsibleState.Expanded) { + item.collapsibleState = TreeItemCollapsibleState.Collapsed + } + } + await this.render() + }) + close && regist('n', close, async () => { + this.hide() + }) + } + + private hide(): void { + let { winid } = this + if (!winid) return + this.nvim.call('coc#window#close', [winid], true) + this.redraw() + this.winid = undefined + this._onDidChangeVisibility.fire({ visible: false }) + } + + private redraw(): void { + if (workspace.isVim || this.filter?.activated) { + this.nvim.command('redraw', true) + } + } + + private cancelResolve(): void { + if (this.resolveTokenSource) { + this.resolveTokenSource.cancel() + this.resolveTokenSource = undefined + } + } + + public dispose(): void { + if (!this.provider) return + if (this.timer) clearTimeout(this.timer) + this.cancelResolve() + let { bufnr } = this + if (this.winid) this._onDidChangeVisibility.fire({ visible: false }) + if (bufnr) this.nvim.command(`silent! bwipeout! ${bufnr}`, true) + this.winid = undefined + this.bufnr = undefined + this.filter?.dispose() + this._selection = [] + this.itemsToFilter = [] + this.tooltipFactory.dispose() + this.renderedItems = [] + this.nodesMap.clear() + this.provider = undefined + this._onDispose.fire() + this._onDispose.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/tree/filter.ts b/sources_non_forked/coc.nvim/src/tree/filter.ts new file mode 100644 index 00000000..3ccb703e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/tree/filter.ts @@ -0,0 +1,96 @@ +'use strict' +import events from '../events' +import { Neovim } from '@chemzqm/neovim' +import { Disposable, Emitter, Event } from 'vscode-languageserver-protocol' +import { disposeAll } from '../util' +export const sessionKey = 'filter' + +export default class Filter { + private _activated = false + private text: string + private history: string[] = [] + private disposables: Disposable[] = [] + private readonly _onDidUpdate = new Emitter() + private readonly _onDidExit = new Emitter() + private readonly _onDidKeyPress = new Emitter() + public readonly onDidKeyPress: Event = this._onDidKeyPress.event + public readonly onDidUpdate: Event = this._onDidUpdate.event + public readonly onDidExit: Event = this._onDidExit.event + constructor(private nvim: Neovim, keys: string[]) { + this.text = '' + events.on('InputChar', (session, character) => { + if (session !== sessionKey || !this._activated) return + if (!keys.includes(character)) { + if (character.length == 1) { + this.text = this.text + character + this._onDidUpdate.fire(this.text) + return + } + if (character == '' || character == '') { + this.text = this.text.slice(0, -1) + this._onDidUpdate.fire(this.text) + return + } + if (character == '') { + this.text = '' + this._onDidUpdate.fire(this.text) + return + } + if (character == '') { + let idx = this.history.indexOf(this.text) + let text = this.history[idx + 1] || this.history[0] + if (text) { + this.text = text + this._onDidUpdate.fire(this.text) + } + return + } + if (character == '') { + let idx = this.history.indexOf(this.text) + let text = this.history[idx - 1] || this.history[this.history.length - 1] + if (text) { + this.text = text + this._onDidUpdate.fire(this.text) + } + } + if (character == '' || character == '') { + this.deactivate() + return + } + } + this._onDidKeyPress.fire(character) + }, null, this.disposables) + } + + public active(): void { + if (this._activated) return + this._activated = true + this.text = '' + this.nvim.call('coc#prompt#start_prompt', [sessionKey], true) + } + + public deactivate(node?: T): void { + if (!this._activated) return + this.nvim.call('coc#prompt#stop_prompt', [sessionKey], true) + this._activated = false + let { text } = this + this.text = '' + this._onDidExit.fire(node) + if (text && !this.history.includes(text)) { + this.history.push(text) + } + } + + public get activated(): boolean { + return this._activated + } + + public dispose(): void { + this.deactivate() + this.history = [] + this._onDidKeyPress.dispose() + this._onDidUpdate.dispose() + this._onDidExit.dispose() + disposeAll(this.disposables) + } +} diff --git a/sources_non_forked/coc.nvim/src/tree/index.ts b/sources_non_forked/coc.nvim/src/tree/index.ts new file mode 100644 index 00000000..82cb9d77 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/tree/index.ts @@ -0,0 +1,258 @@ +'use strict' +import { Disposable, Event, CancellationToken } from 'vscode-languageserver-protocol' +import { ProviderResult } from '../provider' +import { TreeItem, TreeItemIcon, TreeItemCollapsibleState } from './TreeItem' + +export { TreeItem, TreeItemIcon, TreeItemCollapsibleState } + +export interface TreeItemAction { + /** + * Label text in menu. + */ + title: string + handler: (item: T) => ProviderResult +} + +export interface LineState { + /** + * Line count used by message + */ + messageCount: number + /** + * Line count used by title + */ + titleCount: number +} + +export interface TreeViewKeys { + invoke: string + toggle: string + actions: string + collapseAll: string + toggleSelection: string + close: string + activeFilter: string + selectNext: string + selectPrevious: string +} + +export interface TreeItemData { + item: TreeItem + resolved: boolean +} + +/** + * Options for creating a {@link TreeView} + */ +export interface TreeViewOptions { + /** + * bufhidden option for TreeView, default to 'wipe' + */ + bufhidden?: 'hide' | 'unload' | 'delete' | 'wipe' + /** + * Increase width to avoid wrapped lines. + */ + autoWidth?: boolean + /** + * Fixed width for window, default to true + */ + winfixwidth?: boolean + /** + * Enable filter feature, default to false + */ + enableFilter?: boolean + /** + * Disable indent of leaves without children, default to false + */ + disableLeafIndent?: boolean + /** + * A data provider that provides tree data. + */ + treeDataProvider: TreeDataProvider + /** + * Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree, + * the first argument to the command is the tree item that the command was executed on and the second argument is an + * array containing all selected tree items. + */ + canSelectMany?: boolean +} + +/** + * The event that is fired when an element in the {@link TreeView} is expanded or collapsed + */ +export interface TreeViewExpansionEvent { + /** + * Element that is expanded or collapsed. + */ + readonly element: T +} + +/** + * The event that is fired when there is a change in {@link TreeView.selection tree view's selection} + */ +export interface TreeViewSelectionChangeEvent { + readonly selection: T[] +} + +/** + * The event that is fired when there is a change in {@link TreeView.visible tree view's visibility} + */ +export interface TreeViewVisibilityChangeEvent { + readonly visible: boolean +} + +/** + * Represents a Tree view + */ +export interface TreeView extends Disposable { + + /** + * Event that is fired when an element is expanded + */ + readonly onDidExpandElement: Event> + + /** + * Event that is fired when an element is collapsed + */ + readonly onDidCollapseElement: Event> + + /** + * Currently selected elements. + */ + readonly selection: T[] + + /** + * Event that is fired when the {@link TreeView.selection selection} has changed + */ + readonly onDidChangeSelection: Event> + + /** + * `true` if the {@link TreeView tree view} is visible otherwise `false`. + * + * **NOTE:** is `true` when TreeView visible on other tab. + */ + readonly visible: boolean + + /** + * Window id used by TreeView. + */ + readonly windowId: number | undefined + + /** + * Event that is fired when {@link TreeView.visible visibility} has changed + */ + readonly onDidChangeVisibility: Event + + /** + * An optional human-readable message that will be rendered in the view. + * Setting the message to null, undefined, or empty string will remove the message from the view. + */ + message?: string + + /** + * The tree view title is initially taken from viewId of TreeView + * Changes to the title property will be properly reflected in the UI in the title of the view. + */ + title?: string + + /** + * An optional human-readable description which is rendered less prominently in the title of the view. + * Setting the title description to null, undefined, or empty string will remove the description from the view. + */ + description?: string + + /** + * Reveals the given element in the tree view. + * If the tree view is not visible then the tree view is shown and element is revealed. + * + * By default revealed element is selected. + * In order to not to select, set the option `select` to `false`. + * In order to focus, set the option `focus` to `true`. + * In order to expand the revealed element, set the option `expand` to `true`. To expand recursively set `expand` to the number of levels to expand. + * **NOTE:** You can expand only to 3 levels maximum. + * + * **NOTE:** The {@link TreeDataProvider} that the `TreeView` {@link window.createTreeView is registered with} with must implement {@link TreeDataProvider.getParent getParent} method to access this API. + */ + reveal(element: T, options?: { select?: boolean, focus?: boolean, expand?: boolean | number }): Thenable + + /** + * Create tree view in new window, does nothing when it's visible. + * + * **NOTE:** + * **NOTE:** TreeView with same viewId in current tab would be disposed. + * + * @param splitCommand The command to open TreeView window, default to 'belowright 30vs' + */ + show(splitCommand?: string): Promise +} + +/** + * A data provider that provides tree data + */ +export interface TreeDataProvider { + /** + * An optional event to signal that an element or root has changed. + * This will trigger the view to update the changed element/root and its children recursively (if shown). + * To signal that root has changed, do not pass any argument or pass `undefined` or `null`. + */ + onDidChangeTreeData?: Event + + /** + * Get {@link TreeItem} representation of the `element` + * + * @param element The element for which {@link TreeItem} representation is asked for. + * @return {@link TreeItem} representation of the element + */ + getTreeItem(element: T): TreeItem | Thenable + + /** + * Get the children of `element` or root if no element is passed. + * + * @param element The element from which the provider gets children. Can be `undefined`. + * @return Children of `element` or root if no element is passed. + */ + getChildren(element?: T): ProviderResult + + /** + * Optional method to return the parent of `element`. + * Return `null` or `undefined` if `element` is a child of root. + * + * **NOTE:** This method should be implemented in order to access {@link TreeView.reveal reveal} API. + * + * @param element The element for which the parent has to be returned. + * @return Parent of `element`. + */ + getParent?(element: T): ProviderResult + + /** + * Called on hover to resolve the {@link TreeItem.tooltip TreeItem} property if it is undefined. + * Called on tree item click/open to resolve the {@link TreeItem.command TreeItem} property if it is undefined. + * Only properties that were undefined can be resolved in `resolveTreeItem`. + * Functionality may be expanded later to include being called to resolve other missing + * properties on selection and/or on open. + * + * Will only ever be called once per TreeItem. + * + * onDidChangeTreeData should not be triggered from within resolveTreeItem. + * + * *Note* that this function is called when tree items are already showing in the UI. + * Because of that, no property that changes the presentation (label, description, etc.) + * can be changed. + * + * @param item Undefined properties of `item` should be set then `item` should be returned. + * @param element The object associated with the TreeItem. + * @param token A cancellation token. + * @return The resolved tree item or a thenable that resolves to such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveTreeItem?(item: TreeItem, element: T, token: CancellationToken): ProviderResult + + /** + * Called with current element to resolve actions. + * Called when user press 'actions' key. + * + * @param item Resolved item. + * @param element The object under cursor. + */ + resolveActions?(item: TreeItem, element: T): ProviderResult[]> +} diff --git a/sources_non_forked/coc.nvim/src/types.ts b/sources_non_forked/coc.nvim/src/types.ts new file mode 100644 index 00000000..6a97975e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/types.ts @@ -0,0 +1,1153 @@ +'use strict' +// vim: set sw=2 ts=2 sts=2 et foldmarker={{,}} foldmethod=marker foldlevel=0 nofen: +import { Buffer, Neovim, Window } from '@chemzqm/neovim' +import { CancellationToken, CodeAction, CodeActionKind, CreateFile, CreateFileOptions, DeleteFile, DeleteFileOptions, Disposable, DocumentSelector, Event, FormattingOptions, Location, Position, Range, RenameFile, RenameFileOptions, SymbolKind, TextDocumentEdit, TextDocumentSaveReason, TextEdit, WorkspaceEdit, WorkspaceFolder } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import Configurations from './configuration' +import Document from './model/document' +import { ProviderResult, TextDocumentContentProvider } from './provider' + +declare global { + namespace NodeJS { + interface Global { + __TEST__?: boolean + } + } +} +export type Optional = Omit< + T, + K +> & + Partial> + +export interface Thenable { + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable + // eslint-disable-next-line @typescript-eslint/unified-signatures + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable +} + +export type ProviderName = 'rename' | 'onTypeEdit' | 'documentLink' | 'documentColor' + | 'foldingRange' | 'format' | 'codeAction' | 'workspaceSymbols' | 'formatRange' | 'formatOnType' + | 'hover' | 'signature' | 'documentSymbol' | 'documentHighlight' | 'definition' + | 'declaration' | 'typeDefinition' | 'reference' | 'implementation' + | 'codeLens' | 'selectionRange' | 'callHierarchy' | 'semanticTokens' | 'linkedEditing' + +export type LocalMode = 'n' | 'v' | 's' | 'x' + +export interface CurrentState { + doc: Document + winid: number + position: Position + // :h mode() + mode: string +} + +export interface BufferOption { + readonly bufnr: number + readonly eol: number + readonly size: number + readonly winid: number + readonly lines: null | string[] + readonly variables: { [key: string]: any } + readonly bufname: string + readonly fullpath: string + readonly buftype: string + readonly filetype: string + readonly iskeyword: string + readonly changedtick: number + readonly previewwindow: number + readonly indentkeys: string +} + +export interface HandlerDelegate { + checkProvier: (id: ProviderName, document: TextDocument) => void + withRequestToken: (name: string, fn: (token: CancellationToken) => Thenable, checkEmpty?: boolean) => Promise + getCurrentState: () => Promise + addDisposable: (disposable: Disposable) => void + getIcon(kind: SymbolKind): { text: string, hlGroup: string } + getCodeActions(doc: Document, range?: Range, only?: CodeActionKind[]): Promise + applyCodeAction(action: ExtendedCodeAction): Promise +} + +/* + * With providerId so it can be resolved. + */ +export interface ExtendedCodeAction extends CodeAction { + providerId: string +} + +export interface FileSystemWatcher extends Disposable { + ignoreCreateEvents: boolean + ignoreChangeEvents: boolean + ignoreDeleteEvents: boolean + onDidCreate: Event + onDidChange: Event + onDidDelete: Event +} + +export interface FloatConfig { + border?: boolean + rounded?: boolean + highlight?: string + title?: string + borderhighlight?: string + close?: boolean + maxHeight?: number + maxWidth?: number + winblend?: number + focusable?: boolean + shadow?: boolean +} + +export interface HighlightItemOption { + /** + * default to true + */ + combine?: boolean + /** + * default to false + */ + start_incl?: boolean + /** + * default to false + */ + end_incl?: boolean +} + +/** + * Represent a highlight that not cross lines + * all zero based. + */ +export interface HighlightItem extends HighlightItemOption { + lnum: number + hlGroup: string + /** + * 0 based start column. + */ + colStart: number + /** + * 0 based end column. + */ + colEnd: number +} + +export interface BufferSyncItem { + /** + * Called on buffer unload. + */ + dispose: () => void + /** + * Called on buffer change. + */ + onChange?(e: DidChangeTextDocumentParams): void +} + +export interface Env { + completeOpt: string + runtimepath: string + readonly guicursor: string + readonly tabCount: number + readonly mode: string + readonly apiversion: number + readonly floating: boolean + readonly sign: boolean + readonly extensionRoot: string + readonly globalExtensions: string[] + readonly workspaceFolders: string[] + readonly config: any + readonly pid: number + readonly columns: number + readonly lines: number + readonly pumevent: boolean + readonly cmdheight: number + readonly filetypeMap: { [index: string]: string } + readonly isVim: boolean + readonly isCygwin: boolean + readonly isMacvim: boolean + readonly isiTerm: boolean + readonly version: string + readonly locationlist: boolean + readonly progpath: string + readonly dialog: boolean + readonly textprop: boolean + readonly updateHighlight: boolean + readonly vimCommands: CommandConfig[] + readonly semanticHighlights: string[] +} + +export interface CommandConfig { + id: string + cmd: string + title?: string +} + +export interface EditerState { + document: TextDocument + position: Position +} + +/** + * An output channel is a container for readonly textual information. + * + * To get an instance of an `OutputChannel` use + * [createOutputChannel](#window.createOutputChannel). + */ +export interface OutputChannel { + + /** + * The human-readable name of this output channel. + */ + readonly name: string + + readonly content: string + /** + * Append the given value to the channel. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void + + /** + * Append the given value and a line feed character + * to the channel. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void + + /** + * Removes output from the channel. Latest `keep` lines will be remained. + */ + clear(keep?: number): void + + /** + * Reveal this channel in the UI. + * + * @param preserveFocus When `true` the channel will not take focus. + */ + show(preserveFocus?: boolean): void + + /** + * Hide this channel from the UI. + */ + hide(): void + + /** + * Dispose and free associated resources. + */ + dispose(): void +} + +export interface KeymapOption { + sync: boolean + cancel: boolean + silent: boolean + repeat: boolean +} + +export interface Autocmd { + pattern?: string + event: string | string[] + arglist?: string[] + request?: boolean + thisArg?: any + callback: Function +} + +export interface UltiSnippetOption { + regex?: string + context?: string + noPython?: boolean +} + +export interface IWorkspace { + readonly nvim: Neovim + readonly cwd: string + readonly root: string + readonly isVim: boolean + readonly isNvim: boolean + readonly filetypes: Set + readonly languageIds: Set + readonly pluginRoot: string + readonly completeOpt: string + readonly channelNames: string[] + readonly documents: Document[] + readonly configurations: Configurations + textDocuments: TextDocument[] + onDidOpenTextDocument: Event + onDidCloseTextDocument: Event + onDidChangeTextDocument: Event + onWillSaveTextDocument: Event + onDidSaveTextDocument: Event + onDidChangeConfiguration: Event + findUp(filename: string | string[]): Promise + getDocument(uri: number | string): Document + getFormatOptions(uri?: string): Promise + getConfigFile(target: ConfigurationTarget): string + applyEdit(edit: WorkspaceEdit): Promise + createFileSystemWatcher(globPattern: string, ignoreCreate?: boolean, ignoreChange?: boolean, ignoreDelete?: boolean): FileSystemWatcher + getConfiguration(section?: string, _resource?: string): WorkspaceConfiguration + registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable + getWorkspaceFolder(uri: string): WorkspaceFolder | undefined + getQuickfixItem(loc: Location, text?: string, type?: string): Promise + getQuickfixList(locations: Location[]): Promise> + getLine(uri: string, line: number): Promise + readFile(uri: string): Promise + jumpTo(uri: string, position: Position): Promise + createFile(filepath: string, opts?: CreateFileOptions): Promise + renameFile(oldPath: string, newPath: string, opts?: RenameFileOptions): Promise + deleteFile(filepath: string, opts?: DeleteFileOptions): Promise + openResource(uri: string): Promise + resolveModule(name: string): Promise + match(selector: DocumentSelector, document: TextDocument): number + runCommand(cmd: string, cwd?: string, timeout?: number): Promise + dispose(): void +} + +// window {{ +export type MsgTypes = 'error' | 'warning' | 'more' +export type HighlightItemResult = [string, number, number, number, number?] +export type HighlightItemDef = [string, number, number, number, number?, number?, number?] + +export interface HighlightDiff { + remove: number[] + removeMarkers: number[] + add: HighlightItemDef[] +} + +export interface StatusItemOption { + progress?: boolean +} + +export interface ScreenPosition { + row: number + col: number +} + +export interface OpenTerminalOption { + /** + * Cwd of terminal, default to result of |getcwd()| + */ + cwd?: string + /** + * Close terminal on job finish, default to true. + */ + autoclose?: boolean + /** + * Keep focus current window, default to false. + */ + keepfocus?: boolean + /** + * Position of terminal window, default to 'right'. + */ + position?: 'bottom' | 'right' +} + +export interface TerminalResult { + bufnr: number + success: boolean + content?: string +} +/** + * Value-object describing where and how progress should show. + */ +export interface ProgressOptions { + + /** + * A human-readable string which will be used to describe the + * operation. + */ + title?: string + + /** + * Controls if a cancel button should show to allow the user to + * cancel the long running operation. + */ + cancellable?: boolean + /** + * Extension or language-client id + */ + source?: string +} + +/** + * Represents an action that is shown with an information, warning, or + * error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * @see [showWarningMessage](#window.showWarningMessage) + * @see [showErrorMessage](#window.showErrorMessage) + */ +export interface MessageItem { + + /** + * A short title like 'Retry', 'Open Log' etc. + */ + title: string + + /** + * A hint for modal dialogs that the item should be triggered + * when the user cancels the dialog (e.g. by pressing the ESC + * key). + * + * Note: this option is ignored for non-modal messages. + * Note: not used by coc.nvim for now. + */ + isCloseAffordance?: boolean +} + +export type MenuOption = { + title?: string, + content?: string + /** + * Create and highlight shortcut characters. + */ + shortcuts?: boolean + /** + * Position of menu picker, default to 'cursor' + */ + position?: 'cursor' | 'center' + /** + * Border highlight that override user configuration. + */ + borderhighlight?: string +} | string +// }} + +// vim {{ +export interface LocationListItem { + bufnr: number + lnum: number + end_lnum: number + col: number + end_col: number + text: string + type: string +} + +export interface QuickfixItem { + uri?: string + module?: string + range?: Range + text?: string + type?: string + filename?: string + bufnr?: number + lnum?: number + end_lnum?: number + col?: number + end_col?: number + valid?: boolean + nr?: number +} + +/** + * Options to configure the behavior of the quick pick UI. + */ +export interface QuickPickOptions { + + /** + * An optional string that represents the title of the quick pick. + */ + title?: string + + /** + * An optional flag to include the description when filtering the picks. + */ + matchOnDescription?: boolean + + /** + * An optional flag to make the picker accept multiple selections, if true the result is an array of picks. + */ + canPickMany?: boolean +} + +/** + * Represents an item that can be selected from + * a list of items. + */ +export interface QuickPickItem { + /** + * A human-readable string which is rendered prominent + */ + label: string + /** + * A human-readable string which is rendered less prominent in the same line + */ + description?: string + + /** + * Optional flag indicating if this item is picked initially. + */ + picked?: boolean +} +// }} + +// Enums{{ +export enum PatternType { + Buffer, + LanguageServer, + Global, +} + +export enum SourceType { + Native, + Remote, + Service, +} + +export enum MessageLevel { + More, + Warning, + Error +} + +export enum ConfigurationTarget { + Global, + User, + Workspace +} + +export enum ServiceStat { + Initial, + Starting, + StartFailed, + Running, + Stopping, + Stopped, +} + +export enum FileType { + /** + * The file type is unknown. + */ + Unknown = 0, + /** + * A regular file. + */ + File = 1, + /** + * A directory. + */ + Directory = 2, + /** + * A symbolic link to a file. + */ + SymbolicLink = 64 +} +// }} + +// TextDocument {{ +/** + * An event that is fired when a [document](#TextDocument) will be saved. + * + * To make modifications to the document before it is being saved, call the + * [`waitUntil`](#TextDocumentWillSaveEvent.waitUntil)-function with a thenable + * that resolves to an array of [text edits](#TextEdit). + */ +export interface TextDocumentWillSaveEvent { + + /** + * The document that will be saved. + */ + document: TextDocument + + /** + * The reason why save was triggered. + */ + reason: TextDocumentSaveReason + + /** + * Allows to pause the event loop and to apply [pre-save-edits](#TextEdit). + * Edits of subsequent calls to this function will be applied in order. The + * edits will be *ignored* if concurrent modifications of the document happened. + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * @param thenable A thenable that resolves to [pre-save-edits](#TextEdit). + */ + waitUntil(thenable: Thenable): void +} + +export type DocumentChange = TextDocumentEdit | CreateFile | RenameFile | DeleteFile + +export interface LinesChange { + uri: string + lnum: number + oldLines: ReadonlyArray + newLines: ReadonlyArray +} + +/** + * An event describing a change to a text document. + */ +export interface TextDocumentContentChange { + /** + * The range of the document that changed. + */ + range: Range + /** + * The optional length of the range that got replaced. + * + * @deprecated use range instead. + */ + rangeLength?: number + /** + * The new text for the provided range. + */ + text: string +} + +export interface DidChangeTextDocumentParams { + /** + * The document that did change. The version number points + * to the version after all provided content changes have + * been applied. + */ + readonly textDocument: { + version: number + uri: string + } + /** + * The actual content changes. The content changes describe single state changes + * to the document. So if there are two content changes c1 (at array index 0) and + * c2 (at array index 1) for a document in state S then c1 moves the document from + * S to S' and c2 from S' to S''. So c1 is computed on the state S and c2 is computed + * on the state S'. + */ + readonly contentChanges: ReadonlyArray + /** + * Buffer number of document. + */ + readonly bufnr: number + /** + * Original content before change + */ + readonly original: string + /** + * Changed lines + */ + readonly originalLines: ReadonlyArray +} +// }} + +// Completion {{ +export interface Documentation { + filetype: string + content: string + highlights?: HighlightItem[] + active?: [number, number] +} + +export interface VimCompleteItem { + word: string + abbr?: string + menu?: string + info?: string + kind?: string + icase?: number + equal?: number + dup?: number + empty?: number + user_data?: string +} + +export interface CompleteDoneItem { + readonly word: string + readonly user_data?: string + // if there's ClosePum event just received. + close?: boolean + // already cancelled by completion.stop() + closed?: boolean +} + +export interface ExtendedCompleteItem extends VimCompleteItem { + score?: number + sortText?: string + sourceScore?: number + filterText?: string + isSnippet?: boolean + source?: string + matchScore?: number + priority?: number + preselect?: boolean + signature?: string + localBonus?: number + index?: number + // used for preview + documentation?: Documentation[] + detailShown?: number + resolved?: boolean + // saved line for apply TextEdit + line?: string + recentScore?: number +} + +export interface CompleteResult { + items: ExtendedCompleteItem[] + isIncomplete?: boolean + startcol?: number + priority?: number +} + +// option on complete & should_complete +// what need change? line, col, input, colnr, changedtick +// word = '', triggerForInComplete = false +export interface CompleteOption { + readonly bufnr: number + readonly line: string + col: number + input: string + filetype: string + readonly filepath: string + readonly word: string + // cursor position + colnr: number + synname?: string + readonly linenr: number + readonly source?: string + readonly blacklist: string[] + readonly disabled: ReadonlyArray + readonly changedtick: number + readonly indentkeys: string + readonly triggerCharacter?: string + triggerForInComplete?: boolean +} + +export interface SourceStat { + name: string + priority: number + triggerCharacters: string[] + type: string + shortcut: string + filepath: string + disabled: boolean + filetypes: string[] +} + +export type SourceConfig = Omit, 'shortcut' | 'priority' | 'triggerOnly' | 'triggerCharacters' | 'triggerPatterns' | 'enable' | 'filetypes' | 'disableSyntaxes'> + +export interface ISource { + name: string + enable?: boolean + shortcut?: string + priority?: number + sourceType?: SourceType + optionalFns?: string[] + triggerCharacters?: string[] + triggerOnly?: boolean + triggerPatterns?: RegExp[] + disableSyntaxes?: string[] + isSnippet?: boolean + filetypes?: string[] + documentSelector?: DocumentSelector + filepath?: string + firstMatch?: boolean + refresh?(): Promise + toggle?(): void + onEnter?(bufnr: number): void + shouldComplete?(opt: CompleteOption): Promise + doComplete(opt: CompleteOption, token: CancellationToken): ProviderResult + onCompleteResolve?(item: ExtendedCompleteItem, token: CancellationToken): ProviderResult | void + onCompleteDone?(item: ExtendedCompleteItem, opt: CompleteOption): ProviderResult + shouldCommit?(item: ExtendedCompleteItem, character: string): boolean +} +// }} + +// Configuration {{ +/** + * An event describing the change in Configuration + */ +export interface ConfigurationChangeEvent { + + /** + * Returns `true` if the given section for the given resource (if provided) is affected. + * + * @param section Configuration name, supports _dotted_ names. + * @param resource A resource URI. + * @return `true` if the given section for the given resource (if provided) is affected. + */ + affectsConfiguration(section: string, resource?: string): boolean +} + +export interface WorkspaceConfiguration { + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @return The value `section` denotes or `undefined`. + */ + get(section: string): T | undefined + + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @param defaultValue A value should be returned when no value could be found, is `undefined`. + * @return The value `section` denotes or the default. + */ + get(section: string, defaultValue: T): T + + /** + * Check if this configuration has a certain value. + * + * @param section Configuration name, supports _dotted_ names. + * @return `true` if the section doesn't resolve to `undefined`. + */ + has(section: string): boolean + + /** + * Retrieve all information about a configuration setting. A configuration value + * often consists of a *default* value, a global or installation-wide value, + * a workspace-specific value + * + * *Note:* The configuration name must denote a leaf in the configuration tree + * (`editor.fontSize` vs `editor`) otherwise no result is returned. + * + * @param section Configuration name, supports _dotted_ names. + * @return Information about a configuration setting or `undefined`. + */ + inspect(section: string): ConfigurationInspect | undefined + /** + * Update a configuration value. The updated configuration values are persisted. + * + * + * @param section Configuration name, supports _dotted_ names. + * @param value The new value. + * @param isUser if true, always update user configuration + */ + update(section: string, value: any, isUser?: boolean): void + + /** + * Readable dictionary that backs this configuration. + */ + readonly [key: string]: any +} + +export interface ErrorItem { + location: Location + message: string +} + +export interface ConfigurationInspect { + key: string + defaultValue?: T + globalValue?: T + workspaceValue?: T +} + +export interface IConfigurationOverrides { + overrideIdentifier?: string | null + resource?: URI | null +} + +export interface ConfigurationShape { + /** + * Resolve possible workspace config from resource. + */ + getWorkspaceConfig?(resource?: string): URI | undefined + $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, overrides?: IConfigurationOverrides): void + $removeConfigurationOption(target: ConfigurationTarget, key: string, overrides?: IConfigurationOverrides): void +} + +export interface IConfigurationModel { + contents: any +} + +export interface IConfigurationData { + defaults: IConfigurationModel + user: IConfigurationModel + workspace: IConfigurationModel +} +// }} + +// File operation {{ +/** + * An event that is fired when files are going to be renamed. + * + * To make modifications to the workspace before the files are renamed, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ +export interface FileWillRenameEvent { + + /** + * The files that are going to be renamed. + */ + readonly files: ReadonlyArray<{ oldUri: URI, newUri: URI }> + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void +} + +/** + * An event that is fired after files are renamed. + */ +export interface FileRenameEvent { + + /** + * The files that got renamed. + */ + readonly files: ReadonlyArray<{ oldUri: URI, newUri: URI }> +} + +/** + * An event that is fired when files are going to be created. + * + * To make modifications to the workspace before the files are created, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ +export interface FileWillCreateEvent { + + /** + * A cancellation token. + */ + readonly token: CancellationToken + + /** + * The files that are going to be created. + */ + readonly files: ReadonlyArray + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void +} + +/** + * An event that is fired after files are created. + */ +export interface FileCreateEvent { + + /** + * The files that got created. + */ + readonly files: ReadonlyArray +} + +/** + * An event that is fired when files are going to be deleted. + * + * To make modifications to the workspace before the files are deleted, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ +export interface FileWillDeleteEvent { + + /** + * The files that are going to be deleted. + */ + readonly files: ReadonlyArray + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void +} + +/** + * An event that is fired after files are deleted. + */ +export interface FileDeleteEvent { + + /** + * The files that got deleted. + */ + readonly files: ReadonlyArray +} +// }} + +// List {{ +export interface LocationWithLine { + uri: string + line: string + text?: string +} + +export interface ListItem { + label: string + filterText?: string + preselect?: boolean + location?: Location | LocationWithLine | string + data?: any + ansiHighlights?: AnsiHighlight[] + resolved?: boolean + /** + * A string that should be used when comparing this item + * with other items, only used for fuzzy filter. + */ + sortText?: string + converted?: boolean +} + +export interface ListHighlights { + // column indexes + spans: [number, number][] + hlGroup?: string +} + +export interface ListItemWithHighlights extends ListItem { + score?: number + highlights?: ListHighlights +} + +export interface AnsiHighlight { + span: [number, number] + hlGroup: string +} + +export interface ListItemsEvent { + items: ListItem[] + finished: boolean + append?: boolean + reload?: boolean +} + +export type ListMode = 'normal' | 'insert' + +export type Matcher = 'strict' | 'fuzzy' | 'regex' + +export interface ListOptions { + position: string + reverse: boolean + input: string + ignorecase: boolean + interactive: boolean + sort: boolean + mode: ListMode + matcher: Matcher + autoPreview: boolean + numberSelect: boolean + noQuit: boolean + first: boolean +} + +export interface ListContext { + args: string[] + input: string + cwd: string + options: ListOptions + window: Window + buffer: Buffer + listWindow: Window +} + +export interface ListAction { + name: string + persist?: boolean + reload?: boolean + parallel?: boolean + multiple?: boolean + tabPersist?: boolean + execute: (item: ListItem | ListItem[], context: ListContext) => ProviderResult +} + +export interface ListTask { + on(event: 'data', callback: (item: ListItem) => void): void + on(event: 'end', callback: () => void): void + on(event: 'error', callback: (msg: string | Error) => void): void + dispose(): void +} + +export interface ListArgument { + key?: string + hasValue?: boolean + name: string + description: string +} + +export interface IList { + /** + * Unique name of list. + */ + name: string + /** + * Action list. + */ + actions: ListAction[] + /** + * Default action name. + */ + defaultAction: string + /** + * Load list items. + */ + loadItems(context: ListContext, token: CancellationToken): Promise + /** + * Resolve list item. + */ + resolveItem?(item: ListItem): Promise + /** + * Should be true when interactive is supported. + */ + interactive?: boolean + /** + * Description of list. + */ + description?: string + /** + * Detail description, shown in help. + */ + detail?: string + /** + * Options supported by list. + */ + options?: ListArgument[] + /** + * Highlight buffer by vim's syntax commands. + */ + doHighlight?(): void + dispose?(): void +} +// }} diff --git a/sources_non_forked/coc.nvim/src/util/ansiparse.ts b/sources_non_forked/coc.nvim/src/util/ansiparse.ts new file mode 100644 index 00000000..9540cd6e --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/ansiparse.ts @@ -0,0 +1,249 @@ +'use strict' +import { byteLength, upperFirst } from './string' + +export interface AnsiItem { + foreground?: string + background?: string + bold?: boolean + italic?: boolean + underline?: boolean + strikethrough?: boolean + text: string +} + +const foregroundColors = { + 30: 'black', + 31: 'red', + 32: 'green', + 33: 'yellow', + 34: 'blue', + 35: 'magenta', + 36: 'cyan', + 37: 'white', + 90: 'grey' +} + +const backgroundColors = { + 40: 'black', + 41: 'red', + 42: 'green', + 43: 'yellow', + 44: 'blue', + 45: 'magenta', + 46: 'cyan', + 47: 'white' +} + +const styles = { + 1: 'bold', + 3: 'italic', + 4: 'underline', + 9: 'strikethrough' +} + +export interface AnsiHighlight { + span: [number, number] + hlGroup: string +} + +export interface AnsiResult { + line: string + highlights: AnsiHighlight[] +} + +export function parseAnsiHighlights(line: string, markdown = false): AnsiResult { + let items = ansiparse(line) + let highlights: AnsiHighlight[] = [] + let newLabel = '' + for (let item of items) { + if (!item.text) continue + let { foreground, background } = item + let len = byteLength(newLabel) + let span: [number, number] = [len, len + byteLength(item.text)] + if (foreground && background) { + let hlGroup = `CocList${upperFirst(foreground)}${upperFirst(background)}` + highlights.push({ span, hlGroup }) + } else if (foreground) { + let hlGroup: string + if (markdown) { + if (foreground == 'yellow') { + hlGroup = 'CocMarkdownCode' + } else if (foreground == 'blue') { + hlGroup = 'CocMarkdownLink' + } else if (foreground == 'magenta') { + hlGroup = 'CocMarkdownHeader' + } else { + hlGroup = `CocListFg${upperFirst(foreground)}` + } + } else { + hlGroup = `CocListFg${upperFirst(foreground)}` + } + highlights.push({ span, hlGroup }) + } else if (background) { + let hlGroup = `CocListBg${upperFirst(background)}` + highlights.push({ span, hlGroup }) + } + if (item.bold) { + highlights.push({ span, hlGroup: 'CocBold' }) + } else if (item.italic) { + highlights.push({ span, hlGroup: 'CocItalic' }) + } else if (item.underline) { + highlights.push({ span, hlGroup: 'CocUnderline' }) + } else if (item.strikethrough) { + highlights.push({ span, hlGroup: 'CocStrikeThrough' }) + } + newLabel = newLabel + item.text + } + return { line: newLabel, highlights } +} + +export function ansiparse(str: string): AnsiItem[] { + // + // I'm terrible at writing parsers. + // + let matchingControl = null + let matchingData = null + let matchingText = '' + let ansiState = [] + let result = [] + let state: Partial = {} + let eraseChar + + // + // General workflow for this thing is: + // \033\[33mText + // | | | + // | | matchingText + // | matchingData + // matchingControl + // + // \033\[K or \033\[m + // + // In further steps we hope it's all going to be fine. It usually is. + // + + // + // Erases a char from the output + // + eraseChar = () => { + let index + let text + if (matchingText.length) { + matchingText = matchingText.substr(0, matchingText.length - 1) + } + else if (result.length) { + index = result.length - 1 + text = result[index].text + if (text.length === 1) { + // + // A result bit was fully deleted, pop it out to simplify the final output + // + result.pop() + } + else { + result[index].text = text.substr(0, text.length - 1) + } + } + } + + for (let i = 0; i < str.length; i++) { + if (matchingControl != null) { + if (matchingControl == '\x1b' && str[i] == '[') { + // + // We've matched full control code. Lets start matching formatting data. + // + + // + // "emit" matched text with correct state + // + if (matchingText) { + state.text = matchingText + result.push(state) + state = {} + matchingText = '' + } + if (matchingText == '' && (str[i + 1] == 'm' || str[i + 1] == 'K')) { + if (state.foreground || state.background) { + state.text = '' + result.push(state) + } + state = {} + } + + matchingControl = null + matchingData = '' + } else { + // + // We failed to match anything - most likely a bad control code. We + // go back to matching regular strings. + // + matchingText += matchingControl + str[i] + matchingControl = null + } + continue + } else if (matchingData != null) { + if (str[i] == ';') { + // + // `;` separates many formatting codes, for example: `\033[33;43m` + // means that both `33` and `43` should be applied. + // + // TODO: this can be simplified by modifying state here. + // + ansiState.push(matchingData) + matchingData = '' + } else if (str[i] == 'm' || str[i] == 'K') { + // + // `m` finished whole formatting code. We can proceed to matching + // formatted text. + // + ansiState.push(matchingData) + matchingData = null + matchingText = '' + + // + // Convert matched formatting data into user-friendly state object. + // + ansiState.forEach(ansiCode => { + if (foregroundColors[ansiCode]) { + state.foreground = foregroundColors[ansiCode] + } else if (backgroundColors[ansiCode]) { + state.background = backgroundColors[ansiCode] + } else if (ansiCode == 39) { + delete state.foreground + } else if (ansiCode == 49) { + delete state.background + } else if (styles[ansiCode]) { + state[styles[ansiCode]] = true + } else if (ansiCode == 22) { + state.bold = false + } else if (ansiCode == 23) { + state.italic = false + } else if (ansiCode == 24) { + state.underline = false + } else if (ansiCode == 29) { + state.strikethrough = false + } + }) + ansiState = [] + } + else { + matchingData += str[i] + } + continue + } + + if (str[i] == '\x1b') { + matchingControl = str[i] + } else if (str[i] == '\u0008') { + eraseChar() + } else { + matchingText += str[i] + } + } + + if (matchingText) { + state.text = matchingText + (matchingControl ? matchingControl : '') + result.push(state) + } + return result +} diff --git a/sources_non_forked/coc.nvim/src/util/array.ts b/sources_non_forked/coc.nvim/src/util/array.ts new file mode 100644 index 00000000..23a5622a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/array.ts @@ -0,0 +1,115 @@ +'use strict' + +export function intersect(array: T[], other: T[]): boolean { + for (let item of other) { + if (array.includes(item)) { + return true + } + } + return false +} + +export function findIndex(array: ReadonlyArray, val: T, start = 0): number { + let idx = -1 + for (let i = start; i < array.length; i++) { + if (array[i] === val) { + idx = i + break + } + } + return idx +} + +export function splitArray(array: T[], fn: (item: T) => boolean): [T[], T[]] { + let res: [T[], T[]] = [[], []] + for (let item of array) { + if (fn(item)) { + res[0].push(item) + } else { + res[1].push(item) + } + } + return res +} + +export function tail(array: T[], n = 0): T { + return array[array.length - (1 + n)] +} + +export function group(array: T[], size: number): T[][] { + let len = array.length + let res: T[][] = [] + for (let i = 0; i < Math.ceil(len / size); i++) { + res.push(array.slice(i * size, (i + 1) * size)) + } + return res +} + +export function groupBy(array: T[], fn: (v: T) => boolean): [T[], T[]] { + let res: [T[], T[]] = [[], []] + array.forEach(v => { + if (fn(v)) { + res[0].push(v) + } else { + res[1].push(v) + } + }) + return res +} + +/** + * Removes duplicates from the given array. The optional keyFn allows to specify + * how elements are checked for equalness by returning a unique string for each. + */ +export function distinct(array: T[], keyFn?: (t: T) => string): T[] { + if (!keyFn) { + return array.filter((element, position) => array.indexOf(element) === position) + } + + const seen: { [key: string]: boolean } = Object.create(null) + return array.filter(elem => { + const key = keyFn(elem) + if (seen[key]) { + return false + } + + seen[key] = true + + return true + }) +} + +export function lastIndex(array: T[], fn: (t: T) => boolean): number { + let i = array.length - 1 + while (i >= 0) { + if (fn(array[i])) { + break + } + i-- + } + return i +} + +export const flatMap = (xs: T[], f: (item: T) => U[]): U[] => + xs.reduce((x: U[], y: T) => [...x, ...f(y)], []) + +/** + * Add text to sorted array + */ +export function addSortedArray(text: string, arr: string[]): string[] { + let idx: number + for (let i = 0; i < arr.length; i++) { + let s = arr[i] + if (text === s) return arr + if (s > text) { + idx = i + break + } + } + if (idx === undefined) { + arr.push(text) + } else { + arr.splice(idx, 0, text) + } + return arr +} diff --git a/sources_non_forked/coc.nvim/src/util/async.ts b/sources_non_forked/coc.nvim/src/util/async.ts new file mode 100644 index 00000000..336b7968 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/async.ts @@ -0,0 +1,89 @@ +import { CancellationToken } from 'vscode-languageserver-protocol' + +const defaultYieldTimeout = 15 + +class Timer { + + private readonly yieldAfter: number + private startTime: number + private counter: number + private total: number + private counterInterval: number + + constructor(yieldAfter: number = defaultYieldTimeout) { + this.yieldAfter = Math.max(yieldAfter, defaultYieldTimeout) + this.startTime = Date.now() + this.counter = 0 + this.total = 0 + // start with a counter interval of 1. + this.counterInterval = 1 + } + public start() { + this.startTime = Date.now() + } + public shouldYield(): boolean { + if (++this.counter >= this.counterInterval) { + const timeTaken = Date.now() - this.startTime + const timeLeft = Math.max(0, this.yieldAfter - timeTaken) + this.total += this.counter + this.counter = 0 + if (timeTaken >= this.yieldAfter || timeLeft <= 1) { + // Yield also if time left <= 1 since we compute the counter + // for max < 2 ms. + + // Start with interval 1 again. We could do some calculation + // with using 80% of the last counter however other things (GC) + // affect the timing heavily since we have small timings (1 - 15ms). + this.counterInterval = 1 + this.total = 0 + return true + } else { + // Only increase the counter until we have spent <= 2 ms. Increasing + // the counter further is very fragile since timing is influenced + // by other things and can increase the counter too much. This will result + // that we yield in average after [14 - 16]ms. + switch (timeTaken) { + case 0: + case 1: + this.counterInterval = this.total * 2 + break + } + } + } + return false + } +} + +export async function filter

    (items: ReadonlyArray

    , isValid: (item: P) => boolean | { [key: string]: any }, onFilter: (items: (P & { [key: string]: any })[], done: boolean) => void, token?: CancellationToken): Promise { + if (items.length === 0) return + const timer = new Timer() + const len = items.length + function convertBatch(start: number): number { + const result: P[] = [] + timer.start() + for (let i = start; i < len; i++) { + let item = items[i] + let res = isValid(item) + if (res) typeof res === 'boolean' ? result.push(item) : result.push(Object.assign({}, item, res)) + if (timer.shouldYield()) { + let done = i === len - 1 + onFilter(result, done) + return done ? -1 : i + 1 + } + } + onFilter(result, true) + return -1 + } + // Convert the first batch sync on the same frame. + let index = convertBatch(0) + while (index !== -1) { + if (token !== undefined && token.isCancellationRequested) { + break + } + index = await new Promise(resolve => { + setImmediate(() => { + resolve(convertBatch(index)) + }) + }) + } +} diff --git a/sources_non_forked/coc.nvim/src/util/charCode.ts b/sources_non_forked/coc.nvim/src/util/charCode.ts new file mode 100644 index 00000000..9760f306 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/charCode.ts @@ -0,0 +1,425 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// Names from https://blog.codinghorror.com/ascii-pronunciation-rules-for-programmers/ + +/** + * An inlined enum containing useful character codes (to be used with String.charCodeAt). + * Please leave the const keyword such that it gets inlined when compiled to JavaScript! + */ +export const enum CharCode { + Null = 0, + /** + * The `\b` character. + */ + Backspace = 8, + /** + * The `\t` character. + */ + Tab = 9, + /** + * The `\n` character. + */ + LineFeed = 10, + /** + * The `\r` character. + */ + CarriageReturn = 13, + Space = 32, + /** + * The `!` character. + */ + ExclamationMark = 33, + /** + * The `"` character. + */ + DoubleQuote = 34, + /** + * The `#` character. + */ + Hash = 35, + /** + * The `$` character. + */ + DollarSign = 36, + /** + * The `%` character. + */ + PercentSign = 37, + /** + * The `&` character. + */ + Ampersand = 38, + /** + * The `'` character. + */ + SingleQuote = 39, + /** + * The `(` character. + */ + OpenParen = 40, + /** + * The `)` character. + */ + CloseParen = 41, + /** + * The `*` character. + */ + Asterisk = 42, + /** + * The `+` character. + */ + Plus = 43, + /** + * The `,` character. + */ + Comma = 44, + /** + * The `-` character. + */ + Dash = 45, + /** + * The `.` character. + */ + Period = 46, + /** + * The `/` character. + */ + Slash = 47, + + Digit0 = 48, + Digit1 = 49, + Digit2 = 50, + Digit3 = 51, + Digit4 = 52, + Digit5 = 53, + Digit6 = 54, + Digit7 = 55, + Digit8 = 56, + Digit9 = 57, + + /** + * The `:` character. + */ + Colon = 58, + /** + * The `;` character. + */ + Semicolon = 59, + /** + * The `<` character. + */ + LessThan = 60, + /** + * The `=` character. + */ + Equals = 61, + /** + * The `>` character. + */ + GreaterThan = 62, + /** + * The `?` character. + */ + QuestionMark = 63, + /** + * The `@` character. + */ + AtSign = 64, + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + /** + * The `[` character. + */ + OpenSquareBracket = 91, + /** + * The `\` character. + */ + Backslash = 92, + /** + * The `]` character. + */ + CloseSquareBracket = 93, + /** + * The `^` character. + */ + Caret = 94, + /** + * The `_` character. + */ + Underline = 95, + /** + * The ``(`)`` character. + */ + BackTick = 96, + + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + + /** + * The `{` character. + */ + OpenCurlyBrace = 123, + /** + * The `|` character. + */ + Pipe = 124, + /** + * The `}` character. + */ + CloseCurlyBrace = 125, + /** + * The `~` character. + */ + Tilde = 126, + + U_Combining_Grave_Accent = 0x0300, // U+0300 Combining Grave Accent + U_Combining_Acute_Accent = 0x0301, // U+0301 Combining Acute Accent + U_Combining_Circumflex_Accent = 0x0302, // U+0302 Combining Circumflex Accent + U_Combining_Tilde = 0x0303, // U+0303 Combining Tilde + U_Combining_Macron = 0x0304, // U+0304 Combining Macron + U_Combining_Overline = 0x0305, // U+0305 Combining Overline + U_Combining_Breve = 0x0306, // U+0306 Combining Breve + U_Combining_Dot_Above = 0x0307, // U+0307 Combining Dot Above + U_Combining_Diaeresis = 0x0308, // U+0308 Combining Diaeresis + U_Combining_Hook_Above = 0x0309, // U+0309 Combining Hook Above + U_Combining_Ring_Above = 0x030A, // U+030A Combining Ring Above + U_Combining_Double_Acute_Accent = 0x030B, // U+030B Combining Double Acute Accent + U_Combining_Caron = 0x030C, // U+030C Combining Caron + U_Combining_Vertical_Line_Above = 0x030D, // U+030D Combining Vertical Line Above + U_Combining_Double_Vertical_Line_Above = 0x030E, // U+030E Combining Double Vertical Line Above + U_Combining_Double_Grave_Accent = 0x030F, // U+030F Combining Double Grave Accent + U_Combining_Candrabindu = 0x0310, // U+0310 Combining Candrabindu + U_Combining_Inverted_Breve = 0x0311, // U+0311 Combining Inverted Breve + U_Combining_Turned_Comma_Above = 0x0312, // U+0312 Combining Turned Comma Above + U_Combining_Comma_Above = 0x0313, // U+0313 Combining Comma Above + U_Combining_Reversed_Comma_Above = 0x0314, // U+0314 Combining Reversed Comma Above + U_Combining_Comma_Above_Right = 0x0315, // U+0315 Combining Comma Above Right + U_Combining_Grave_Accent_Below = 0x0316, // U+0316 Combining Grave Accent Below + U_Combining_Acute_Accent_Below = 0x0317, // U+0317 Combining Acute Accent Below + U_Combining_Left_Tack_Below = 0x0318, // U+0318 Combining Left Tack Below + U_Combining_Right_Tack_Below = 0x0319, // U+0319 Combining Right Tack Below + U_Combining_Left_Angle_Above = 0x031A, // U+031A Combining Left Angle Above + U_Combining_Horn = 0x031B, // U+031B Combining Horn + U_Combining_Left_Half_Ring_Below = 0x031C, // U+031C Combining Left Half Ring Below + U_Combining_Up_Tack_Below = 0x031D, // U+031D Combining Up Tack Below + U_Combining_Down_Tack_Below = 0x031E, // U+031E Combining Down Tack Below + U_Combining_Plus_Sign_Below = 0x031F, // U+031F Combining Plus Sign Below + U_Combining_Minus_Sign_Below = 0x0320, // U+0320 Combining Minus Sign Below + U_Combining_Palatalized_Hook_Below = 0x0321, // U+0321 Combining Palatalized Hook Below + U_Combining_Retroflex_Hook_Below = 0x0322, // U+0322 Combining Retroflex Hook Below + U_Combining_Dot_Below = 0x0323, // U+0323 Combining Dot Below + U_Combining_Diaeresis_Below = 0x0324, // U+0324 Combining Diaeresis Below + U_Combining_Ring_Below = 0x0325, // U+0325 Combining Ring Below + U_Combining_Comma_Below = 0x0326, // U+0326 Combining Comma Below + U_Combining_Cedilla = 0x0327, // U+0327 Combining Cedilla + U_Combining_Ogonek = 0x0328, // U+0328 Combining Ogonek + U_Combining_Vertical_Line_Below = 0x0329, // U+0329 Combining Vertical Line Below + U_Combining_Bridge_Below = 0x032A, // U+032A Combining Bridge Below + U_Combining_Inverted_Double_Arch_Below = 0x032B, // U+032B Combining Inverted Double Arch Below + U_Combining_Caron_Below = 0x032C, // U+032C Combining Caron Below + U_Combining_Circumflex_Accent_Below = 0x032D, // U+032D Combining Circumflex Accent Below + U_Combining_Breve_Below = 0x032E, // U+032E Combining Breve Below + U_Combining_Inverted_Breve_Below = 0x032F, // U+032F Combining Inverted Breve Below + U_Combining_Tilde_Below = 0x0330, // U+0330 Combining Tilde Below + U_Combining_Macron_Below = 0x0331, // U+0331 Combining Macron Below + U_Combining_Low_Line = 0x0332, // U+0332 Combining Low Line + U_Combining_Double_Low_Line = 0x0333, // U+0333 Combining Double Low Line + U_Combining_Tilde_Overlay = 0x0334, // U+0334 Combining Tilde Overlay + U_Combining_Short_Stroke_Overlay = 0x0335, // U+0335 Combining Short Stroke Overlay + U_Combining_Long_Stroke_Overlay = 0x0336, // U+0336 Combining Long Stroke Overlay + U_Combining_Short_Solidus_Overlay = 0x0337, // U+0337 Combining Short Solidus Overlay + U_Combining_Long_Solidus_Overlay = 0x0338, // U+0338 Combining Long Solidus Overlay + U_Combining_Right_Half_Ring_Below = 0x0339, // U+0339 Combining Right Half Ring Below + U_Combining_Inverted_Bridge_Below = 0x033A, // U+033A Combining Inverted Bridge Below + U_Combining_Square_Below = 0x033B, // U+033B Combining Square Below + U_Combining_Seagull_Below = 0x033C, // U+033C Combining Seagull Below + U_Combining_X_Above = 0x033D, // U+033D Combining X Above + U_Combining_Vertical_Tilde = 0x033E, // U+033E Combining Vertical Tilde + U_Combining_Double_Overline = 0x033F, // U+033F Combining Double Overline + U_Combining_Grave_Tone_Mark = 0x0340, // U+0340 Combining Grave Tone Mark + U_Combining_Acute_Tone_Mark = 0x0341, // U+0341 Combining Acute Tone Mark + U_Combining_Greek_Perispomeni = 0x0342, // U+0342 Combining Greek Perispomeni + U_Combining_Greek_Koronis = 0x0343, // U+0343 Combining Greek Koronis + U_Combining_Greek_Dialytika_Tonos = 0x0344, // U+0344 Combining Greek Dialytika Tonos + U_Combining_Greek_Ypogegrammeni = 0x0345, // U+0345 Combining Greek Ypogegrammeni + U_Combining_Bridge_Above = 0x0346, // U+0346 Combining Bridge Above + U_Combining_Equals_Sign_Below = 0x0347, // U+0347 Combining Equals Sign Below + U_Combining_Double_Vertical_Line_Below = 0x0348, // U+0348 Combining Double Vertical Line Below + U_Combining_Left_Angle_Below = 0x0349, // U+0349 Combining Left Angle Below + U_Combining_Not_Tilde_Above = 0x034A, // U+034A Combining Not Tilde Above + U_Combining_Homothetic_Above = 0x034B, // U+034B Combining Homothetic Above + U_Combining_Almost_Equal_To_Above = 0x034C, // U+034C Combining Almost Equal To Above + U_Combining_Left_Right_Arrow_Below = 0x034D, // U+034D Combining Left Right Arrow Below + U_Combining_Upwards_Arrow_Below = 0x034E, // U+034E Combining Upwards Arrow Below + U_Combining_Grapheme_Joiner = 0x034F, // U+034F Combining Grapheme Joiner + U_Combining_Right_Arrowhead_Above = 0x0350, // U+0350 Combining Right Arrowhead Above + U_Combining_Left_Half_Ring_Above = 0x0351, // U+0351 Combining Left Half Ring Above + U_Combining_Fermata = 0x0352, // U+0352 Combining Fermata + U_Combining_X_Below = 0x0353, // U+0353 Combining X Below + U_Combining_Left_Arrowhead_Below = 0x0354, // U+0354 Combining Left Arrowhead Below + U_Combining_Right_Arrowhead_Below = 0x0355, // U+0355 Combining Right Arrowhead Below + U_Combining_Right_Arrowhead_And_Up_Arrowhead_Below = 0x0356, // U+0356 Combining Right Arrowhead And Up Arrowhead Below + U_Combining_Right_Half_Ring_Above = 0x0357, // U+0357 Combining Right Half Ring Above + U_Combining_Dot_Above_Right = 0x0358, // U+0358 Combining Dot Above Right + U_Combining_Asterisk_Below = 0x0359, // U+0359 Combining Asterisk Below + U_Combining_Double_Ring_Below = 0x035A, // U+035A Combining Double Ring Below + U_Combining_Zigzag_Above = 0x035B, // U+035B Combining Zigzag Above + U_Combining_Double_Breve_Below = 0x035C, // U+035C Combining Double Breve Below + U_Combining_Double_Breve = 0x035D, // U+035D Combining Double Breve + U_Combining_Double_Macron = 0x035E, // U+035E Combining Double Macron + U_Combining_Double_Macron_Below = 0x035F, // U+035F Combining Double Macron Below + U_Combining_Double_Tilde = 0x0360, // U+0360 Combining Double Tilde + U_Combining_Double_Inverted_Breve = 0x0361, // U+0361 Combining Double Inverted Breve + U_Combining_Double_Rightwards_Arrow_Below = 0x0362, // U+0362 Combining Double Rightwards Arrow Below + U_Combining_Latin_Small_Letter_A = 0x0363, // U+0363 Combining Latin Small Letter A + U_Combining_Latin_Small_Letter_E = 0x0364, // U+0364 Combining Latin Small Letter E + U_Combining_Latin_Small_Letter_I = 0x0365, // U+0365 Combining Latin Small Letter I + U_Combining_Latin_Small_Letter_O = 0x0366, // U+0366 Combining Latin Small Letter O + U_Combining_Latin_Small_Letter_U = 0x0367, // U+0367 Combining Latin Small Letter U + U_Combining_Latin_Small_Letter_C = 0x0368, // U+0368 Combining Latin Small Letter C + U_Combining_Latin_Small_Letter_D = 0x0369, // U+0369 Combining Latin Small Letter D + U_Combining_Latin_Small_Letter_H = 0x036A, // U+036A Combining Latin Small Letter H + U_Combining_Latin_Small_Letter_M = 0x036B, // U+036B Combining Latin Small Letter M + U_Combining_Latin_Small_Letter_R = 0x036C, // U+036C Combining Latin Small Letter R + U_Combining_Latin_Small_Letter_T = 0x036D, // U+036D Combining Latin Small Letter T + U_Combining_Latin_Small_Letter_V = 0x036E, // U+036E Combining Latin Small Letter V + U_Combining_Latin_Small_Letter_X = 0x036F, // U+036F Combining Latin Small Letter X + + /** + * Unicode Character 'LINE SEPARATOR' (U+2028) + * http://www.fileformat.info/info/unicode/char/2028/index.htm + */ + LINE_SEPARATOR_2028 = 8232, + + // http://www.fileformat.info/info/unicode/category/Sk/list.htm + U_CIRCUMFLEX = 0x005E, // U+005E CIRCUMFLEX + U_GRAVE_ACCENT = 0x0060, // U+0060 GRAVE ACCENT + U_DIAERESIS = 0x00A8, // U+00A8 DIAERESIS + U_MACRON = 0x00AF, // U+00AF MACRON + U_ACUTE_ACCENT = 0x00B4, // U+00B4 ACUTE ACCENT + U_CEDILLA = 0x00B8, // U+00B8 CEDILLA + U_MODIFIER_LETTER_LEFT_ARROWHEAD = 0x02C2, // U+02C2 MODIFIER LETTER LEFT ARROWHEAD + U_MODIFIER_LETTER_RIGHT_ARROWHEAD = 0x02C3, // U+02C3 MODIFIER LETTER RIGHT ARROWHEAD + U_MODIFIER_LETTER_UP_ARROWHEAD = 0x02C4, // U+02C4 MODIFIER LETTER UP ARROWHEAD + U_MODIFIER_LETTER_DOWN_ARROWHEAD = 0x02C5, // U+02C5 MODIFIER LETTER DOWN ARROWHEAD + U_MODIFIER_LETTER_CENTRED_RIGHT_HALF_RING = 0x02D2, // U+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING + U_MODIFIER_LETTER_CENTRED_LEFT_HALF_RING = 0x02D3, // U+02D3 MODIFIER LETTER CENTRED LEFT HALF RING + U_MODIFIER_LETTER_UP_TACK = 0x02D4, // U+02D4 MODIFIER LETTER UP TACK + U_MODIFIER_LETTER_DOWN_TACK = 0x02D5, // U+02D5 MODIFIER LETTER DOWN TACK + U_MODIFIER_LETTER_PLUS_SIGN = 0x02D6, // U+02D6 MODIFIER LETTER PLUS SIGN + U_MODIFIER_LETTER_MINUS_SIGN = 0x02D7, // U+02D7 MODIFIER LETTER MINUS SIGN + U_BREVE = 0x02D8, // U+02D8 BREVE + U_DOT_ABOVE = 0x02D9, // U+02D9 DOT ABOVE + U_RING_ABOVE = 0x02DA, // U+02DA RING ABOVE + U_OGONEK = 0x02DB, // U+02DB OGONEK + U_SMALL_TILDE = 0x02DC, // U+02DC SMALL TILDE + U_DOUBLE_ACUTE_ACCENT = 0x02DD, // U+02DD DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_RHOTIC_HOOK = 0x02DE, // U+02DE MODIFIER LETTER RHOTIC HOOK + U_MODIFIER_LETTER_CROSS_ACCENT = 0x02DF, // U+02DF MODIFIER LETTER CROSS ACCENT + U_MODIFIER_LETTER_EXTRA_HIGH_TONE_BAR = 0x02E5, // U+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR + U_MODIFIER_LETTER_HIGH_TONE_BAR = 0x02E6, // U+02E6 MODIFIER LETTER HIGH TONE BAR + U_MODIFIER_LETTER_MID_TONE_BAR = 0x02E7, // U+02E7 MODIFIER LETTER MID TONE BAR + U_MODIFIER_LETTER_LOW_TONE_BAR = 0x02E8, // U+02E8 MODIFIER LETTER LOW TONE BAR + U_MODIFIER_LETTER_EXTRA_LOW_TONE_BAR = 0x02E9, // U+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR + U_MODIFIER_LETTER_YIN_DEPARTING_TONE_MARK = 0x02EA, // U+02EA MODIFIER LETTER YIN DEPARTING TONE MARK + U_MODIFIER_LETTER_YANG_DEPARTING_TONE_MARK = 0x02EB, // U+02EB MODIFIER LETTER YANG DEPARTING TONE MARK + U_MODIFIER_LETTER_UNASPIRATED = 0x02ED, // U+02ED MODIFIER LETTER UNASPIRATED + U_MODIFIER_LETTER_LOW_DOWN_ARROWHEAD = 0x02EF, // U+02EF MODIFIER LETTER LOW DOWN ARROWHEAD + U_MODIFIER_LETTER_LOW_UP_ARROWHEAD = 0x02F0, // U+02F0 MODIFIER LETTER LOW UP ARROWHEAD + U_MODIFIER_LETTER_LOW_LEFT_ARROWHEAD = 0x02F1, // U+02F1 MODIFIER LETTER LOW LEFT ARROWHEAD + U_MODIFIER_LETTER_LOW_RIGHT_ARROWHEAD = 0x02F2, // U+02F2 MODIFIER LETTER LOW RIGHT ARROWHEAD + U_MODIFIER_LETTER_LOW_RING = 0x02F3, // U+02F3 MODIFIER LETTER LOW RING + U_MODIFIER_LETTER_MIDDLE_GRAVE_ACCENT = 0x02F4, // U+02F4 MODIFIER LETTER MIDDLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_GRAVE_ACCENT = 0x02F5, // U+02F5 MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT + U_MODIFIER_LETTER_MIDDLE_DOUBLE_ACUTE_ACCENT = 0x02F6, // U+02F6 MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT + U_MODIFIER_LETTER_LOW_TILDE = 0x02F7, // U+02F7 MODIFIER LETTER LOW TILDE + U_MODIFIER_LETTER_RAISED_COLON = 0x02F8, // U+02F8 MODIFIER LETTER RAISED COLON + U_MODIFIER_LETTER_BEGIN_HIGH_TONE = 0x02F9, // U+02F9 MODIFIER LETTER BEGIN HIGH TONE + U_MODIFIER_LETTER_END_HIGH_TONE = 0x02FA, // U+02FA MODIFIER LETTER END HIGH TONE + U_MODIFIER_LETTER_BEGIN_LOW_TONE = 0x02FB, // U+02FB MODIFIER LETTER BEGIN LOW TONE + U_MODIFIER_LETTER_END_LOW_TONE = 0x02FC, // U+02FC MODIFIER LETTER END LOW TONE + U_MODIFIER_LETTER_SHELF = 0x02FD, // U+02FD MODIFIER LETTER SHELF + U_MODIFIER_LETTER_OPEN_SHELF = 0x02FE, // U+02FE MODIFIER LETTER OPEN SHELF + U_MODIFIER_LETTER_LOW_LEFT_ARROW = 0x02FF, // U+02FF MODIFIER LETTER LOW LEFT ARROW + U_GREEK_LOWER_NUMERAL_SIGN = 0x0375, // U+0375 GREEK LOWER NUMERAL SIGN + U_GREEK_TONOS = 0x0384, // U+0384 GREEK TONOS + U_GREEK_DIALYTIKA_TONOS = 0x0385, // U+0385 GREEK DIALYTIKA TONOS + U_GREEK_KORONIS = 0x1FBD, // U+1FBD GREEK KORONIS + U_GREEK_PSILI = 0x1FBF, // U+1FBF GREEK PSILI + U_GREEK_PERISPOMENI = 0x1FC0, // U+1FC0 GREEK PERISPOMENI + U_GREEK_DIALYTIKA_AND_PERISPOMENI = 0x1FC1, // U+1FC1 GREEK DIALYTIKA AND PERISPOMENI + U_GREEK_PSILI_AND_VARIA = 0x1FCD, // U+1FCD GREEK PSILI AND VARIA + U_GREEK_PSILI_AND_OXIA = 0x1FCE, // U+1FCE GREEK PSILI AND OXIA + U_GREEK_PSILI_AND_PERISPOMENI = 0x1FCF, // U+1FCF GREEK PSILI AND PERISPOMENI + U_GREEK_DASIA_AND_VARIA = 0x1FDD, // U+1FDD GREEK DASIA AND VARIA + U_GREEK_DASIA_AND_OXIA = 0x1FDE, // U+1FDE GREEK DASIA AND OXIA + U_GREEK_DASIA_AND_PERISPOMENI = 0x1FDF, // U+1FDF GREEK DASIA AND PERISPOMENI + U_GREEK_DIALYTIKA_AND_VARIA = 0x1FED, // U+1FED GREEK DIALYTIKA AND VARIA + U_GREEK_DIALYTIKA_AND_OXIA = 0x1FEE, // U+1FEE GREEK DIALYTIKA AND OXIA + U_GREEK_VARIA = 0x1FEF, // U+1FEF GREEK VARIA + U_GREEK_OXIA = 0x1FFD, // U+1FFD GREEK OXIA + U_GREEK_DASIA = 0x1FFE, // U+1FFE GREEK DASIA + + U_OVERLINE = 0x203E, // Unicode Character 'OVERLINE' + + /** + * UTF-8 BOM + * Unicode Character 'ZERO WIDTH NO-BREAK SPACE' (U+FEFF) + * http://www.fileformat.info/info/unicode/char/feff/index.htm + */ + UTF8_BOM = 65279 +} diff --git a/sources_non_forked/coc.nvim/src/util/color.ts b/sources_non_forked/coc.nvim/src/util/color.ts new file mode 100644 index 00000000..aa222fda --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/color.ts @@ -0,0 +1,33 @@ +'use strict' +import { Color } from 'vscode-languageserver-protocol' + +function pad(str: string): string { + return str.length == 1 ? `0${str}` : str +} + +export function toHexString(color: Color): string { + let c = toHexColor(color) + return `${pad(c.red.toString(16))}${pad(c.green.toString(16))}${pad(c.blue.toString(16))}` +} + +export function toHexColor(color: Color): { red: number; green: number; blue: number } { + let { red, green, blue } = color + return { + red: Math.round(red * 255), + green: Math.round(green * 255), + blue: Math.round(blue * 255) + } +} + +export function isDark(color: Color): boolean { + // http://www.w3.org/TR/WCAG20/#relativeluminancedef + let rgb = [color.red, color.green, color.blue] + let lum = [] + for (let i = 0; i < rgb.length; i++) { + let chan = rgb[i] + lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4) + } + let luma = 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2] + return luma <= 0.5 +} + diff --git a/sources_non_forked/coc.nvim/src/util/convert.ts b/sources_non_forked/coc.nvim/src/util/convert.ts new file mode 100644 index 00000000..40d9514d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/convert.ts @@ -0,0 +1,61 @@ +'use strict' +import { SymbolKind } from 'vscode-languageserver-protocol' + +export function getSymbolKind(kind: SymbolKind): string { + switch (kind) { + case SymbolKind.File: + return 'File' + case SymbolKind.Module: + return 'Module' + case SymbolKind.Namespace: + return 'Namespace' + case SymbolKind.Package: + return 'Package' + case SymbolKind.Class: + return 'Class' + case SymbolKind.Method: + return 'Method' + case SymbolKind.Property: + return 'Property' + case SymbolKind.Field: + return 'Field' + case SymbolKind.Constructor: + return 'Constructor' + case SymbolKind.Enum: + return 'Enum' + case SymbolKind.Interface: + return 'Interface' + case SymbolKind.Function: + return 'Function' + case SymbolKind.Variable: + return 'Variable' + case SymbolKind.Constant: + return 'Constant' + case SymbolKind.String: + return 'String' + case SymbolKind.Number: + return 'Number' + case SymbolKind.Boolean: + return 'Boolean' + case SymbolKind.Array: + return 'Array' + case SymbolKind.Object: + return 'Object' + case SymbolKind.Key: + return 'Key' + case SymbolKind.Null: + return 'Null' + case SymbolKind.EnumMember: + return 'EnumMember' + case SymbolKind.Struct: + return 'Struct' + case SymbolKind.Event: + return 'Event' + case SymbolKind.Operator: + return 'Operator' + case SymbolKind.TypeParameter: + return 'TypeParameter' + default: + return 'Unknown' + } +} diff --git a/sources_non_forked/coc.nvim/src/util/diff.ts b/sources_non_forked/coc.nvim/src/util/diff.ts new file mode 100644 index 00000000..500a2571 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/diff.ts @@ -0,0 +1,204 @@ +'use strict' +import fastDiff from 'fast-diff' +import { Position, TextEdit, Range } from 'vscode-languageserver-types' +import { byteLength } from './string' +const logger = require('./logger')('util-diff') + +export interface ChangedLines { + start: number + end: number + replacement: string[] +} + +interface Change { + start: number + end: number + newText: string +} + +export function diffLines(oldLines: ReadonlyArray, newLines: ReadonlyArray, startLine: number): ChangedLines { + let endOffset = 0 + let startOffset = 0 + let parts = oldLines.slice(startLine + 1) + for (let i = 0; i < Math.min(parts.length, newLines.length); i++) { + if (parts[parts.length - 1 - i] == newLines[newLines.length - 1 - i]) { + endOffset = endOffset + 1 + } else { + break + } + } + for (let i = 0; i <= Math.min(startLine, newLines.length - 1 - endOffset); i++) { + if (oldLines[i] == newLines[i]) { + startOffset = startOffset + 1 + } else { + break + } + } + let replacement = newLines.slice(startOffset, newLines.length - endOffset) + let end = oldLines.length - endOffset + if (end > startOffset && replacement.length) { + let offset = 0 + for (let i = 0; i < Math.min(replacement.length, end - startOffset); i++) { + if (replacement[i] == oldLines[startOffset + i]) { + offset = offset + 1 + } else { + break + } + } + if (offset) { + return { + start: startOffset + offset, + end, + replacement: replacement.slice(offset) + } + } + } + return { + start: startOffset, + end, + replacement + } +} + +export function getChange(oldStr: string, newStr: string, cursorEnd?: number): Change { + let ol = oldStr.length + let nl = newStr.length + let max = Math.min(ol, nl) + let newText = '' + let startOffset = 0 + let endOffset = -1 + let shouldLimit = false + // find first endOffset, could <= this. one + for (let i = 0; i <= max; i++) { + if (cursorEnd != null && i == cursorEnd) { + endOffset = i + shouldLimit = true + break + } + if (oldStr[ol - i - 1] != newStr[nl - i - 1]) { + endOffset = i + break + } + } + if (endOffset == -1) return null + // find start offset + let remain = max - endOffset + if (remain == 0) { + startOffset = 0 + } else { + for (let i = 0; i <= remain; i++) { + if (oldStr[i] != newStr[i] || i == remain) { + startOffset = i + break + } + } + } + // limit to minimal change + remain = remain - startOffset + if (shouldLimit && remain > 0) { + let end = endOffset + for (let i = 0; i < remain; i++) { + let oc = oldStr[ol - end - 1 - i] + let nc = newStr[nl - end - 1 - i] + if (oc == nc) { + endOffset = endOffset + 1 + } else { + break + } + } + } + let end = ol - endOffset + if (ol == nl && startOffset == end) return null + newText = newStr.slice(startOffset, nl - endOffset) + // optimize for add new line(s) + if (startOffset == end) { + let pre = startOffset == 0 ? '' : newStr[startOffset - 1] + if (pre && pre != '\n' + && oldStr[startOffset] == '\n' + && newText.startsWith('\n')) { + return { start: startOffset + 1, end: end + 1, newText: newText.slice(1) + '\n' } + } + } + return { start: startOffset, end, newText } +} + +export function patchLine(from: string, to: string, fill = ' '): string { + if (from == to) return to + let idx = to.indexOf(from) + if (idx !== -1) return fill.repeat(idx) + from + let result = fastDiff(from, to) + let str = '' + for (let item of result) { + if (item[0] == fastDiff.DELETE) { + // not allowed + return to + } else if (item[0] == fastDiff.INSERT) { + str = str + fill.repeat(byteLength(item[1])) + } else { + str = str + item[1] + } + } + return str +} + +export function getTextEdit(oldLines: ReadonlyArray, newLines: ReadonlyArray, cursor?: Position, insertMode?: boolean): TextEdit | undefined { + let ol = oldLines.length + let nl = newLines.length + let n = cursor ? cursor.line : Math.min(ol, nl) + let used = 0 + for (let i = 0; i < n; i++) { + if (newLines[i] === oldLines[i]) { + used += 1 + } else { + break + } + } + if (ol == nl && used == ol) return undefined + let delta = nl - ol + let r = Math.min(ol - used, nl - used) + let e = 0 + for (let i = 0; i < r; i++) { + if (newLines[nl - i - 1] === oldLines[ol - i - 1]) { + e += 1 + } else { + break + } + } + let inserted = e == 0 ? newLines.slice(used) : newLines.slice(used, -e) + if (delta == 0 && cursor && inserted.length == 1) { + let newLine = newLines[used] + let oldLine = oldLines[used] + let nl = newLine.length + let ol = oldLine.length + if (nl === 0) return TextEdit.del(Range.create(used, 0, used, ol)) + if (ol === 0) return TextEdit.insert(Position.create(used, 0), newLine) + let character = Math.min(cursor.character, nl) + if (!insertMode && nl >= ol && character !== nl) { + // insert text + character += 1 + } + let r = 0 + for (let i = 0; i < nl - character; i++) { + let idx = ol - 1 - i + if (idx === -1) break + if (newLine[nl - 1 - i] === oldLine[idx]) { + r += 1 + } else { + break + } + } + let l = 0 + for (let i = 0; i < Math.min(ol - r, nl - r); i++) { + if (newLine[i] === oldLine[i]) { + l += 1 + } else { + break + } + } + let newText = r === 0 ? newLine.slice(l) : newLine.slice(l, -r) + return TextEdit.replace(Range.create(used, l, used, ol - r), newText) + } + let text = inserted.length > 0 ? inserted.join('\n') + '\n' : '' + if (text.length === 0 && used === ol - e) return undefined + return TextEdit.replace(Range.create(used, 0, ol - e, 0), text) +} diff --git a/sources_non_forked/coc.nvim/src/util/errors.ts b/sources_non_forked/coc.nvim/src/util/errors.ts new file mode 100644 index 00000000..5c0d18db --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/errors.ts @@ -0,0 +1,29 @@ +'use strict' + +export function illegalArgument(name?: string): Error { + if (name) { + return new Error(`Illegal argument: ${name}`) + } else { + return new Error('Illegal argument') + } +} + +export function directoryNotExists(dir: string): Error { + return new Error(`Directory ${dir} not exists`) +} + +export function fileExists(filepath: string) { + return new Error(`File ${filepath} already exists`) +} + +export function fileNotExists(filepath: string) { + return new Error(`File ${filepath} not exists`) +} + +export function shouldNotAsync(method: string) { + return new Error(`${method} should not be called in an asynchronize manner`) +} + +export function badScheme(scheme: string) { + return new Error(`Change of ${scheme} not supported`) +} diff --git a/sources_non_forked/coc.nvim/src/util/extensions.ts b/sources_non_forked/coc.nvim/src/util/extensions.ts new file mode 100644 index 00000000..89406ce0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/extensions.ts @@ -0,0 +1,16 @@ +'use strict' +declare interface Promise { + /** + * Catches task error and ignores them. + */ + logError(): void +} + +/** + * Explicitly tells that promise should be run asynchronously. + */ +Promise.prototype.logError = function (this: Promise): void { + this.catch(e => { + require('./logger')('util-extensions').error(e) + }) +} diff --git a/sources_non_forked/coc.nvim/src/util/factory.ts b/sources_non_forked/coc.nvim/src/util/factory.ts new file mode 100644 index 00000000..2bb3268b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/factory.ts @@ -0,0 +1,179 @@ +'use strict' +/* eslint-disable @typescript-eslint/no-unsafe-return */ +import fs from 'fs' +import path from 'path' +import * as vm from 'vm' +import { defaults } from './lodash' +const createLogger = require('./logger') +const logger = createLogger('util-factoroy') + +export interface ExtensionExport { + activate: (context: unknown) => any + deactivate: () => any | null +} +export interface ILogger { + debug: (data: string, ...meta: any[]) => void + log: (data: string, ...meta: any[]) => void + error: (data: string, ...meta: any[]) => void + warn: (data: string, ...meta: any[]) => void + info: (data: string, ...meta: any[]) => void +} + +export interface IModule { + new(name: string): any + _resolveFilename: (file: string, context: any) => string + _extensions: {} + _cache: { [file: string]: any } + _compile: () => void + wrap: (content: string) => string + require: (file: string) => NodeModule + _nodeModulePaths: (filename: string) => string[] +} + +const Module: IModule = require('module') +const REMOVED_GLOBALS = [ + 'reallyExit', + 'abort', + 'umask', + 'setuid', + 'setgid', + 'setgroups', + '_fatalException', + 'exit', + 'kill', +] + +function removedGlobalStub(name: string): Function { + return () => { + throw new Error(`process.${name}() is not allowed in extension sandbox`) + } +} + +// @see node/lib/internal/module.js +function makeRequireFunction(this: any): any { + const req: any = (p: string) => { + if (p === 'coc.nvim') { + return require('../index') + } + return this.require(p) + } + req.resolve = (request: string) => Module._resolveFilename(request, this) + req.main = process.mainModule + // Enable support to add extra extension types + req.extensions = Module._extensions + req.cache = Module._cache + return req +} + +// @see node/lib/module.js +export function compileInSandbox(sandbox: ISandbox): Function { + // eslint-disable-next-line + return function(this: any, content: string, filename: string): any { + const require = makeRequireFunction.call(this) + const dirname = path.dirname(filename) + // remove shebang + // eslint-disable-next-line + const newContent = content.replace(/^\#\!.*/, '') + const wrapper = Module.wrap(newContent) + const compiledWrapper = vm.runInContext(wrapper, sandbox, { filename }) + const args = [this.exports, require, this, filename, dirname] + return compiledWrapper.apply(this.exports, args) + } +} + +export interface ISandbox { + process: NodeJS.Process + module: NodeModule + require: (p: string) => any + console: { [key in keyof Console]?: Function } + Buffer: any + Reflect: any + // eslint-disable-next-line id-blacklist + String: any + Promise: any +} + +export function createSandbox(filename: string, logger: ILogger): ISandbox { + const module = new Module(filename) + module.paths = Module._nodeModulePaths(filename) + + const sandbox = vm.createContext({ + module, + Buffer, + console: { + debug: (...args: any[]) => { + logger.debug.apply(logger, args) + }, + log: (...args: any[]) => { + logger.info.apply(logger, args) + }, + error: (...args: any[]) => { + logger.error.apply(logger, args) + }, + info: (...args: any[]) => { + logger.info.apply(logger, args) + }, + warn: (...args: any[]) => { + logger.warn.apply(logger, args) + } + } + }) as ISandbox + + defaults(sandbox, global) + sandbox.Reflect = Reflect + + sandbox.require = function sandboxRequire(p): any { + const oldCompile = Module.prototype._compile + // Not work on test environment! + Module.prototype._compile = compileInSandbox(sandbox) + const moduleExports = sandbox.module.require(p) + Module.prototype._compile = oldCompile + return moduleExports + } + + // patch `require` in sandbox to run loaded module in sandbox context + // if you need any of these, it might be worth discussing spawning separate processes + sandbox.process = new (process as any).constructor() + for (let key of Object.keys(process)) { + sandbox.process[key] = process[key] + } + + REMOVED_GLOBALS.forEach(name => { + sandbox.process[name] = removedGlobalStub(name) + }) + sandbox.process['chdir'] = () => {} + + // read-only umask + sandbox.process.umask = (mask?: number) => { + if (typeof mask !== 'undefined') { + throw new Error('Cannot use process.umask() to change mask (read-only)') + } + return process.umask() + } + + return sandbox +} + +// inspiration drawn from Module +export function createExtension(id: string, filename: string, isEmpty = false): ExtensionExport { + if (isEmpty || !fs.existsSync(filename)) return { + activate: () => {}, + deactivate: null + } + const sandbox = createSandbox(filename, createLogger(`extension:${id}`)) + + delete Module._cache[require.resolve(filename)] + + // attempt to import plugin + // Require plugin to export activate & deactivate + const defaultImport = sandbox.require(filename) + const activate = (defaultImport && defaultImport.activate) || defaultImport + + if (typeof activate !== 'function') { + return { activate: () => {}, deactivate: null } + } + return { + activate, + deactivate: typeof defaultImport.deactivate === 'function' ? defaultImport.deactivate : null + } +} diff --git a/sources_non_forked/coc.nvim/src/util/fs.ts b/sources_non_forked/coc.nvim/src/util/fs.ts new file mode 100644 index 00000000..a6562e74 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/fs.ts @@ -0,0 +1,277 @@ +'use strict' +import { exec } from 'child_process' +import fs from 'fs-extra' +import minimatch from 'minimatch' +import os from 'os' +import path from 'path' +import readline from 'readline' +import util from 'util' +import glob from 'glob' +import * as platform from './platform' +const logger = require('./logger')('util-fs') + +export type OnReadLine = (line: string) => void + +export async function statAsync(filepath: string): Promise { + let stat = null + try { + stat = await fs.stat(filepath) + } catch (e) {} + return stat +} + +export function renameAsync(oldPath: string, newPath: string): Promise { + return new Promise((resolve, reject) => { + fs.rename(oldPath, newPath, err => { + if (err) return reject(err) + resolve() + }) + }) +} + +export async function isGitIgnored(fullpath: string): Promise { + if (!fullpath) return false + let stat = await statAsync(fullpath) + if (!stat || !stat.isFile()) return false + let root = null + try { + let { stdout } = await util.promisify(exec)('git rev-parse --show-toplevel', { cwd: path.dirname(fullpath) }) + root = stdout.trim() + } catch (e) {} + if (!root) return false + let file = path.relative(root, fullpath) + try { + let { stdout } = await util.promisify(exec)(`git check-ignore ${file}`, { cwd: root }) + return stdout.trim() == file + } catch (e) {} + return false +} + +export function isFolderIgnored(folder: string, ignored: string[] = []): boolean { + if (!ignored || !ignored.length) return false + return ignored.some(p => minimatch(folder, p, { dot: true })) +} + +export function resolveRoot(folder: string, subs: string[], cwd?: string, bottomup = false, checkCwd = true, ignored: string[] = []): string | null { + let dir = fixDriver(folder) + if (checkCwd + && cwd + && isParentFolder(cwd, dir, true) + && !isFolderIgnored(cwd, ignored) + && inDirectory(cwd, subs)) return cwd + let parts = dir.split(path.sep) + if (bottomup) { + while (parts.length > 0) { + let dir = parts.join(path.sep) + if (!isFolderIgnored(dir, ignored) && inDirectory(dir, subs)) { + return dir + } + parts.pop() + } + return null + } else { + let curr: string[] = [parts.shift()] + for (let part of parts) { + curr.push(part) + let dir = curr.join(path.sep) + if (!isFolderIgnored(dir, ignored) && inDirectory(dir, subs)) { + return dir + } + } + return null + } +} + +export async function checkFolder(dir: string, pattern: string, timeout = 500): Promise { + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + gl.abort() + resolve(false) + }, timeout) + let find = false + let gl = glob(pattern, { + nosort: true, + dot: true, + cwd: dir, + nodir: true, + absolute: false + }, err => { + clearTimeout(timer) + if (err) return reject(err) + resolve(find) + }) + gl.on('match', () => { + clearTimeout(timer) + find = true + gl.abort() + resolve(true) + }) + gl.on('end', () => { + clearTimeout(timer) + resolve(find) + }) + }) +} + +export function inDirectory(dir: string, subs: string[]): boolean { + try { + let files = fs.readdirSync(dir) + for (let pattern of subs) { + // note, only '*' expanded + let is_wildcard = (pattern.includes('*')) + let res = is_wildcard ? + (minimatch.match(files, pattern, { nobrace: true, noext: true, nocomment: true, nonegate: true, dot: true }).length !== 0) : + (files.includes(pattern)) + if (res) return true + } + } catch (e) { + // could be failed without permission + } + return false +} + +export function findUp(name: string | string[], cwd: string): string { + let root = path.parse(cwd).root + let subs = Array.isArray(name) ? name : [name] + while (cwd && cwd !== root) { + let find = inDirectory(cwd, subs) + if (find) { + for (let sub of subs) { + let filepath = path.join(cwd, sub) + if (fs.existsSync(filepath)) { + return filepath + } + } + } + cwd = path.dirname(cwd) + } + return null +} + +export function readFile(fullpath: string, encoding: string): Promise { + return new Promise((resolve, reject) => { + fs.readFile(fullpath, encoding, (err, content) => { + if (err) reject(err) + resolve(content) + }) + }) +} + +export function getFileLineCount(filepath: string): Promise { + let i + let count = 0 + return new Promise((resolve, reject) => { + fs.createReadStream(filepath) + .on('error', e => reject(e)) + .on('data', chunk => { + for (i = 0; i < chunk.length; ++i) if (chunk[i] == 10) count++ + }) + .on('end', () => resolve(count)) + }) +} + +export function readFileLines(fullpath: string, start: number, end: number): Promise { + if (!fs.existsSync(fullpath)) { + return Promise.reject(new Error(`file does not exist: ${fullpath}`)) + } + let res: string[] = [] + const input = fs.createReadStream(fullpath, { encoding: 'utf8' }) + const rl = readline.createInterface({ + input, + crlfDelay: Infinity, + terminal: false + } as any) + let n = 0 + return new Promise((resolve, reject) => { + rl.on('line', line => { + if (n >= start && n <= end) { + res.push(line) + } + if (n == end) { + rl.close() + } + n = n + 1 + }) + rl.on('close', () => { + resolve(res) + input.close() + }) + rl.on('error', reject) + }) +} + +export function readFileLine(fullpath: string, count: number): Promise { + if (!fs.existsSync(fullpath)) { + return Promise.reject(new Error(`file does not exist: ${fullpath}`)) + } + const input = fs.createReadStream(fullpath, { encoding: 'utf8' }) + const rl = readline.createInterface({ + input, + crlfDelay: Infinity, + terminal: false + } as any) + let n = 0 + return new Promise((resolve, reject) => { + rl.on('line', line => { + if (n == count) { + if (n == 0 && line.startsWith('\uFEFF')) { + // handle BOM + line = line.slice(1) + } + rl.close() + input.close() + resolve(line) + return + } + n = n + 1 + }) + rl.on('error', reject) + }) +} + +export function sameFile(fullpath: string | null, other: string | null, caseInsensitive?: boolean): boolean { + caseInsensitive = typeof caseInsensitive == 'boolean' ? caseInsensitive : platform.isWindows || platform.isMacintosh + if (!fullpath || !other) return false + if (caseInsensitive) return fullpath.toLowerCase() === other.toLowerCase() + return fullpath === other +} + +export function fileStartsWith(dir: string, pdir: string) { + let caseInsensitive = platform.isWindows || platform.isMacintosh + if (caseInsensitive) return dir.toLowerCase().startsWith(pdir.toLowerCase()) + return dir.startsWith(pdir) +} + +export async function writeFile(fullpath: string, content: string): Promise { + await fs.writeFile(fullpath, content, { encoding: 'utf8' }) +} + +export function isFile(uri: string): boolean { + return uri.startsWith('file:') +} + +export function parentDirs(pth: string): string[] { + let { root, dir } = path.parse(pth) + if (dir === root) return [root] + const dirs = [root] + const parts = dir.slice(root.length).split(path.sep) + for (let i = 1; i <= parts.length; i++) { + dirs.push(path.join(root, parts.slice(0, i).join(path.sep))) + } + return dirs +} + +export function isParentFolder(folder: string, filepath: string, checkEqual = false): boolean { + let pdir = fixDriver(path.resolve(path.normalize(folder))) + let dir = fixDriver(path.resolve(path.normalize(filepath))) + if (pdir == '//') pdir = '/' + if (sameFile(pdir, dir)) return checkEqual ? true : false + if (pdir.endsWith(path.sep)) return fileStartsWith(dir, pdir) + return fileStartsWith(dir, pdir) && dir[pdir.length] == path.sep +} + +// use uppercase for windows driver +export function fixDriver(filepath: string, platform = os.platform()): string { + if (platform != 'win32' || filepath[1] != ':') return filepath + return filepath[0].toUpperCase() + filepath.slice(1) +} diff --git a/sources_non_forked/coc.nvim/src/util/fuzzy.ts b/sources_non_forked/coc.nvim/src/util/fuzzy.ts new file mode 100644 index 00000000..b761d309 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/fuzzy.ts @@ -0,0 +1,50 @@ +'use strict' + +export function getCharCodes(str: string): number[] { + let res = [] + for (let i = 0, l = str.length; i < l; i++) { + res.push(str.charCodeAt(i)) + } + return res +} + +export function wordChar(ch: number): boolean { + return (ch >= 97 && ch <= 122) || (ch >= 65 && ch <= 90) +} + +export function caseMatch(input: number, code: number, ignorecase = false): boolean { + if (input == code) return true + if (input >= 97 && input <= 122 && code + 32 === input) return true + if (ignorecase && input <= 90 && input + 32 === code) return true + return false +} + +export function fuzzyChar(a: string, b: string): boolean { + let ca = a.charCodeAt(0) + let cb = b.charCodeAt(0) + if (ca === cb) return true + if (ca >= 97 && ca <= 122 && cb + 32 === ca) return true + return false +} + +// upper case must match, lower case ignore case +export function fuzzyMatch(needle: number[], text: string): boolean { + let totalCount = needle.length + if (needle.length > text.length) return false + let i = 0 + for (let j = 0; j < text.length; j++) { + if (i === totalCount) break + let code = text.charCodeAt(j) + let m = needle[i] + if (code === m) { + i = i + 1 + continue + } + // upper case match lower case + if ((m >= 97 && m <= 122) && code + 32 === m) { + i = i + 1 + continue + } + } + return i === totalCount +} diff --git a/sources_non_forked/coc.nvim/src/util/fzy.ts b/sources_non_forked/coc.nvim/src/util/fzy.ts new file mode 100644 index 00000000..b7c59a84 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/fzy.ts @@ -0,0 +1,202 @@ +'use strict' +let SCORE_MIN = -Infinity +let SCORE_MAX = Infinity + +let SCORE_GAP_LEADING = -0.005 +let SCORE_GAP_TRAILING = -0.005 +let SCORE_GAP_INNER = -0.01 +let SCORE_MATCH_CONSECUTIVE = 1 +let SCORE_MATCH_SLASH = 0.9 +let SCORE_MATCH_WORD = 0.8 +let SCORE_MATCH_CAPITAL = 0.7 +let SCORE_MATCH_DOT = 0.6 + +function islower(s): boolean { + return s.toLowerCase() === s +} + +function isupper(s): boolean { + return s.toUpperCase() === s +} + +function precompute_bonus(haystack): number[] { + /* Which positions are beginning of words */ + let m = haystack.length + let match_bonus = new Array(m) + + let last_ch = '/' + for (let i = 0; i < m; i++) { + let ch = haystack[i] + + if (last_ch === '/') { + match_bonus[i] = SCORE_MATCH_SLASH + } else if (last_ch === '-' || last_ch === '_' || last_ch === ' ') { + match_bonus[i] = SCORE_MATCH_WORD + } else if (last_ch === '.') { + match_bonus[i] = SCORE_MATCH_DOT + } else if (islower(last_ch) && isupper(ch)) { + match_bonus[i] = SCORE_MATCH_CAPITAL + } else { + match_bonus[i] = 0 + } + + last_ch = ch + } + + return match_bonus +} + +function compute(needle, haystack, D, M): void { + let n = needle.length + let m = haystack.length + + let lower_needle = needle.toLowerCase() + let lower_haystack = haystack.toLowerCase() + + let match_bonus = precompute_bonus(haystack) + + /* + * D[][] Stores the best score for this position ending with a match. + * M[][] Stores the best possible score at this position. + */ + + for (let i = 0; i < n; i++) { + D[i] = new Array(m) + M[i] = new Array(m) + + let prev_score = SCORE_MIN + let gap_score = i === n - 1 ? SCORE_GAP_TRAILING : SCORE_GAP_INNER + + for (let j = 0; j < m; j++) { + if (lower_needle[i] === lower_haystack[j]) { + let score = SCORE_MIN + if (!i) { + score = (j * SCORE_GAP_LEADING) + match_bonus[j] + } else if (j) { /* i > 0 && j > 0*/ + score = Math.max( + M[i - 1][j - 1] + match_bonus[j], + + /* consecutive match, doesn't stack with match_bonus */ + D[i - 1][j - 1] + SCORE_MATCH_CONSECUTIVE) + } + D[i][j] = score + M[i][j] = prev_score = Math.max(score, prev_score + gap_score) + } else { + D[i][j] = SCORE_MIN + M[i][j] = prev_score = prev_score + gap_score + } + } + } +} + +export function score(needle, haystack): number { + let n = needle.length + let m = haystack.length + + if (!n || !m) + return SCORE_MIN + + if (n === m) { + /* Since this method can only be called with a haystack which + * matches needle. If the lengths of the strings are equal the + * strings themselves must also be equal (ignoring case). + */ + return SCORE_MAX + } + + if (m > 1024) { + /* + * Unreasonably large candidate: return no score + * If it is a valid match it will still be returned, it will + * just be ranked below any reasonably sized candidates + */ + return SCORE_MIN + } + + let D = new Array(n) + let M = new Array(n) + + compute(needle, haystack, D, M) + + return M[n - 1][m - 1] +} + +export function groupPositions(arr: number[]): [number, number][] { + let res: [number, number][] = [] + for (let i = 0; i < arr.length; i++) { + let last = res.length ? res[res.length - 1] : undefined + let curr = arr[i] + if (last && curr == last[1]) { + last[1] = curr + 1 + } else { + res.push([curr, curr + 1]) + } + } + return res +} + +export function positions(needle: string, haystack: string): number[] { + let n = needle.length + let m = haystack.length + + let positions = new Array(n) + + if (!n || !m) + return positions + + if (n === m) { + for (let i = 0; i < n; i++) + positions[i] = i + return positions + } + + if (m > 1024) { + return positions + } + + let D = new Array(n) + let M = new Array(n) + + compute(needle, haystack, D, M) + + /* backtrack to find the positions of optimal matching */ + let match_required = false + + for (let i = n - 1, j = m - 1; i >= 0; i--) { + for (; j >= 0; j--) { + /* + * There may be multiple paths which result in + * the optimal weight. + * + * For simplicity, we will pick the first one + * we encounter, the latest in the candidate + * string. + */ + if (D[i][j] !== SCORE_MIN && + (match_required || D[i][j] === M[i][j])) { + /* If this score was determined using + * SCORE_MATCH_CONSECUTIVE, the + * previous character MUST be a match + */ + match_required = + i && j && + M[i][j] === D[i - 1][j - 1] + SCORE_MATCH_CONSECUTIVE + positions[i] = j-- + break + } + } + } + + return positions +} + +export function hasMatch(needle: string, haystack: string): boolean { + needle = needle.toLowerCase() + haystack = haystack.toLowerCase() + let l = needle.length + for (let i = 0, j = 0; i < l; i += 1) { + j = haystack.indexOf(needle[i], j) + 1 + if (j === 0) return false + } + return true +} diff --git a/sources_non_forked/coc.nvim/src/util/index.ts b/sources_non_forked/coc.nvim/src/util/index.ts new file mode 100644 index 00000000..52d5637b --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/index.ts @@ -0,0 +1,163 @@ +'use strict' +import { exec, ExecOptions } from 'child_process' +import debounce from 'debounce' +import fs from 'fs' +import isuri from 'isuri' +import path from 'path' +import { Disposable, MarkupContent, MarkupKind } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import which from 'which' +import * as platform from './platform' +export { platform } +const logger = require('./logger')('util-index') + +export type MapMode = 'n' | 'i' | 'v' | 'x' | 's' | 'o' + +export const CONFIG_FILE_NAME = 'coc-settings.json' + +export function isMarkdown(content: MarkupContent | string | undefined): boolean { + if (MarkupContent.is(content) && content.kind == MarkupKind.Markdown) { + return true + } + return false +} + +export function wait(ms: number): Promise { + if (ms <= 0) return Promise.resolve(undefined) + return new Promise(resolve => { + setTimeout(() => { + resolve(undefined) + }, ms) + }) +} + +export function waitNextTick(fn?: () => void): Promise { + return new Promise(resolve => { + process.nextTick(() => { + if (fn) fn() + resolve(undefined) + }) + }) +} + +export function waitImmediate(): Promise { + return new Promise(resolve => { + setImmediate(() => { + resolve(undefined) + }) + }) +} + +export function getUri(fullpath: string, id: number, buftype: string, isCygwin: boolean): string { + if (!fullpath) return `untitled:${id}` + // https://github.com/neoclide/coc-java/issues/82 + if (platform.isWindows && !isCygwin && !fullpath.startsWith('jdt://')) fullpath = path.win32.normalize(fullpath) + if (path.isAbsolute(fullpath)) return URI.file(fullpath).toString() + if (isuri.isValid(fullpath)) return URI.parse(fullpath).toString() + if (buftype != '') return `${buftype}:${id}` + return `unknown:${id}` +} + +export function disposeAll(disposables: Disposable[]): void { + while (disposables.length) { + const item = disposables.pop() + if (item) { + item.dispose() + } + } +} + +export function executable(command: string): boolean { + try { + which.sync(command) + } catch (e) { + return false + } + return true +} + +export function runCommand(cmd: string, opts: ExecOptions = {}, timeout?: number): Promise { + if (!platform.isWindows) { + opts.shell = opts.shell || process.env.SHELL + } + opts.maxBuffer = 500 * 1024 + return new Promise((resolve, reject) => { + let timer: NodeJS.Timer + if (timeout) { + timer = setTimeout(() => { + reject(new Error(`timeout after ${timeout}s`)) + }, timeout * 1000) + } + exec(cmd, opts, (err, stdout, stderr) => { + if (timer) clearTimeout(timer) + if (err) { + reject(new Error(`exited with ${err.code}\n${err}\n${stderr}`)) + return + } + resolve(stdout) + }) + }) +} + +export function watchFile(filepath: string, onChange: () => void): Disposable { + let callback = debounce(onChange, 100) + try { + let watcher = fs.watch(filepath, { + persistent: true, + recursive: false, + encoding: 'utf8' + }, () => { + callback() + }) + return Disposable.create(() => { + callback.clear() + watcher.close() + }) + } catch (e) { + return Disposable.create(() => { + callback.clear() + }) + } +} + +export function isRunning(pid: number): boolean { + try { + let res: any = process.kill(pid, 0) + return res == true + } + catch (e) { + return e['code'] === 'EPERM' + } +} + +export function getKeymapModifier(mode: MapMode): string { + if (mode == 'n' || mode == 'o' || mode == 'x' || mode == 'v') return '' + if (mode == 'i') return '' + if (mode == 's') return '' + return '' +} + +export function concurrent(arr: T[], fn: (val: T) => Promise, limit = 3): Promise { + if (arr.length == 0) return Promise.resolve() + let finished = 0 + let total = arr.length + let remain = arr.slice() + return new Promise(resolve => { + let run = (val): void => { + let cb = () => { + finished = finished + 1 + if (finished == total) { + resolve() + } else if (remain.length) { + let next = remain.shift() + run(next) + } + } + fn(val).then(cb, cb) + } + for (let i = 0; i < Math.min(limit, remain.length); i++) { + let val = remain.shift() + run(val) + } + }) +} diff --git a/sources_non_forked/coc.nvim/src/util/is.ts b/sources_non_forked/coc.nvim/src/util/is.ts new file mode 100644 index 00000000..acb70bbc --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/is.ts @@ -0,0 +1,59 @@ +'use strict' +import { VimCompleteItem } from '../types' +/* eslint-disable id-blacklist */ +const hasOwnProperty = Object.prototype.hasOwnProperty + +export function vimCompleteItem(value: any): value is VimCompleteItem { + return value && typeof value.word === 'string' && value.user_data !== '' +} + +export function boolean(value: any): value is boolean { + return typeof value === 'boolean' +} + +export function string(value: any): value is string { + return typeof value === 'string' +} + +export function number(value: any): value is number { + return typeof value === 'number' +} + +export function array(array: any): array is any[] { + return Array.isArray(array) +} + +export function func(value: any): value is Function { + return typeof value == 'function' +} + +export function objectLiteral(obj: any): obj is object { + return ( + obj != null && + typeof obj === 'object' && + !Array.isArray(obj) && + !(obj instanceof RegExp) && + !(obj instanceof Date) + ) +} + +export function emptyObject(obj: any): boolean { + if (!objectLiteral(obj)) { + return false + } + + for (let key in obj) { + if (hasOwnProperty.call(obj, key)) { + return false + } + } + + return true +} + +export function typedArray( + value: any, + check: (value: any) => boolean +): value is T[] { + return Array.isArray(value) && (value as any).every(check) +} diff --git a/sources_non_forked/coc.nvim/src/util/lodash.ts b/sources_non_forked/coc.nvim/src/util/lodash.ts new file mode 100644 index 00000000..4e35d62d --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/lodash.ts @@ -0,0 +1,53 @@ +'use strict' + +/** Used for built-in method references. */ +const objectProto = Object.prototype + +/** Used to check objects for own properties. */ +const hasOwnProperty = objectProto.hasOwnProperty + +/** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @since 0.1.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see defaultsDeep + * @example + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }) + * // => { 'a': 1, 'b': 2 } + */ +export function defaults(obj: any, ...sources: any[]): any { + obj = Object(obj) + sources.forEach(source => { + if (source != null) { + source = Object(source) + for (const key in source) { + const value = obj[key] + if (value === undefined || + (value === objectProto[key] && !hasOwnProperty.call(obj, key))) { + obj[key] = source[key] + } + } + } + }) + return obj +} + +export function omit(obj: T, properties: string[]): T { + let o = {} + for (let key of Object.keys(obj)) { + if (!properties.includes(key)) { + o[key] = obj[key] + } + } + return o as T +} diff --git a/sources_non_forked/coc.nvim/src/util/logger.ts b/sources_non_forked/coc.nvim/src/util/logger.ts new file mode 100644 index 00000000..a2394ea0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/logger.ts @@ -0,0 +1,70 @@ +'use strict' +import fs from 'fs' +import log4js from 'log4js' +import path from 'path' +import os from 'os' +import { mkdirpSync } from 'fs-extra' + +function getLogFile(): string { + let file = process.env.NVIM_COC_LOG_FILE + if (file) return file + let dir = process.env.XDG_RUNTIME_DIR + if (dir) { + try { + fs.accessSync(dir, fs.constants.R_OK | fs.constants.W_OK) + return path.join(dir, `coc-nvim-${process.pid}.log`) + } catch (err) { + // noop + } + } + let tmpdir = os.tmpdir() + dir = path.join(tmpdir, `coc.nvim-${process.pid}`) + if (!fs.existsSync(dir)) mkdirpSync(dir) + return path.join(dir, `coc-nvim.log`) +} + +const MAX_LOG_SIZE = 1024 * 1024 +const MAX_LOG_BACKUPS = 10 +let logfile = getLogFile() +const level = process.env.NVIM_COC_LOG_LEVEL || 'info' + +if (fs.existsSync(logfile)) { + // cleanup if exists + try { + fs.writeFileSync(logfile, '', { encoding: 'utf8', mode: 0o666 }) + } catch (e) { + // noop + } +} + +exports.getLogFile = getLogFile + +log4js.configure({ + disableClustering: true, + appenders: { + out: { + type: 'file', + mode: 0o666, + filename: logfile, + maxLogSize: MAX_LOG_SIZE, + backups: MAX_LOG_BACKUPS, + layout: { + type: 'pattern', + // Format log in following pattern: + // yyyy-MM-dd HH:mm:ss.mil $Level (pid:$pid) $categroy - $message. + pattern: `%d{ISO8601} %p (pid:${process.pid}) [%c] - %m`, + }, + } + }, + categories: { + default: { appenders: ['out'], level } + } +}) + +module.exports = (name = 'coc-nvim'): log4js.Logger => { + let logger = log4js.getLogger(name) + return Object.assign(logger, { + getLogFile, + logfile + }) +} diff --git a/sources_non_forked/coc.nvim/src/util/mutex.ts b/sources_non_forked/coc.nvim/src/util/mutex.ts new file mode 100644 index 00000000..86607c20 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/mutex.ts @@ -0,0 +1,47 @@ +'use strict' +export class Mutex { + private tasks: (() => void)[] = [] + private count = 1 + + private sched(): void { + if (this.count > 0 && this.tasks.length > 0) { + this.count-- + let next = this.tasks.shift() + next() + } + } + + public get busy(): boolean { + return this.count == 0 + } + + public acquire(): Promise<() => void> { + return new Promise<() => void>(res => { + let task = () => { + let released = false + res(() => { + if (!released) { + released = true + this.count++ + this.sched() + } + }) + } + this.tasks.push(task) + process.nextTick(this.sched.bind(this)) + }) + } + + public use(f: () => Promise): Promise { + return this.acquire() + .then(release => f() + .then(res => { + release() + return res + }) + .catch(err => { + release() + throw err + })) + } +} diff --git a/sources_non_forked/coc.nvim/src/util/object.ts b/sources_non_forked/coc.nvim/src/util/object.ts new file mode 100644 index 00000000..6b8a8a9c --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/object.ts @@ -0,0 +1,138 @@ +'use strict' +import * as Is from './is' + +export function isEmpty(obj: object | null | undefined): boolean { + if (!obj) return true + if (Array.isArray(obj)) return obj.length == 0 + return Object.keys(obj).length == 0 +} + +export function deepClone(obj: T): T { + if (!obj || typeof obj !== 'object') { + return obj + } + if (obj instanceof RegExp) { + // See https://github.com/Microsoft/TypeScript/issues/10990 + return obj as any + } + const result: any = Array.isArray(obj) ? [] : {} + Object.keys(obj).forEach(key => { + if (obj[key] && typeof obj[key] === 'object') { + result[key] = deepClone(obj[key]) + } else { + result[key] = obj[key] + } + }) + return result +} + +const _hasOwnProperty = Object.prototype.hasOwnProperty + +export function deepFreeze(obj: T): T { + if (!obj || typeof obj !== 'object') { + return obj + } + const stack: any[] = [obj] + while (stack.length > 0) { + let obj = stack.shift() + Object.freeze(obj) + for (const key in obj) { + if (_hasOwnProperty.call(obj, key)) { + let prop = obj[key] + if (typeof prop === 'object' && !Object.isFrozen(prop)) { + stack.push(prop) + } + } + } + } + return obj +} + +/** + * Copies all properties of source into destination. The optional parameter "overwrite" allows to control + * if existing properties on the destination should be overwritten or not. Defaults to true (overwrite). + */ +export function mixin( + destination: any, + source: any, + overwrite = true +): any { + if (!Is.objectLiteral(destination)) { + return source + } + + if (Is.objectLiteral(source)) { + Object.keys(source).forEach(key => { + if (key in destination) { + if (overwrite) { + if (Is.objectLiteral(destination[key]) && Is.objectLiteral(source[key])) { + mixin(destination[key], source[key], overwrite) + } else { + destination[key] = source[key] + } + } + } else { + destination[key] = source[key] + } + }) + } + return destination +} + +export function equals(one: any, other: any): boolean { + if (one === other) { + return true + } + if ( + one === null || + one === undefined || + other === null || + other === undefined + ) { + return false + } + if (typeof one !== typeof other) { + return false + } + if (typeof one !== 'object') { + return false + } + if (Array.isArray(one) !== Array.isArray(other)) { + return false + } + + let i: number + let key: string + + if (Array.isArray(one)) { + if (one.length !== other.length) { + return false + } + for (i = 0; i < one.length; i++) { + if (!equals(one[i], other[i])) { + return false + } + } + } else { + const oneKeys: string[] = [] + + for (key in one) { + oneKeys.push(key) + } + oneKeys.sort() + const otherKeys: string[] = [] + for (key in other) { + otherKeys.push(key) + } + otherKeys.sort() + if (!equals(oneKeys, otherKeys)) { + return false + } + for (i = 0; i < oneKeys.length; i++) { + if (!equals(one[oneKeys[i]], other[oneKeys[i]])) { + return false + } + } + } + return true +} diff --git a/sources_non_forked/coc.nvim/src/util/platform.ts b/sources_non_forked/coc.nvim/src/util/platform.ts new file mode 100644 index 00000000..6e4af8a0 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/platform.ts @@ -0,0 +1,79 @@ +'use strict' +let _isWindows = false +let _isMacintosh = false +let _isLinux = false +let _isNative = false +let _isWeb = false + +export interface IProcessEnvironment { + [key: string]: string +} + +interface INodeProcess { + nextTick: Function + platform: string + env: IProcessEnvironment + getuid(): number +} + +declare let process: INodeProcess +declare let global: any +declare let self: any + +export const language = 'en' + +// OS detection +if ( + typeof process === 'object' && + typeof process.nextTick === 'function' && + typeof process.platform === 'string' +) { + _isWindows = process.platform === 'win32' + _isMacintosh = process.platform === 'darwin' + _isLinux = process.platform === 'linux' + _isNative = true +} + +export enum Platform { + Web, + Mac, + Linux, + Windows +} + +let _platform: Platform = Platform.Web +if (_isNative) { + if (_isMacintosh) { + _platform = Platform.Mac + } else if (_isWindows) { + _platform = Platform.Windows + } else if (_isLinux) { + _platform = Platform.Linux + } +} + +export const isWindows = _isWindows +export const isMacintosh = _isMacintosh +export const isLinux = _isLinux +export const isNative = _isNative +export const isWeb = _isWeb +export const platform = _platform + +const _globals = + typeof self === 'object' + ? self + : typeof global === 'object' + ? global + : ({} as any) +export const globals: any = _globals + +export const enum OperatingSystem { + Windows = 1, + Macintosh = 2, + Linux = 3 +} +export const OS = _isMacintosh + ? OperatingSystem.Macintosh + : _isWindows + ? OperatingSystem.Windows + : OperatingSystem.Linux diff --git a/sources_non_forked/coc.nvim/src/util/position.ts b/sources_non_forked/coc.nvim/src/util/position.ts new file mode 100644 index 00000000..1d663a80 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/position.ts @@ -0,0 +1,114 @@ +'use strict' +import { Position, Range } from 'vscode-languageserver-protocol' + +export function rangeInRange(r: Range, range: Range): boolean { + return positionInRange(r.start, range) === 0 && positionInRange(r.end, range) === 0 +} + +export function samePosition(one: Position, two: Position): boolean { + return one.line === two.line && one.character === two.character +} + +/** + * Convert to well formed range + */ +export function toValidRange(range: Range, max?: Position): Range { + let { start, end } = range + if (start.line > end.line || (start.line === end.line && start.character > end.character)) { + let m = start + start = end + end = m + } + start = Position.create(Math.max(0, start.line), Math.max(0, start.character)) + end = Position.create(Math.max(0, end.line), Math.max(0, end.character)) + return { start, end } +} + +export function rangeAdjacent(r: Range, range: Range): boolean { + if (comparePosition(r.end, range.start) == 0) { + return true + } + if (comparePosition(range.end, r.start) == 0) { + return true + } + return false +} + +/** + * Check if two ranges have overlap character. + */ +export function rangeOverlap(r: Range, range: Range): boolean { + let { start, end } = r + if (comparePosition(end, range.start) <= 0) { + return false + } + if (comparePosition(start, range.end) >= 0) { + return false + } + return true +} + +/** + * Check if two ranges have overlap or nested + */ +export function rangeIntersect(r: Range, range: Range): boolean { + if (positionInRange(r.start, range) == 0) { + return true + } + if (positionInRange(r.end, range) == 0) { + return true + } + if (rangeInRange(range, r)) { + return true + } + return false +} + +/** + * Adjust from start position + */ +export function adjustRangePosition(range: Range, position: Position): Range { + let { line, character } = position + let { start, end } = range + let endCharacter = end.line == start.line ? end.character + character : end.character + return Range.create(start.line + line, character + start.character, end.line + line, endCharacter) +} + +export function lineInRange(line: number, range: Range): boolean { + let { start, end } = range + return line >= start.line && line <= end.line +} + +export function emptyRange(range: Range): boolean { + let { start, end } = range + return start.line == end.line && start.character == end.character +} + +export function positionInRange(position: Position, range: Range): number { + let { start, end } = range + if (comparePosition(position, start) < 0) return -1 + if (comparePosition(position, end) > 0) return 1 + return 0 +} + +export function comparePosition(position: Position, other: Position): number { + if (position.line > other.line) return 1 + if (other.line == position.line && position.character > other.character) return 1 + if (other.line == position.line && position.character == other.character) return 0 + return -1 +} + +export function isSingleLine(range: Range): boolean { + return range.start.line == range.end.line +} + +/* + * Get end position by content + */ +export function getEnd(start: Position, content: string): Position { + const lines = content.split(/\r?\n/) + const len = lines.length + const lastLine = lines[len - 1] + const end = len == 1 ? start.character + content.length : lastLine.length + return Position.create(start.line + len - 1, end) +} diff --git a/sources_non_forked/coc.nvim/src/util/processes.ts b/sources_non_forked/coc.nvim/src/util/processes.ts new file mode 100644 index 00000000..98367dfa --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/processes.ts @@ -0,0 +1,51 @@ +'use strict' +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as cp from 'child_process' +import { join, dirname, resolve } from 'path' +import ChildProcess = cp.ChildProcess + +declare const ESBUILD + +const isWindows = process.platform === 'win32' +const isMacintosh = process.platform === 'darwin' +const isLinux = process.platform === 'linux' +const pluginRoot = typeof ESBUILD === 'undefined' ? resolve(__dirname, '../..') : dirname(__dirname) + +export function terminate(process: ChildProcess, cwd?: string): boolean { + if (process.killed) return + if (isWindows) { + try { + // This we run in Atom execFileSync is available. + // Ignore stderr since this is otherwise piped to parent.stderr + // which might be already closed. + let options: any = { + stdio: ['pipe', 'pipe', 'ignore'] + } + if (cwd) { + options.cwd = cwd + } + cp.execFileSync( + 'taskkill', + ['/T', '/F', '/PID', process.pid.toString()], + options + ) + return true + } catch (err) { + return false + } + } else if (isLinux || isMacintosh) { + try { + let filepath = join(pluginRoot, 'bin/terminateProcess.sh') + let result = cp.spawnSync(filepath, [process.pid.toString()]) + return result.error ? false : true + } catch (err) { + return false + } + } else { + process.kill('SIGKILL') + return true + } +} diff --git a/sources_non_forked/coc.nvim/src/util/score.ts b/sources_non_forked/coc.nvim/src/util/score.ts new file mode 100644 index 00000000..029b742a --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/score.ts @@ -0,0 +1,142 @@ +'use strict' +import { sep as pathSeparator } from 'path' +import { getCharCodes, fuzzyMatch, fuzzyChar, caseMatch } from './fuzzy' + +export interface MatchResult { + score: number + matches?: number[] // character indexes +} + +// first is start or path start +1, fuzzy +0.5 +// next is followed of path start +1, fuzzy +0.5 +// filename startsWith +1, fuzzy +0.5 + +export function getMatchResult(text: string, query: string, filename = ''): MatchResult { + if (!text) return { score: 0 } + if (!query) return { score: 1 } + let matches: number[] = [] + let codes = getCharCodes(query) + let filenameIdx = filename ? text.indexOf(filename) : -1 + let matchBase = filenameIdx != -1 && fuzzyMatch(codes, filename) + let score = 0 + let c = query[0] + let idx = 0 + let first = text[0] + // base => start => pathSeparator => fuzzy + if (matchBase) { + if (filename.startsWith(c)) { + score = score + 2 + idx = filenameIdx + 1 + matches.push(filenameIdx) + } else if (filename[0].toLowerCase() == c) { + score = score + 1.5 + idx = filenameIdx + 1 + matches.push(filenameIdx) + } else { + for (let i = 1; i < filename.length; i++) { + if (fuzzyChar(c, filename[i])) { + score = score + 1 + idx = filenameIdx + i + 1 + matches.push(filenameIdx + i) + break + } + } + } + } else if (first.toLowerCase() === c.toLowerCase()) { + score = score + (first == c ? 1 : 0.5) + matches.push(0) + idx = 1 + } else { + for (let i = 1; i < text.length; i++) { + let pre = text[i - 1] + if (pre == pathSeparator && text[i] == c) { + score = score + 1 + matches.push(i) + idx = i + 1 + break + } + } + if (idx == 0) { + for (let i = 0; i < text.length; i++) { + if (fuzzyChar(c.toLowerCase(), text[i])) { + score = score + (c === text[i] ? 0.5 : 0.3) + matches.push(i) + idx = i + 1 + break + } + } + } + } + if (idx == 0) return { score: 0 } + if (codes.length == 1) return { score, matches } + return nextResult(codes.slice(1), text, idx, { score, matches }) +} + +/** + * + * @public + * @param {number[]} codes - remain codes + * @param {string} text - total text + * @param {number} idx - start index of text + * @param {MatchResult} curr - current result + * @returns {MatchResult | null} + */ +function nextResult(codes: number[], text: string, idx: number, curr: MatchResult): MatchResult | null { + let { score, matches } = curr + let results: MatchResult[] = [] + let c = codes[0] + let remain = codes.slice(1) + let result: MatchResult + + function getRemainResult(index: number): void { + if (!result) return + if (remain.length == 0) { + results.push(result) + } else if (result) { + let res = nextResult(remain, text, index, result) + if (res) results.push(res) + } + } + let followed = idx < text.length ? text[idx].charCodeAt(0) : null + if (!followed) return null + if (followed == c) { + result = { score: score + 1, matches: matches.concat([idx]) } + getRemainResult(idx + 1) + } else if (caseMatch(c, followed, true)) { + result = { score: score + 0.5, matches: matches.concat([idx]) } + getRemainResult(idx + 1) + } + if (idx + 1 < text.length) { + // follow path + for (let i = idx + 1; i < text.length; i++) { + let ch = text[i].charCodeAt(0) + if (text[i - 1] == pathSeparator && caseMatch(c, ch, true)) { + let add = c == ch ? 1 : 0.5 + result = { score: score + add, matches: matches.concat([i]) } + getRemainResult(i + 1) + break + } + } + // next fuzzy + for (let i = idx + 1; i < text.length; i++) { + let ch = text[i].charCodeAt(0) + if (caseMatch(c, ch, true)) { + let add = c == ch ? 0.5 : 0.2 + result = { score: score + add, matches: matches.concat([i]) } + getRemainResult(i + 1) + break + } + } + } + return results.length ? bestResult(results) : null +} + +function bestResult(results: MatchResult[]): MatchResult { + let res = results[0] + for (let i = 1; i < results.length; i++) { + if (results[i].score > res.score) { + res = results[i] + } + } + return res +} diff --git a/sources_non_forked/coc.nvim/src/util/string.ts b/sources_non_forked/coc.nvim/src/util/string.ts new file mode 100644 index 00000000..22aed879 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/string.ts @@ -0,0 +1,149 @@ +'use strict' +import { Range } from 'vscode-languageserver-protocol' + +export function rangeParts(text: string, range: Range): [string, string] { + let { start, end } = range + let lines = text.split(/\r?\n/) + let before = '' + let after = '' + let len = lines.length + // get start and end parts + for (let i = 0; i < len; i++) { + let curr = lines[i] + if (i < start.line) { + before += curr + '\n' + continue + } + if (i > end.line) { + after += curr + (i == len - 1 ? '' : '\n') + continue + } + if (i == start.line) { + before += curr.slice(0, start.character) + } + if (i == end.line) { + after += curr.slice(end.character) + (i == len - 1 ? '' : '\n') + } + } + return [before, after] +} + +// lowerCase 1, upperCase 2 +export function getCase(code: number): number { + if (code >= 97 && code <= 122) return 1 + if (code >= 65 && code <= 90) return 2 + return 0 +} + +export function getNextWord(codes: ReadonlyArray, index: number): [number, number] | undefined { + let preCase = index == 0 ? 0 : getCase(codes[index - 1]) + for (let i = index; i < codes.length; i++) { + let curr = getCase(codes[i]) + if (curr > 0 && curr != preCase) { + return [i, codes[i]] + } + preCase = curr + } + return undefined +} + +export function getCharIndexes(input: string, character: string): number[] { + let res: number[] = [] + for (let i = 0; i < input.length; i++) { + if (input[i] == character) res.push(i) + } + return res +} + +// nvim use utf8 +export function byteLength(str: string): number { + return Buffer.byteLength(str) +} + +export function upperFirst(str: string): string { + return str?.length > 0 ? str[0].toUpperCase() + str.slice(1) : '' +} + +export function byteIndex(content: string, index: number): number { + let s = content.slice(0, index) + return Buffer.byteLength(s) +} + +export function indexOf(str: string, ch: string, count = 1): number { + let curr = 0 + for (let i = 0; i < str.length; i++) { + if (str[i] == ch) { + curr = curr + 1 + if (curr == count) { + return i + } + } + } + return -1 +} + +export function characterIndex(content: string, byteIndex: number): number { + let buf = Buffer.from(content, 'utf8') + return buf.slice(0, byteIndex).toString('utf8').length +} + +export function byteSlice(content: string, start: number, end?: number): string { + let buf = Buffer.from(content, 'utf8') + return buf.slice(start, end).toString('utf8') +} + +export function isWord(character: string): boolean { + let code = character.charCodeAt(0) + if (code > 128) return false + if (code == 95) return true + if (code >= 48 && code <= 57) return true + if (isAlphabet(code)) return true + return false +} + +export function isAlphabet(code: number): boolean { + if (code >= 65 && code <= 90) return true + if (code >= 97 && code <= 122) return true + return false +} + +function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean { + if (typeof a !== 'string' || typeof b !== 'string') { + return false + } + for (let i = 0; i < stopAt; i++) { + const codeA = a.charCodeAt(i) + const codeB = b.charCodeAt(i) + if (codeA === codeB) { + continue + } + // a-z A-Z + if (isAlphabet(codeA) && isAlphabet(codeB)) { + const diff = Math.abs(codeA - codeB) + if (diff !== 0 && diff !== 32) { + return false + } + } + // Any other charcode + else { + if (String.fromCharCode(codeA).toLowerCase() !== String.fromCharCode(codeB).toLowerCase()) { + return false + } + } + } + return true +} + +export function equalsIgnoreCase(a: string, b: string): boolean { + const len1 = a ? a.length : 0 + const len2 = b ? b.length : 0 + if (len1 !== len2) return false + return doEqualsIgnoreCase(a, b) +} + +export function contentToLines(content: string, eol: boolean): string[] { + if (eol && content.endsWith('\n')) { + return content.slice(0, -1).split('\n') + } + return content.split('\n') +} diff --git a/sources_non_forked/coc.nvim/src/util/textedit.ts b/sources_non_forked/coc.nvim/src/util/textedit.ts new file mode 100644 index 00000000..5f949e20 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/util/textedit.ts @@ -0,0 +1,312 @@ +'use strict' +import { AnnotatedTextEdit, ChangeAnnotation, Position, Range, TextDocumentEdit, TextEdit, WorkspaceEdit } from 'vscode-languageserver-protocol' +import { LinesTextDocument } from '../model/textdocument' +import { DocumentChange } from '../types' +import { comparePosition, emptyRange, samePosition, toValidRange } from './position' +import { byteLength, contentToLines } from './string' + +export type TextChangeItem = [string[], number, number, number, number] + +export function singleLineEdit(edit: TextEdit): boolean { + let { range, newText } = edit + return range.start.line == range.end.line && newText.indexOf('\n') == -1 +} + +export function lineCountChange(edit: TextEdit): number { + let { newText } = edit + let range = getWellformedRange(edit.range) + let n = range.end.line - range.start.line + return newText.split(/\r?\n/).length - n - 1 +} + +export function getWellformedRange(range: Range): Range { + const start = range.start + const end = range.end + if (start.line > end.line || (start.line === end.line && start.character > end.character)) { + return { start: end, end: start } + } + return range +} + +export function getWellformedEdit(textEdit: TextEdit) { + const range = getWellformedRange(textEdit.range) + if (range !== textEdit.range) { + return { newText: textEdit.newText, range } + } + return textEdit +} + +export function mergeSort(data: T[], compare: (a: T, b: T) => number): T[] { + if (data.length <= 1) { + // sorted + return data + } + const p = (data.length / 2) | 0 + const left = data.slice(0, p) + const right = data.slice(p) + mergeSort(left, compare) + mergeSort(right, compare) + let leftIdx = 0 + let rightIdx = 0 + let i = 0 + while (leftIdx < left.length && rightIdx < right.length) { + let ret = compare(left[leftIdx], right[rightIdx]) + if (ret <= 0) { + // smaller_equal -> take left to preserve order + data[i++] = left[leftIdx++] + } else { + // greater -> take right + data[i++] = right[rightIdx++] + } + } + while (leftIdx < left.length) { + data[i++] = left[leftIdx++] + } + while (rightIdx < right.length) { + data[i++] = right[rightIdx++] + } + return data +} + +export function emptyTextEdit(edit: TextEdit): boolean { + return emptyRange(edit.range) && edit.newText.length === 0 +} + +export function emptyWorkspaceEdit(edit: WorkspaceEdit): boolean { + let { changes, documentChanges } = edit + if (documentChanges && documentChanges.length) return false + if (changes && Object.keys(changes).length) return false + return true +} + +export function getConfirmAnnotations(changes: ReadonlyArray, changeAnnotations: { [id: string]: ChangeAnnotation }): ReadonlyArray { + let keys: string[] = [] + for (let change of changes) { + let key = getAnnotationKey(change) + if (key && !keys.includes(key) && changeAnnotations[key]?.needsConfirmation) keys.push(key) + } + return keys +} + +export function getAnnotationKey(change: DocumentChange): string | undefined { + let key: string + if (TextDocumentEdit.is(change)) { + if (AnnotatedTextEdit.is(change.edits[0])) { + key = change.edits[0].annotationId + } + } else { + key = change.annotationId + } + return key +} + +export function toDocumentChanges(edit: WorkspaceEdit): DocumentChange[] { + if (edit.documentChanges) return edit.documentChanges + let changes: DocumentChange[] = [] + if (edit.changes) { + for (let [uri, edits] of Object.entries(edit.changes)) { + changes.push({ textDocument: { uri, version: null }, edits }) + } + } + return changes +} + +/** + * Filter unnessary edits and fix edits. + */ +export function filterSortEdits(textDocument: LinesTextDocument, edits: TextEdit[]): TextEdit[] { + let res: TextEdit[] = [] + let end = textDocument.end + let checkEnd = end.line > 0 && end.character == 0 + let prevDelete: Position | undefined + for (let i = 0; i < edits.length; i++) { + let edit = edits[i] + let { newText } = edit + let range = toValidRange(edit.range) + if (prevDelete) { + // merge possible delete, insert edits. + if (samePosition(prevDelete, range.start) && emptyRange(range) && newText.length > 0) { + let last = res[res.length - 1] + last.newText = newText + prevDelete = undefined + continue + } + prevDelete = undefined + } + if (newText.includes('\r')) newText = newText.replace(/\r\n/g, '\n') + let d = comparePosition(range.end, end) + if (d > 0) range.end = { line: end.line, character: end.character } + if (textDocument.getText(range) !== newText) { + // Adjust textEdit to make it acceptable by nvim_buf_set_text + if (d === 0 && checkEnd && !emptyRange(range) && newText.endsWith('\n')) { + newText = newText.slice(0, -1) + let text = textDocument.lines[end.line - 1] + range.end = Position.create(end.line - 1, text.length) + } else if (newText.length == 0) { + prevDelete = range.start + } + res.push({ range, newText }) + } + } + return mergeSort(res, (a, b) => { + let diff = a.range.start.line - b.range.start.line + if (diff === 0) { + return a.range.start.character - b.range.start.character + } + return diff + }) +} + +/** + * Apply valid & sorted edits + */ +export function applyEdits(document: LinesTextDocument, edits: TextEdit[]): string[] | undefined { + if (edits.length == 1) { + let { start, end } = edits[0].range + let { lines } = document + let sl = lines[start.line] ?? '' + let el = lines[end.line] ?? '' + let content = sl.substring(0, start.character) + edits[0].newText + el.substring(end.character) + if (end.line >= lines.length && document.eol) { + if (content == '') return [...lines.slice(0, start.line)] + if (content.endsWith('\n')) content = content.slice(0, -1) + return [...lines.slice(0, start.line), ...content.split('\n')] + } + return [...lines.slice(0, start.line), ...content.split('\n'), ...lines.slice(end.line + 1)] + } + let text = document.getText() + let lastModifiedOffset = 0 + const spans = [] + for (const e of edits) { + let startOffset = document.offsetAt(e.range.start) + if (startOffset < lastModifiedOffset) { + throw new Error('Overlapping edit') + } + else if (startOffset > lastModifiedOffset) { + spans.push(text.substring(lastModifiedOffset, startOffset)) + } + if (e.newText.length) { + spans.push(e.newText) + } + lastModifiedOffset = document.offsetAt(e.range.end) + } + spans.push(text.substring(lastModifiedOffset)) + let result = spans.join('') + if (result === text) return undefined + return contentToLines(result, document.eol) +} + +export function toTextChanges(lines: ReadonlyArray, edits: TextEdit[]): TextChangeItem[] { + return edits.map(o => { + let { start, end } = o.range + let sl = lines[start.line] ?? '' + let sc = byteLength(sl.slice(0, start.character)) + let el = end.line == start.line ? sl : lines[end.line] ?? '' + let ec = byteLength(el.slice(0, end.character)) + let { newText } = o + return [newText.length > 0 ? newText.split('\n') : [], start.line, sc, end.line, ec] + }) +} + +export function getChangedPosition(start: Position, edit: TextEdit): { line: number; character: number } { + let { range, newText } = edit + if (comparePosition(range.end, start) <= 0) { + let lines = newText.split('\n') + let lineCount = lines.length - (range.end.line - range.start.line) - 1 + let character = start.character + if (range.end.line == start.line) { + let last = lines[lines.length - 1].length + if (lines.length > 1) { + character = last + character - range.end.character + } else { + character = range.start.character + last + character - range.end.character + } + } + return { line: lineCount, character: character - start.character } + } + return { line: 0, character: 0 } +} + +export function getPosition(start: Position, edit: TextEdit): Position { + let { line, character } = start + let { range, newText } = edit + let { end } = range + let lines = newText.split('\n') + let lineCount = lines.length - (end.line - range.start.line) - 1 + let c = range.end.line - start.line + if (c > 0) return { line, character } + if (c < 0) return { line: line + lineCount, character } + if (lines.length > 1) { + let last = lines[lines.length - 1].length + return { line: line + lineCount, character: last + character - end.character } + } + let d = range.start.character - range.end.character + return { line: line + lineCount, character: d + newText.length + character } +} + +/** + * Get new position from sorted edits + */ +export function getPositionFromEdits(start: Position, edits: TextEdit[]): Position { + let position = Position.create(start.line, start.character) + let before = false + for (let i = edits.length - 1; i >= 0; i--) { + let edit = edits[i] + if (before) { + position.line += lineCountChange(edit) + continue + } + let d = comparePosition(edit.range.end, position) + if (d > 0) continue + if (edit.range.end.line == position.line) { + position = getPosition(position, edit) + } else { + before = true + position.line += lineCountChange(edit) + } + } + return position +} + +export function getChangedLineCount(start: Position, edits: TextEdit[]): number { + let total = 0 + for (let edit of edits) { + let r = getWellformedRange(edit.range) + if (comparePosition(r.end, start) <= 0) { + total += lineCountChange(edit) + } + } + return total +} + +/** + * Merge sorted edits to single textedit + */ +export function mergeTextEdits(edits: TextEdit[], oldLines: ReadonlyArray, newLines: ReadonlyArray): TextEdit { + let start = edits[0].range.start + let end = edits[edits.length - 1].range.end + let lr = oldLines.length - end.line + let cr = (oldLines[end.line] ?? '').length - end.character + let line = newLines.length - lr + let character = (newLines[line] ?? '').length - cr + let newText = getText(start, Position.create(line, character), newLines) + return TextEdit.replace(Range.create(start, end), newText) +} + +function getText(start: Position, end: Position, lines: ReadonlyArray): string { + if (start.line === end.line) { + return (lines[start.line] ?? '').slice(start.character, end.character) + } + let spans: string[] = [] + for (let i = start.line; i <= end.line; i++) { + let s = lines[i] ?? '' + if (i === start.line) { + spans.push(s.slice(start.character)) + } else if (i === end.line) { + spans.push(s.slice(0, end.character)) + } else { + spans.push(s) + } + } + return spans.join('\n') +} diff --git a/sources_non_forked/coc.nvim/src/window.ts b/sources_non_forked/coc.nvim/src/window.ts new file mode 100644 index 00000000..f40dcfdf --- /dev/null +++ b/sources_non_forked/coc.nvim/src/window.ts @@ -0,0 +1,935 @@ +'use strict' +import { Neovim } from '@chemzqm/neovim' +import fs from 'fs' +import path from 'path' +import { CancellationToken, Emitter, Event, Position, Range } from 'vscode-languageserver-protocol' +import { URI } from 'vscode-uri' +import channels from './core/channels' +import { TextEditor } from './core/editors' +import Terminals from './core/terminals' +import * as ui from './core/ui' +import Cursors from './cursors/index' +import events from './events' +import languages from './languages' +import Dialog, { DialogConfig, DialogPreferences } from './model/dialog' +import Highligher from './model/highligher' +import InputBox, { InputOptions, InputPreference } from './model/input' +import Menu, { isMenuItem, MenuItem } from './model/menu' +import Notification, { NotificationConfig, NotificationKind, NotificationPreferences } from './model/notification' +import Picker from './model/picker' +import ProgressNotification, { Progress } from './model/progress' +import QuickPick, { QuickPickConfig } from './model/quickpick' +import StatusLine, { StatusBarItem } from './model/status' +import TerminalModel, { TerminalOptions } from './model/terminal' +import { TreeView, TreeViewOptions } from './tree' +import { Env, HighlightDiff, HighlightItem, HighlightItemDef, HighlightItemResult, MenuOption, MessageItem, MessageLevel, MsgTypes, OpenTerminalOption, OutputChannel, ProgressOptions, QuickPickItem, QuickPickOptions, ScreenPosition, StatusItemOption, TerminalResult } from './types' +import { CONFIG_FILE_NAME } from './util' +import { isParentFolder, sameFile } from './util/fs' +import { Mutex } from './util/mutex' +import { equals } from './util/object' +import { isWindows } from './util/platform' +import workspace from './workspace' +const logger = require('./util/logger')('window') +const PLUGIN_ROOT = path.dirname(__dirname) +let tab_global_id = 3000 +export type MessageKind = 'Error' | 'Warning' | 'Info' +export type Item = QuickPickItem | string + +export const PROVIDER_NAMES = [ + 'formatOnType', + 'rename', + 'onTypeEdit', + 'documentLink', + 'documentColor', + 'foldingRange', + 'format', + 'codeAction', + 'formatRange', + 'hover', + 'signature', + 'documentSymbol', + 'documentHighlight', + 'definition', + 'declaration', + 'typeDefinition', + 'reference', + 'implementation', + 'codeLens', + 'selectionRange', + 'callHierarchy', + 'semanticTokens', + 'semanticTokensRange', + 'linkedEditing' +] + +function generateTabId(): number { + return tab_global_id++ +} + +function convertHighlightItem(item: HighlightItem): HighlightItemDef { + return [item.hlGroup, item.lnum, item.colStart, item.colEnd, item.combine ? 1 : 0, item.start_incl ? 1 : 0, item.end_incl ? 1 : 0] +} + +function isSame(item: HighlightItem, curr: HighlightItemResult): boolean { + let arr = [item.hlGroup, item.lnum, item.colStart, item.colEnd] + return equals(arr, curr.slice(0, 4)) +} + +export class Window { + public mutex = new Mutex() + private tabIds: number[] = [] + private statusLine: StatusLine | undefined + private terminalManager: Terminals = new Terminals() + private readonly _onDidTabClose = new Emitter() + public readonly onDidTabClose: Event = this._onDidTabClose.event + public readonly cursors: Cursors + + public init(env: Env): void { + for (let i = 1; i <= env.tabCount; i++) { + this.tabIds.push(generateTabId()) + } + events.on('TabNew', (nr: number) => { + this.tabIds.splice(nr - 1, 0, generateTabId()) + }) + events.on('TabClosed', (nr: number) => { + let id = this.tabIds[nr - 1] + this.tabIds.splice(nr - 1, 1) + if (id) this._onDidTabClose.fire(id) + }) + } + + public getTabNumber(id: number): number | undefined { + if (!this.tabIds.includes(id)) return undefined + return this.tabIds.indexOf(id) + 1 + } + + public getTabId(nr: number): number | undefined { + return this.tabIds[nr - 1] + } + + public get nvim(): Neovim { + return workspace.nvim + } + + public dispose(): void { + this.terminalManager.dispose() + this.statusLine?.dispose() + } + + public get activeTextEditor(): TextEditor | undefined { + return workspace.editors.activeTextEditor + } + + public get visibleTextEditors(): TextEditor[] { + return workspace.editors.visibleTextEditors + } + + public get onDidChangeActiveTextEditor(): Event { + return workspace.editors.onDidChangeActiveTextEditor + } + + public get onDidChangeVisibleTextEditors(): Event> { + return workspace.editors.onDidChangeVisibleTextEditors + } + + public get terminals(): ReadonlyArray { + return this.terminalManager.terminals + } + + public get onDidOpenTerminal(): Event { + return this.terminalManager.onDidOpenTerminal + } + + public get onDidCloseTerminal(): Event { + return this.terminalManager.onDidCloseTerminal + } + + public async createTerminal(opts: TerminalOptions): Promise { + return await this.terminalManager.createTerminal(this.nvim, opts) + } + /** + * Reveal message with message type. + * + * @param msg Message text to show. + * @param messageType Type of message, could be `error` `warning` and `more`, default to `more` + */ + public showMessage(msg: string, messageType: MsgTypes = 'more'): void { + let { messageLevel } = this + let hl: 'Error' | 'MoreMsg' | 'WarningMsg' = 'Error' + let level = MessageLevel.Error + switch (messageType) { + case 'more': + level = MessageLevel.More + hl = 'MoreMsg' + break + case 'warning': + level = MessageLevel.Warning + hl = 'WarningMsg' + break + } + if (level >= messageLevel) { + ui.showMessage(this.nvim, msg, hl) + } + } + + /** + * Run command in vim terminal for result + * + * @param cmd Command to run. + * @param cwd Cwd of terminal, default to result of |getcwd()|. + */ + public async runTerminalCommand(cmd: string, cwd?: string, keepfocus = false): Promise { + cwd = cwd || workspace.cwd + return await this.nvim.callAsync('coc#ui#run_terminal', { cmd, cwd, keepfocus: keepfocus ? 1 : 0 }) as TerminalResult + } + + /** + * Open terminal window. + * + * @param cmd Command to run. + * @param opts Terminal option. + * @returns number buffer number of terminal + */ + public async openTerminal(cmd: string, opts: OpenTerminalOption = {}): Promise { + let bufnr = await this.nvim.call('coc#ui#open_terminal', { cmd, ...opts }) + return bufnr as number + } + + /** + * Show quickpick for single item, use `window.menuPick` for menu at current current position. + * + * @deprecated Use 'window.showMenuPicker()' or `window.showQuickPick` instead. + * @param items Label list. + * @param placeholder Prompt text, default to 'choose by number'. + * @returns Index of selected item, or -1 when canceled. + */ + public async showQuickpick(items: string[], placeholder = 'Choose by number'): Promise { + return await this.showMenuPicker(items, { title: placeholder, position: 'center' }) + } + + /** + * Shows a selection list. + */ + public async showQuickPick(itemsOrItemsPromise: Item[] | Promise, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Promise { + this.checkDialog('showQuickPick') + options = options || {} + const items = await Promise.resolve(itemsOrItemsPromise) + let isText = items.some(s => typeof s === 'string') + if (token.isCancellationRequested) return undefined + return await this.mutex.use(() => { + return new Promise((resolve, reject) => { + if (token.isCancellationRequested) return resolve(undefined) + let quickpick = new QuickPick(this.nvim, { + items: items.map(o => typeof o === 'string' ? { label: o } : o), + title: options.title ?? '', + canSelectMany: options.canPickMany + }) + quickpick.matchOnDescription = options.matchOnDescription + quickpick.onDidFinish(items => { + if (items == null) return resolve(undefined) + let arr = isText ? items.map(o => o.label) : items + if (options.canPickMany) return resolve(arr) + resolve(arr[0]) + }) + quickpick.show(this.dialogPreference).catch(reject) + }) + }) + } + + /** + * Creates a {@link QuickPick} to let the user pick an item or items from a + * list of items of type T. + * + * Note that in many cases the more convenient {@link window.showQuickPick} + * is easier to use. {@link window.createQuickPick} should be used + * when {@link window.showQuickPick} does not offer the required flexibility. + * + * @return A new {@link QuickPick}. + */ + public async createQuickPick(config: QuickPickConfig): Promise> { + this.checkDialog('createQuickPick') + return await this.mutex.use(async () => { + let quickpick = new QuickPick(this.nvim, config) + await quickpick.show(this.dialogPreference) + return quickpick + }) + } + + /** + * Show menu picker at current cursor position, |inputlist()| is used as fallback. + * Use `workspace.env.dialog` to check if the picker window/popup could work. + * + * @param items Array of texts. + * @param option Options for menu. + * @param token A token that can be used to signal cancellation. + * @returns Selected index (0 based), -1 when canceled. + */ + public async showMenuPicker(items: string[] | MenuItem[], option?: MenuOption, token?: CancellationToken): Promise { + if (workspace.env.dialog) { + return await this.mutex.use(async () => { + if (token && token.isCancellationRequested) return -1 + option = option || {} + if (typeof option === 'string') option = { title: option } + let menu = new Menu(this.nvim, { items, ...option }, token) + let promise = new Promise(resolve => { + menu.onDidClose(selected => { + resolve(selected) + }) + }) + await menu.show(this.dialogPreference) + return await promise + }) + } else { + return await this.mutex.use(async () => { + let placeholder = typeof option === 'string' ? option : option.title ?? (option.content ?? '') + 'Choose by number' + let title = placeholder + ':' + let titles: string[] = [] + let idx = 1 + for (const item of items) { + if (isMenuItem(item) && item.disabled) continue + titles.push(`${idx}. ${isMenuItem(item) ? item.text : item}`) + idx++ + } + let res = await this.nvim.callAsync('coc#ui#quickpick', [title, titles.map(s => s.trim())]) + let n = parseInt(res, 10) + if (isNaN(n) || n <= 0 || n > items.length) return -1 + return n - 1 + }) + } + } + + /** + * Open local config file + */ + public async openLocalConfig(): Promise { + let fsPath = await this.nvim.call('expand', ['%:p']) + let filetype = await this.nvim.eval('&filetype') as string + if (!fsPath || !path.isAbsolute(fsPath)) { + throw new Error(`current buffer doesn't have valid file path.`) + } + let folder = workspace.getWorkspaceFolder(URI.file(fsPath).toString()) + if (!folder) { + let c = workspace.getConfiguration('coc.preferences') + let patterns = c.get('rootPatterns', []) + let w = workspace.getConfiguration('workspace') + let ignored = w.get('ignoredFiletypes', []) + if (ignored.includes(filetype)) { + throw new Error(`Can't resolve workspace folder for current file, current filetype exclude for workspace folder resolve.`) + } + throw new Error(`Can't resolve workspace folder for current file, consider create one of ${patterns.join(', ')} in your project root.`) + } + let root = URI.parse(folder.uri).fsPath + let dir = path.join(root, '.vim') + if (!fs.existsSync(dir)) { + let res = await this.showPrompt(`Would you like to create folder'${root}/.vim'?`) + if (!res) return + fs.mkdirSync(dir) + } + let filepath = path.join(dir, CONFIG_FILE_NAME) + await this.nvim.call('coc#util#open_file', ['edit', filepath]) + } + + /** + * Prompt user for confirm, a float/popup window would be used when possible, + * use vim's |confirm()| function as callback. + * + * @param title The prompt text. + * @returns Result of confirm. + */ + public async showPrompt(title: string): Promise { + return await this.mutex.use(() => { + return ui.showPrompt(this.nvim, title) + }) + } + + /** + * Show dialog window at the center of screen. + * Note that the dialog would always be closed after button click. + * Use `workspace.env.dialog` to check if dialog could work. + * + * @param config Dialog configuration. + * @returns Dialog or null when dialog can't work. + */ + public async showDialog(config: DialogConfig): Promise

    { + this.checkDialog('showDialog') + return await this.mutex.use(async () => { + let dialog = new Dialog(this.nvim, config) + await dialog.show(this.dialogPreference) + return dialog + }) + } + + /** + * Request input from user + * + * @param title Title text of prompt window. + * @param defaultValue Default value of input, empty text by default. + * @param {InputOptions} option for input window + * @returns {Promise} + */ + public async requestInput(title: string, defaultValue?: string, option?: InputOptions): Promise { + let { nvim } = this + const preferences = workspace.getConfiguration('coc.preferences') + if (workspace.env.dialog && preferences.get('promptInput', true) && !isWindows) { + return await this.mutex.use(async () => { + let input = new InputBox(nvim, defaultValue ?? '') + await input.show(title, Object.assign(this.inputPreference, option ?? {})) + return await new Promise(resolve => { + input.onDidFinish(text => { + resolve(text) + }) + }) + }) + } else { + return await this.mutex.use(async () => { + let res = await workspace.callAsync('input', [title + ': ', defaultValue || '']) + nvim.command('normal! :', true) + return res + }) + } + } + + /** + * Creates and show a {@link InputBox} to let the user enter some text input. + * + * @return A new {@link InputBox}. + */ + public async createInputBox(title: string, defaultValue: string | undefined, option: InputPreference): Promise { + this.checkDialog('createInputBox') + let input = new InputBox(this.nvim, defaultValue ?? '') + await input.show(title, Object.assign(this.inputPreference, option)) + return input + } + + /** + * Create statusbar item that would be included in `g:coc_status`. + * + * @param priority Higher priority item would be shown right. + * @param option + * @return A new status bar item. + */ + public createStatusBarItem(priority = 0, option: StatusItemOption = {}): StatusBarItem { + if (!workspace.env) { + let fn = () => {} + return { text: '', show: fn, dispose: fn, hide: fn, priority: 0, isProgress: false } + } + if (!this.statusLine) { + this.statusLine = new StatusLine(this.nvim) + } + return this.statusLine.createStatusBarItem(priority, option.progress || false) + } + + /** + * Create a new output channel + * + * @param name Unique name of output channel. + * @returns A new output channel. + */ + public createOutputChannel(name: string): OutputChannel { + return channels.create(name, this.nvim) + } + + /** + * Reveal buffer of output channel. + * + * @param name Name of output channel. + * @param preserveFocus Preserve window focus when true. + */ + public showOutputChannel(name: string, preserveFocus?: boolean): void { + let config = workspace.getConfiguration('workspace') + let command = config.get('openOutputCommand', 'vs') + channels.show(name, command, preserveFocus) + } + + /** + * Echo lines at the bottom of vim. + * + * @param lines Line list. + * @param truncate Truncate the lines to avoid 'press enter to continue' when true + */ + public async echoLines(lines: string[], truncate = false): Promise { + let { nvim } = this + let cmdHeight = workspace.env.cmdheight + if (lines.length > cmdHeight && truncate) { + lines = lines.slice(0, cmdHeight) + } + let maxLen = workspace.env.columns - 12 + lines = lines.map(line => { + line = line.replace(/\n/g, ' ') + if (truncate) line = line.slice(0, maxLen) + return line + }) + if (truncate && lines.length == cmdHeight) { + let last = lines[lines.length - 1] + lines[cmdHeight - 1] = `${last.length == maxLen ? last.slice(0, -4) : last} ...` + } + await nvim.call('coc#ui#echo_lines', [lines]) + } + + /** + * Get current cursor position (line, character both 0 based). + * + * @returns Cursor position. + */ + public getCursorPosition(): Promise { + return ui.getCursorPosition(this.nvim) + } + + /** + * Move cursor to position. + * + * @param position LSP position. + */ + public async moveTo(position: Position): Promise { + await ui.moveTo(this.nvim, position, workspace.env.isVim) + } + + /** + * Get selected range for current document + */ + public getSelectedRange(mode: string): Promise { + return ui.getSelection(this.nvim, mode) + } + + /** + * Visual select range of current document + */ + public async selectRange(range: Range): Promise { + await ui.selectRange(this.nvim, range, this.nvim.isVim) + } + + /** + * Get current cursor character offset in document, + * length of line break would always be 1. + * + * @returns Character offset. + */ + public getOffset(): Promise { + return ui.getOffset(this.nvim) + } + + /** + * Get screen position of current cursor(relative to editor), + * both `row` and `col` are 0 based. + * + * @returns Cursor screen position. + */ + public getCursorScreenPosition(): Promise { + return ui.getCursorScreenPosition(this.nvim) + } + + /** + * Show multiple picker at center of screen. + * Use `workspace.env.dialog` to check if dialog could work. + * + * @param items Array of QuickPickItem or string. + * @param title Title of picker dialog. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + public async showPickerDialog(items: string[], title: string, token?: CancellationToken): Promise + public async showPickerDialog(items: T[], title: string, token?: CancellationToken): Promise + public async showPickerDialog(items: any, title: string, token?: CancellationToken): Promise { + this.checkDialog('showPickerDialog') + return await this.mutex.use(async () => { + if (token && token.isCancellationRequested) { + return undefined + } + let useString = typeof items[0] === 'string' + let picker = new Picker(this.nvim, { + title, + items: useString ? items.map(s => { + return { label: s } + }) : items, + }, token) + let promise = new Promise(resolve => { + picker.onDidClose(selected => { + resolve(selected) + }) + }) + await picker.show(this.dialogPreference) + let picked = await promise + let res = picked == undefined ? undefined : items.filter((_, i) => picked.includes(i)) + return res + }) + } + + /** + * Show an information message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + public async showInformationMessage(message: string, ...items: T[]): Promise { + let stack = Error().stack + return await this._showMessage('Info', message, items, stack) + } + + /** + * Show an warning message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + public async showWarningMessage(message: string, ...items: T[]): Promise { + let stack = Error().stack + return await this._showMessage('Warning', message, items, stack) + } + + /** + * Show an error message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + public async showErrorMessage(message: string, ...items: T[]): Promise { + let stack = Error().stack + return await this._showMessage('Error', message, items, stack) + } + + private async showMessagePicker(title: string, content: string, hlGroup: string, items: T[]): Promise { + let texts = items.map(o => typeof o === 'string' ? o : o.title) + let res = await this.showMenuPicker(texts, { + content, + title: title.replace(/\r?\n/, ' '), + borderhighlight: hlGroup + }) + return items[res] + } + + private async _showMessage(kind: MessageKind, message: string, items: T[], stack: string): Promise { + if (!this.enableMessageDialog) return await this.showConfirm(message, items, kind) as any + if (this.preferMenuPicker && items.length > 0) return await this.showMessagePicker('Choose action', message, `Coc${kind}Float`, items) + let texts = typeof items[0] === 'string' ? items : (items as any[]).map(s => s.title) + let idx = await this.createNotification(kind.toLowerCase() as NotificationKind, message, texts, stack) + return idx == -1 ? undefined : items[idx] + } + + public async showNotification(config: NotificationConfig): Promise { + this.checkDialog('showNotification') + let stack = Error().stack + let notification = new Notification(this.nvim, config) + await notification.show(this.getNotificationPreference(stack)) + } + + // fallback for vim without dialog + private async showConfirm(message: string, items: T[], kind: MessageKind): Promise { + if (!items || items.length == 0) { + let msgType: MsgTypes = kind == 'Info' ? 'more' : kind == 'Error' ? 'error' : 'warning' + this.showMessage(message, msgType) + return undefined + } + let titles: string[] = typeof items[0] === 'string' ? items.slice() as string[] : items.map(o => (o as MessageItem).title) + let choices = titles.map((s, i) => `${i + 1}${s}`) + let res = await this.nvim.callAsync('coc#util#with_callback', ['confirm', [message, choices.join('\n'), 0, kind]]) + return items[res - 1] + } + + /** + * Show progress in the editor. Progress is shown while running the given callback + * and while the promise it returned isn't resolved nor rejected. + */ + public async withProgress(options: ProgressOptions, task: (progress: Progress, token: CancellationToken) => Thenable): Promise { + this.checkDialog('withProgress') + let stack = Error().stack + let progress = new ProgressNotification(this.nvim, { + task, + title: options.title, + cancellable: options.cancellable + }) + let config = workspace.getConfiguration('notification') + let minWidth = config.get('minProgressWidth', 30) + let promise = new Promise(resolve => { + progress.onDidFinish(resolve) + }) + await progress.show(Object.assign(this.getNotificationPreference(stack, options.source), { minWidth })) + return await promise + } + + /** + * Create a {@link TreeView} instance. + * + * @param viewId Id of the view, used as title of TreeView when title doesn't exist. + * @param options Options for creating the {@link TreeView} + * @returns a {@link TreeView}. + */ + public createTreeView(viewId: string, options: TreeViewOptions): TreeView { + const BasicTreeView = require('./tree/TreeView').default + return new BasicTreeView(viewId, options) + } + + /** + * Get diff from highlight items and current highlights on vim. + * Return null when buffer not loaded + * + * @param bufnr Buffer number + * @param ns Highlight namespace + * @param items Highlight items + * @param region 0 based start and end line count (end exclusive) + * @param token CancellationToken + * @returns {Promise} + */ + public async diffHighlights(bufnr: number, ns: string, items: HighlightItem[], region?: [number, number] | undefined, token?: CancellationToken): Promise { + let args = [bufnr, ns] + if (Array.isArray(region)) args.push(region[0], region[1]) + let curr = await this.nvim.call('coc#highlight#get_highlights', args) as HighlightItemResult[] + if (!curr || token?.isCancellationRequested) return null + items.sort((a, b) => a.lnum - b.lnum) + let linesToRemove = [] + let checkMarkers = workspace.has('nvim-0.5.1') || workspace.isVim + let removeMarkers = [] + let newItems: HighlightItemDef[] = [] + let itemIndex = 0 + let maxIndex = items.length - 1 + let maxLnum = 0 + // highlights on vim + let map: Map = new Map() + curr.forEach(o => { + maxLnum = Math.max(maxLnum, o[1]) + let arr = map.get(o[1]) + if (arr) { + arr.push(o) + } else { + map.set(o[1], [o]) + } + }) + if (curr.length > 0) { + let start = Array.isArray(region) ? region[0] : 0 + for (let i = start; i <= maxLnum; i++) { + let exists = map.get(i) || [] + let added: HighlightItem[] = [] + for (let j = itemIndex; j <= maxIndex; j++) { + let o = items[j] + if (o.lnum == i) { + itemIndex = j + 1 + added.push(o) + } else { + itemIndex = j + break + } + } + if (added.length == 0) { + if (exists.length) { + if (checkMarkers) { + removeMarkers.push(...exists.map(o => o[4])) + } else { + linesToRemove.push(i) + } + } + } else { + if (exists.length == 0) { + newItems.push(...added.map(o => convertHighlightItem(o))) + } else if (added.length != exists.length || !(added.every((o, i) => isSame(o, exists[i])))) { + if (checkMarkers) { + removeMarkers.push(...exists.map(o => o[4])) + } else { + linesToRemove.push(i) + } + newItems.push(...added.map(o => convertHighlightItem(o))) + } + } + } + } + for (let i = itemIndex; i <= maxIndex; i++) { + newItems.push(convertHighlightItem(items[i])) + } + return { remove: linesToRemove, add: newItems, removeMarkers } + } + + /** + * Apply highlight diffs, normally used with `window.diffHighlights` + * + * Timer is used to add highlights when there're too many highlight items to add, + * the highlight process won't be finished on that case. + * + * @param {number} bufnr - Buffer name + * @param {string} ns - Namespace + * @param {number} priority + * @param {HighlightDiff} diff + * @param {boolean} notify - Use notification, default false. + * @returns {Promise} + */ + public async applyDiffHighlights(bufnr: number, ns: string, priority: number, diff: HighlightDiff, notify = false): Promise { + let { nvim } = this + let { remove, add, removeMarkers } = diff + if (remove.length === 0 && add.length === 0 && removeMarkers.length === 0) return + nvim.pauseNotification() + if (removeMarkers.length) { + nvim.call('coc#highlight#del_markers', [bufnr, ns, removeMarkers], true) + } + if (remove.length) { + nvim.call('coc#highlight#clear', [bufnr, ns, remove], true) + } + if (add.length) { + nvim.call('coc#highlight#set', [bufnr, ns, add, priority], true) + } + if (notify) { + nvim.resumeNotification(true, true) + } else { + await nvim.resumeNotification(true) + } + } + + public async bufferCheck(): Promise { + let doc = await workspace.document + let msg: string + if (!doc.attached) { + if (!doc.enabled) { + msg = 'Document not attached, b:coc_enabled is 0' + } else if (doc.buftype !== '' && doc.buftype !== 'acwrite') { + msg = `Document not attached with buftype '${doc.buftype}'` + } else { + msg = `Document not attached, file size exceed coc.preferences.maxFileSize` + } + } + if (msg) { + await this.showDialog({ + title: 'Buffer check result', + content: msg, + highlight: 'WarningMsg' + }) + return + } + let hi = new Highligher() + hi.addLine('Provider state', 'Title') + hi.addLine('') + for (let name of PROVIDER_NAMES) { + let exists = languages.hasProvider(name, doc.textDocument) + hi.addTexts([ + { text: '-', hlGroup: 'Comment' }, + { text: ' ' }, + exists ? { text: '✓', hlGroup: 'CocListFgGreen' } : { text: '✗', hlGroup: 'CocListFgRed' }, + { text: ' ' }, + { text: name, hlGroup: exists ? 'Normal' : 'CocFadeOut' } + ]) + } + await this.showDialog({ + title: 'Buffer check result', + content: hi.content, + highlights: hi.highlights + }) + } + + private createNotification(kind: NotificationKind, message: string, items: string[], stack: string): Promise { + return new Promise((resolve, reject) => { + let config: NotificationConfig = { + kind, + content: message, + buttons: items.map((s, index) => { + return { text: s, index } + }), + callback: idx => { + resolve(idx) + } + } + let notification = new Notification(this.nvim, config) + notification.show(this.getNotificationPreference(stack)).catch(reject) + }) + } + + /** + * Get extension name from error stack + */ + public parseSource(stack: string, level = 2): string | undefined { + let line = stack.split(/\r?\n/).slice(level)[0] + if (!line) return undefined + line = line.replace(/^\s*at\s*/, '') + let filepath: string + if (line.endsWith(')')) { + let ms = line.match(/(\((.*?):\d+:\d+\))$/) + if (ms) filepath = ms[2] + } else { + let ms = line.match(/(.*?):\d+:\d+$/) + if (ms) filepath = ms[1] + } + if (!filepath) return undefined + let arr = require('./extensions').default.getExtensionsInfo() + let find = arr.find(o => sameFile(o.filepath, filepath)) + if (find) return find.name.startsWith('single') ? path.basename(find.filepath) : find.name + find = arr.find(o => isParentFolder(o.directory, filepath)) + if (find) return find.name + if (isParentFolder(PLUGIN_ROOT, filepath)) return 'coc.nvim' + } + + private get dialogPreference(): DialogPreferences { + let config = workspace.getConfiguration('dialog') + return { + rounded: config.get('rounded', true), + maxWidth: config.get('maxWidth'), + maxHeight: config.get('maxHeight'), + floatHighlight: config.get('floatHighlight'), + floatBorderHighlight: config.get('floatBorderHighlight'), + pickerButtons: config.get('pickerButtons'), + pickerButtonShortcut: config.get('pickerButtonShortcut'), + confirmKey: config.get('confirmKey'), + shortcutHighlight: config.get('shortcutHighlight') + } + } + + private get inputPreference(): InputPreference { + let config = workspace.getConfiguration('dialog') + return { + rounded: config.get('rounded', true), + maxWidth: config.get('maxWidth'), + highlight: config.get('floatHighlight'), + borderhighlight: config.get('floatBorderHighlight'), + } + } + + private getNotificationPreference(stack: string, source?: string): NotificationPreferences { + if (!source) source = this.parseSource(stack) + let config = workspace.getConfiguration('notification') + let disabledList = config.get('disabledProgressSources', []) + let disabled = Array.isArray(disabledList) && (disabledList.includes('*') || disabledList.includes(source)) + return { + broder: config.get('border', true), + focusable: config.get('focusable', true), + marginRight: config.get('marginRight', 10), + timeout: config.get('timeout', 10), + maxWidth: config.get('maxWidth'), + maxHeight: config.get('maxHeight'), + highlight: config.get('highlightGroup'), + winblend: config.get('winblend'), + disabled, + source, + } + } + + private checkDialog(name: string): void { + if (workspace.env.dialog) return + throw new Error(`API window.${name} requires vim >= 8.2.0750 or neovim >= 0.4.0, please upgrade your vim`) + } + + private get enableMessageDialog(): boolean { + if (!workspace.env.dialog) return false + let config = workspace.getConfiguration('coc.preferences') + return config.get('enableMessageDialog', false) + } + + private get preferMenuPicker(): boolean { + if (!workspace.env.dialog) return false + let config = workspace.getConfiguration('notification') + return config.get('preferMenuPicker', false) + } + + public get messageLevel(): MessageLevel { + let config = workspace.getConfiguration('coc.preferences') + let level = config.get('messageLevel', 'more') + switch (level) { + case 'error': + return MessageLevel.Error + case 'warning': + return MessageLevel.Warning + default: + return MessageLevel.More + } + } +} + +export default new Window() diff --git a/sources_non_forked/coc.nvim/src/workspace.ts b/sources_non_forked/coc.nvim/src/workspace.ts new file mode 100644 index 00000000..91e4f852 --- /dev/null +++ b/sources_non_forked/coc.nvim/src/workspace.ts @@ -0,0 +1,552 @@ +'use strict' +import { NeovimClient as Neovim } from '@chemzqm/neovim' +import fs from 'fs-extra' +import os from 'os' +import path from 'path' +import { CancellationToken, CreateFileOptions, DeleteFileOptions, Disposable, DocumentSelector, Event, FormattingOptions, Location, LocationLink, Position, RenameFileOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceFoldersChangeEvent } from 'vscode-languageserver-protocol' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { URI } from 'vscode-uri' +import { version as VERSION } from '../package.json' +import Configurations from './configuration' +import ConfigurationShape from './configuration/shape' +import Autocmds from './core/autocmds' +import channels from './core/channels' +import ContentProvider from './core/contentProvider' +import Documents from './core/documents' +import Files, { GlobPattern } from './core/files' +import { FileSystemWatcher, FileSystemWatcherManager } from './core/fileSystemWatcher' +import { createNameSpace, findUp, getWatchmanPath, has, resolveModule, score } from './core/funcs' +import Keymaps from './core/keymaps' +import Locations from './core/locations' +import * as ui from './core/ui' +import Watchers from './core/watchers' +import Editors from './core/editors' +import WorkspaceFolderController from './core/workspaceFolder' +import events from './events' +import BufferSync, { SyncItem } from './model/bufferSync' +import DB from './model/db' +import type Document from './model/document' +import Mru from './model/mru' +import Task from './model/task' +import { LinesTextDocument } from './model/textdocument' +import { TextDocumentContentProvider } from './provider' +import { Autocmd, ConfigurationChangeEvent, ConfigurationTarget, DidChangeTextDocumentParams, EditerState, Env, FileCreateEvent, FileDeleteEvent, FileRenameEvent, FileWillCreateEvent, FileWillDeleteEvent, FileWillRenameEvent, IWorkspace, KeymapOption, LocalMode, QuickfixItem, TextDocumentWillSaveEvent, WorkspaceConfiguration } from './types' +import { CONFIG_FILE_NAME, MapMode, runCommand } from './util/index' + +const APIVERSION = 30 +const logger = require('./util/logger')('workspace') +const methods = [ + 'showMessage', 'runTerminalCommand', 'openTerminal', 'showQuickpick', + 'menuPick', 'openLocalConfig', 'showPrompt', 'createStatusBarItem', 'createOutputChannel', + 'showOutputChannel', 'requestInput', 'echoLines', 'getCursorPosition', 'moveTo', + 'getOffset', 'getSelectedRange', 'selectRange', 'createTerminal', +] + +export class Workspace implements IWorkspace { + public readonly onDidChangeConfiguration: Event + public readonly onDidOpenTextDocument: Event + public readonly onDidCloseTextDocument: Event + public readonly onDidChangeTextDocument: Event + public readonly onDidSaveTextDocument: Event + public readonly onWillSaveTextDocument: Event + public readonly onDidChangeWorkspaceFolders: Event + public readonly onDidRuntimePathChange: Event + public readonly onDidCreateFiles: Event + public readonly onDidRenameFiles: Event + public readonly onDidDeleteFiles: Event + public readonly onWillCreateFiles: Event + public readonly onWillRenameFiles: Event + public readonly onWillDeleteFiles: Event + public readonly nvim: Neovim + public readonly version: string + public readonly configurations: Configurations + public readonly workspaceFolderControl: WorkspaceFolderController + public readonly documentsManager: Documents + public readonly contentProvider: ContentProvider + public readonly autocmds: Autocmds + public readonly watchers: Watchers + public readonly keymaps: Keymaps + public readonly locations: Locations + public readonly files: Files + public readonly fileSystemWatchers: FileSystemWatcherManager + public readonly editors: Editors + + private _env: Env + + constructor() { + this.version = VERSION + let home = path.normalize(process.env.COC_VIMCONFIG) || path.join(os.homedir(), '.vim') + let userConfigFile = path.join(home, CONFIG_FILE_NAME) + this.configurations = new Configurations(userConfigFile, new ConfigurationShape(this)) + this.workspaceFolderControl = new WorkspaceFolderController(this.configurations) + let documents = this.documentsManager = new Documents(this.configurations, this.workspaceFolderControl) + this.contentProvider = new ContentProvider(documents) + this.watchers = new Watchers() + this.autocmds = new Autocmds(this.contentProvider, this.watchers) + this.keymaps = new Keymaps(documents) + this.locations = new Locations(this.configurations, documents, this.contentProvider) + this.files = new Files(documents, this.configurations, this.workspaceFolderControl, this.keymaps) + this.editors = new Editors(documents) + this.onDidRuntimePathChange = this.watchers.onDidRuntimePathChange + this.onDidChangeWorkspaceFolders = this.workspaceFolderControl.onDidChangeWorkspaceFolders + this.onDidChangeConfiguration = this.configurations.onDidChange + this.onDidOpenTextDocument = documents.onDidOpenTextDocument + this.onDidChangeTextDocument = documents.onDidChangeDocument + this.onDidCloseTextDocument = documents.onDidCloseDocument + this.onDidSaveTextDocument = documents.onDidSaveTextDocument + this.onWillSaveTextDocument = documents.onWillSaveTextDocument + this.onDidCreateFiles = this.files.onDidCreateFiles + this.onDidRenameFiles = this.files.onDidRenameFiles + this.onDidDeleteFiles = this.files.onDidDeleteFiles + this.onWillCreateFiles = this.files.onWillCreateFiles + this.onWillRenameFiles = this.files.onWillRenameFiles + this.onWillDeleteFiles = this.files.onWillDeleteFiles + let watchmanPath = global.__TEST__ ? null : this.getWatchmanPath() + this.fileSystemWatchers = new FileSystemWatcherManager(this.workspaceFolderControl, watchmanPath) + } + + public async init(window: any): Promise { + let { nvim } = this + for (let method of methods) { + Object.defineProperty(this, method, { + get: () => { + return (...args: any[]) => { + let stack = '\n' + Error().stack.split('\n').slice(2, 4).join('\n') + logger.warn(`workspace.${method} is deprecated, please use window.${method} instead.`, stack) + return window[method].apply(window, args) + } + } + }) + } + for (let name of ['onDidOpenTerminal', 'onDidCloseTerminal']) { + Object.defineProperty(this, name, { + get: () => { + let stack = '\n' + Error().stack.split('\n').slice(2, 4).join('\n') + logger.warn(`workspace.${name} is deprecated, please use window.${name} instead.`, stack) + return window[name] + } + }) + } + let env = this._env = await nvim.call('coc#util#vim_info') as Env + window.init(env) + if (this._env.apiversion != APIVERSION) { + nvim.echoError(`API version ${this._env.apiversion} is not ${APIVERSION}, please build coc.nvim by 'yarn install' after pull source code.`) + } + this.workspaceFolderControl.setWorkspaceFolders(this._env.workspaceFolders) + this.configurations.updateUserConfig(this._env.config) + this.files.attach(nvim, env, window) + this.contentProvider.attach(nvim) + this.keymaps.attach(nvim) + this.autocmds.attach(nvim, env) + this.locations.attach(nvim, env) + this.watchers.attach(nvim, env) + await this.attach() + await this.editors.attach(nvim) + let channel = channels.create('watchman', nvim) + this.fileSystemWatchers.attach(channel) + } + + public get cwd(): string { + return this.documentsManager.cwd + } + + public get env(): Env { + return this._env + } + + public get root(): string { + return this.documentsManager.root || this.cwd + } + + public get rootPath(): string { + return this.root + } + + public get bufnr(): number { + return this.documentsManager.bufnr + } + + /** + * @deprecated + */ + public get insertMode(): boolean { + return events.insertMode + } + + public get floatSupported(): boolean { + return this.env.floating || this.env.textprop + } + + /** + * @deprecated + */ + public get uri(): string { + return this.documentsManager.uri + } + + /** + * @deprecated + */ + public get workspaceFolder(): WorkspaceFolder { + return this.workspaceFolders[0] + } + + public get textDocuments(): TextDocument[] { + return this.documentsManager.textDocuments + } + + public get documents(): Document[] { + return this.documentsManager.documents + } + + public get document(): Promise { + return this.documentsManager.document + } + + public get workspaceFolders(): ReadonlyArray { + return this.workspaceFolderControl.workspaceFolders + } + + public get folderPaths(): string[] { + return this.workspaceFolders.map(f => URI.parse(f.uri).fsPath) + } + + public get channelNames(): string[] { + return channels.names + } + + public get pluginRoot(): string { + return path.dirname(__dirname) + } + + public get isVim(): boolean { + return this._env.isVim + } + + public get isNvim(): boolean { + return !this._env.isVim + } + + public get completeOpt(): string { + return this._env.completeOpt + } + + public get filetypes(): Set { + return this.documentsManager.filetypes + } + + public get languageIds(): Set { + return this.documentsManager.languageIds + } + + /** + * @deprecated + */ + public createNameSpace(name: string): number { + return createNameSpace(name) + } + + public getConfigFile(target: ConfigurationTarget): string { + return this.configurations.getConfigFile(target) + } + + public has(feature: string): boolean { + return has(this.env, feature) + } + + /** + * Register autocmd on vim. + */ + public registerAutocmd(autocmd: Autocmd): Disposable { + return this.autocmds.registerAutocmd(autocmd) + } + + /** + * Watch for option change. + */ + public watchOption(key: string, callback: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void { + this.watchers.watchOption(key, callback, disposables) + } + + /** + * Watch global variable, works on neovim only. + */ + public watchGlobal(key: string, callback?: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void { + this.watchers.watchGlobal(key, callback || function() {}, disposables) + } + + /** + * Check if selector match document. + */ + public match(selector: DocumentSelector, document: { uri: string, languageId: string }): number { + return score(selector, document.uri, document.languageId) + } + + /** + * Create a FileSystemWatcher instance, doesn't fail when watchman not found. + */ + public createFileSystemWatcher(globPattern: string, ignoreCreate?: boolean, ignoreChange?: boolean, ignoreDelete?: boolean): FileSystemWatcher { + return this.fileSystemWatchers.createFileSystemWatcher(globPattern, ignoreCreate, ignoreChange, ignoreDelete) + } + + public getWatchmanPath(): string | null { + return getWatchmanPath(this.configurations) + } + + /** + * Get configuration by section and optional resource uri. + */ + public getConfiguration(section?: string, resource?: string): WorkspaceConfiguration { + return this.configurations.getConfiguration(section, resource) + } + + /** + * Get created document by uri or bufnr. + */ + public getDocument(uri: number | string): Document | null { + return this.documentsManager.getDocument(uri) + } + + public isAttached(bufnr: number): boolean { + let doc = this.documentsManager.getDocument(bufnr) + return doc != null && doc.attached + } + + /** + * Get attached document by uri or bufnr. + * Throw error when document doesn't exist or isn't attached. + */ + public getAttachedDocument(uri: number | string): Document { + let doc = this.getDocument(uri) + if (!doc) throw new Error(`Buffer ${uri} not created.`) + if (!doc.attached) throw new Error(`Buffer ${uri} not attached, try :CocCommand document.checkBuffer`) + return doc + } + /** + * Convert location to quickfix item. + */ + public getQuickfixItem(loc: Location | LocationLink, text?: string, type = '', module?: string): Promise { + return this.documentsManager.getQuickfixItem(loc, text, type, module) + } + + /** + * Create persistence Mru instance. + */ + public createMru(name: string): Mru { + return new Mru(name) + } + + public async getQuickfixList(locations: Location[]): Promise> { + return this.documentsManager.getQuickfixList(locations) + } + + /** + * Populate locations to UI. + */ + public async showLocations(locations: Location[]): Promise { + await this.locations.showLocations(locations) + } + + /** + * Get content of line by uri and line. + */ + public getLine(uri: string, line: number): Promise { + return this.documentsManager.getLine(uri, line) + } + + /** + * Get WorkspaceFolder of uri + */ + public getWorkspaceFolder(uri: string): WorkspaceFolder | undefined { + return this.workspaceFolderControl.getWorkspaceFolder(URI.parse(uri)) + } + + /** + * Get content from buffer or file by uri. + */ + public readFile(uri: string): Promise { + return this.documentsManager.readFile(uri) + } + + public async getCurrentState(): Promise { + let document = await this.document + let position = await ui.getCursorPosition(this.nvim) + return { + document: document.textDocument, + position + } + } + + public async getFormatOptions(uri?: string): Promise { + return this.documentsManager.getFormatOptions(uri) + } + + /** + * Resolve module from yarn or npm. + */ + public resolveModule(name: string): Promise { + return resolveModule(name) + } + + /** + * Run nodejs command + */ + public async runCommand(cmd: string, cwd?: string, timeout?: number): Promise { + cwd = cwd || this.cwd + return runCommand(cmd, { cwd }, timeout) + } + + /** + * Expand filepath with `~` and/or environment placeholders + */ + public expand(filepath: string): string { + return this.documentsManager.expand(filepath) + } + + public async callAsync(method: string, args: any[]): Promise { + if (this.isNvim) return await this.nvim.call(method, args) + return await this.nvim.callAsync('coc#util#with_callback', [method, args]) + } + + public registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable { + return this.contentProvider.registerTextDocumentContentProvider(scheme, provider) + } + + public registerKeymap(modes: MapMode[], key: string, fn: Function, opts: Partial = {}): Disposable { + return this.keymaps.registerKeymap(modes, key, fn, opts) + } + + public registerExprKeymap(mode: 'i' | 'n' | 'v' | 's' | 'x', key: string, fn: Function, buffer = false): Disposable { + return this.keymaps.registerExprKeymap(mode, key, fn, buffer) + } + + public registerLocalKeymap(mode: LocalMode, key: string, fn: Function, notify = false): Disposable { + return this.keymaps.registerLocalKeymap(mode, key, fn, notify) + } + + /** + * Create Task instance that runs in vim. + */ + public createTask(id: string): Task { + return new Task(this.nvim, id) + } + + /** + * Create DB instance at extension root. + */ + public createDatabase(name: string): DB { + let root: string + if (global.hasOwnProperty('__TEST__')) { + root = path.join(os.tmpdir(), `coc-${process.pid}`) + fs.mkdirpSync(root) + } else { + root = path.dirname(this.env.extensionRoot) + } + let filepath = path.join(root, name + '.json') + return new DB(filepath) + } + + public registerBufferSync(create: (doc: Document) => T | undefined): BufferSync { + return new BufferSync(create, this.documentsManager) + } + + public async attach(): Promise { + await this.documentsManager.attach(this.nvim, this._env) + } + + public jumpTo(uri: string, position?: Position | null, openCommand?: string): Promise { + return this.files.jumpTo(uri, position, openCommand) + } + + /** + * Findup for filename or filenames from current filepath or root. + */ + public findUp(filename: string | string[]): Promise { + return findUp(this.nvim, this.cwd, filename) + } + + /** + * Apply WorkspaceEdit. + */ + public applyEdit(edit: WorkspaceEdit): Promise { + return this.files.applyEdit(edit) + } + + /** + * Create a file in vim and disk + */ + public createFile(filepath: string, opts: CreateFileOptions = {}): Promise { + return this.files.createFile(filepath, opts) + } + + /** + * Load uri as document. + */ + public loadFile(uri: string): Promise { + return this.files.loadResource(uri) + } + + /** + * Load the files that not loaded + */ + public async loadFiles(uris: string[]): Promise<(Document | undefined)[]> { + return this.files.loadResources(uris) + } + + /** + * Rename file in vim and disk + */ + public async renameFile(oldPath: string, newPath: string, opts: RenameFileOptions = {}): Promise { + await this.files.renameFile(oldPath, newPath, opts) + } + + /** + * Delete file from vim and disk. + */ + public async deleteFile(filepath: string, opts: DeleteFileOptions = {}): Promise { + await this.files.deleteFile(filepath, opts) + } + + public async renameCurrent(): Promise { + await this.files.renameCurrent() + } + + /** + * Open resource by uri + */ + public async openResource(uri: string): Promise { + await this.files.openResource(uri) + } + + public openTextDocument(uri: URI | string): Promise { + return this.files.openTextDocument(uri) + } + + public getRelativePath(pathOrUri: string | URI, includeWorkspace?: boolean): string { + return this.workspaceFolderControl.getRelativePath(pathOrUri, includeWorkspace) + } + + public async findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Promise { + return this.files.findFiles(include, exclude, maxResults, token) + } + + public detach(): void { + this.documentsManager.detach() + } + + public reset(): void { + this.configurations.reset() + this.workspaceFolderControl.reset() + this.documentsManager.reset() + } + + public dispose(): void { + this.watchers.dispose() + this.autocmds.dispose() + this.contentProvider.dispose() + this.documentsManager.dispose() + this.configurations.dispose() + } +} + +export default new Workspace() diff --git a/sources_non_forked/coc.nvim/tsconfig.json b/sources_non_forked/coc.nvim/tsconfig.json new file mode 100644 index 00000000..97b07dfb --- /dev/null +++ b/sources_non_forked/coc.nvim/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "outDir": "lib", + "strict": true, + "noEmit": true, + "sourceMap": true, + "importHelpers": true, + "allowUnreachableCode": false, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": false, + "noImplicitThis": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "strictPropertyInitialization": false, + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "lib": ["es2017", "es2018", "es2019"], + "declaration": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "strictNullChecks": false, + "strictFunctionTypes": false, + "plugins": [] + }, + "include": ["src"], + "exclude": ["typings", "build", "node_modules"] +} diff --git a/sources_non_forked/coc.nvim/typings/LICENSE b/sources_non_forked/coc.nvim/typings/LICENSE new file mode 100644 index 00000000..fc9556c9 --- /dev/null +++ b/sources_non_forked/coc.nvim/typings/LICENSE @@ -0,0 +1,19 @@ +Copyright 2020 chemzqm@gmail.com + +Permission 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: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE 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. diff --git a/sources_non_forked/coc.nvim/typings/Readme.md b/sources_non_forked/coc.nvim/typings/Readme.md new file mode 100644 index 00000000..b3ebe4eb --- /dev/null +++ b/sources_non_forked/coc.nvim/typings/Readme.md @@ -0,0 +1,18 @@ +This package contains typings of coc.nvim only. + +Files were exported from https://github.com/neoclide/coc.nvim/blob/master/typings + +## Installation + + npm install --save-dev coc.nvim + +## Support coc.nvim + +If you like my work, consider supporting me on Patreon or PayPal: + +Patreon donate button +PayPal donate button + +## Credits + +[Visual Studio Code](https://github.com/microsoft/vscode), and [Microsoft](https://github.com/microsoft) diff --git a/sources_non_forked/coc.nvim/typings/index.d.ts b/sources_non_forked/coc.nvim/typings/index.d.ts new file mode 100644 index 00000000..d4233f25 --- /dev/null +++ b/sources_non_forked/coc.nvim/typings/index.d.ts @@ -0,0 +1,10107 @@ +/****************************************************************** +MIT License http://www.opensource.org/licenses/mit-license.php +Author Qiming Zhao (https://github.com/chemzqm) +*******************************************************************/ + +/// +import cp from 'child_process' + +declare module 'coc.nvim' { + // Language server protocol interfaces {{ + export interface Thenable { + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable + // eslint-disable-next-line @typescript-eslint/unified-signatures + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable + } + + export interface Disposable { + /** + * Dispose this object. + */ + dispose(): void + } + + export namespace Disposable { + function create(func: () => void): Disposable + } + /** + * The declaration of a symbol representation as one or many [locations](#Location). + */ + export type Declaration = Location | Location[] + /** + * Information about where a symbol is declared. + * + * Provides additional metadata over normal [location](#Location) declarations, including the range of + * the declaring symbol. + * + * Servers should prefer returning `DeclarationLink` over `Declaration` if supported + * by the client. + */ + export type DeclarationLink = LocationLink + + export type ProgressToken = number | string + + export interface WorkDoneProgressBegin { + kind: 'begin' + /** + * Mandatory title of the progress operation. Used to briefly inform about + * the kind of operation being performed. + * + * Examples: "Indexing" or "Linking dependencies". + */ + title: string + /** + * Controls if a cancel button should show to allow the user to cancel the + * long running operation. Clients that don't support cancellation are allowed + * to ignore the setting. + */ + cancellable?: boolean + /** + * Optional, more detailed associated progress message. Contains + * complementary information to the `title`. + * + * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + * If unset, the previous progress message (if any) is still valid. + */ + message?: string + /** + * Optional progress percentage to display (value 100 is considered 100%). + * If not provided infinite progress is assumed and clients are allowed + * to ignore the `percentage` value in subsequent in report notifications. + * + * The value should be steadily rising. Clients are free to ignore values + * that are not following this rule. + */ + percentage?: number + } + + export interface WorkDoneProgressReport { + kind: 'report' + /** + * Controls enablement state of a cancel button. This property is only valid if a cancel + * button got requested in the `WorkDoneProgressStart` payload. + * + * Clients that don't support cancellation or don't support control the button's + * enablement state are allowed to ignore the setting. + */ + cancellable?: boolean + /** + * Optional, more detailed associated progress message. Contains + * complementary information to the `title`. + * + * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + * If unset, the previous progress message (if any) is still valid. + */ + message?: string + /** + * Optional progress percentage to display (value 100 is considered 100%). + * If not provided infinite progress is assumed and clients are allowed + * to ignore the `percentage` value in subsequent in report notifications. + * + * The value should be steadily rising. Clients are free to ignore values + * that are not following this rule. + */ + percentage?: number + } + + /** + * The file event type + */ + export namespace FileChangeType { + /** + * The file got created. + */ + const Created = 1 + /** + * The file got changed. + */ + const Changed = 2 + /** + * The file got deleted. + */ + const Deleted = 3 + } + + export type FileChangeType = 1 | 2 | 3 + + /** + * An event describing a file change. + */ + export interface FileEvent { + /** + * The file's uri. + */ + uri: string + /** + * The change type. + */ + type: FileChangeType + } + + export interface WorkDoneProgressEnd { + kind: 'end' + /** + * Optional, a final message indicating to for example indicate the outcome + * of the operation. + */ + message?: string + } + + /** + * A literal to identify a text document in the client. + */ + export interface TextDocumentIdentifier { + /** + * The text document's uri. + */ + uri: string + } + + /** + * A parameter literal used in requests to pass a text document and a position inside that + * document. + */ + export interface TextDocumentPositionParams { + /** + * The text document. + */ + textDocument: TextDocumentIdentifier + /** + * The position inside the text document. + */ + position: Position + } + + export interface WorkspaceFolder { + /** + * The associated URI for this workspace folder. + */ + uri: string + /** + * The name of the workspace folder. Used to refer to this + * workspace folder in the user interface. + */ + name: string + } + + /** + * An event describing a change to a text document. + */ + export interface TextDocumentContentChange { + /** + * The range of the document that changed. + */ + range: Range + /** + * The new text for the provided range. + */ + text: string + } + + /** + * The workspace folder change event. + */ + export interface WorkspaceFoldersChangeEvent { + /** + * The array of added workspace folders + */ + added: WorkspaceFolder[] + /** + * The array of the removed workspace folders + */ + removed: WorkspaceFolder[] + } + + /** + * An event that is fired when a [document](#LinesTextDocument) will be saved. + * + * To make modifications to the document before it is being saved, call the + * [`waitUntil`](#TextDocumentWillSaveEvent.waitUntil)-function with a thenable + * that resolves to an array of [text edits](#TextEdit). + */ + export interface TextDocumentWillSaveEvent { + + /** + * The document that will be saved. + */ + document: LinesTextDocument + + /** + * The reason why save was triggered. + */ + reason: 1 | 2 | 3 + } + + /** + * A document filter denotes a document by different properties like + * the [language](#LinesTextDocument.languageId), the [scheme](#Uri.scheme) of + * its resource, or a glob-pattern that is applied to the [path](#LinesTextDocument.fileName). + * + * Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + * + * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` + * @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` + */ + export type DocumentFilter = { + /** A language id, like `typescript`. */ + language: string + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme?: string + /** A glob pattern, like `*.{ts,js}`. */ + pattern?: string + } | { + /** A language id, like `typescript`. */ + language?: string + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme: string + /** A glob pattern, like `*.{ts,js}`. */ + pattern?: string + } | { + /** A language id, like `typescript`. */ + language?: string + /** A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + scheme?: string + /** A glob pattern, like `*.{ts,js}`. */ + pattern: string + } + /** + * A document selector is the combination of one or many document filters. + * + * @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; + */ + export type DocumentSelector = (string | DocumentFilter)[] + /** + * A selection range represents a part of a selection hierarchy. A selection range + * may have a parent selection range that contains it. + */ + export interface SelectionRange { + /** + * The [range](#Range) of this selection range. + */ + range: Range + /** + * The parent selection range containing this range. Therefore `parent.range` must contain `this.range`. + */ + parent?: SelectionRange + } + + /** + * MarkedString can be used to render human readable text. It is either a markdown string + * or a code-block that provides a language and a code snippet. The language identifier + * is semantically equal to the optional language identifier in fenced code blocks in GitHub + * issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting + * + * The pair of a language and a value is an equivalent to markdown: + * ```${language} + * ${value} + * ``` + * + * Note that markdown strings will be sanitized - that means html will be escaped. + * @deprecated use MarkupContent instead. + */ + export type MarkedString = string | { + language: string + value: string + } + /** + * The result of a hover request. + */ + export interface Hover { + /** + * The hover's content + */ + contents: MarkupContent | MarkedString | MarkedString[] + /** + * An optional range + */ + range?: Range + } + + /** + * The definition of a symbol represented as one or many [locations](#Location). + * For most programming languages there is only one location at which a symbol is + * defined. + * + * Servers should prefer returning `DefinitionLink` over `Definition` if supported + * by the client. + */ + export type Definition = Location | Location[] + + /** + * Information about where a symbol is defined. + * + * Provides additional metadata over normal [location](#Location) definitions, including the range of + * the defining symbol + */ + export type DefinitionLink = LocationLink + + /** + * How a signature help was triggered. + */ + export namespace SignatureHelpTriggerKind { + /** + * Signature help was invoked manually by the user or by a command. + */ + const Invoked: 1 + /** + * Signature help was triggered by a trigger character. + */ + const TriggerCharacter: 2 + /** + * Signature help was triggered by the cursor moving or by the document content changing. + */ + const ContentChange: 3 + } + + export type SignatureHelpTriggerKind = 1 | 2 | 3 + + /** + * Represents the signature of something callable. A signature + * can have a label, like a function-name, a doc-comment, and + * a set of parameters. + */ + export interface SignatureInformation { + /** + * The label of this signature. Will be shown in + * the UI. + */ + label: string + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string | MarkupContent + /** + * The parameters of this signature. + */ + parameters?: ParameterInformation[] + } + + /** + * Represents a parameter of a callable-signature. A parameter can + * have a label and a doc-comment. + */ + export interface ParameterInformation { + /** + * The label of this parameter information. + * + * Either a string or an inclusive start and exclusive end offsets within its containing + * signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 + * string representation as `Position` and `Range` does. + * + * *Note*: a label of type string should be a substring of its containing signature label. + * Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. + */ + label: string | [number, number] + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string | MarkupContent + } + + /** + * Signature help represents the signature of something + * callable. There can be multiple signature but only one + * active and only one active parameter. + */ + export interface SignatureHelp { + /** + * One or more signatures. + */ + signatures: SignatureInformation[] + /** + * The active signature. Set to `null` if no + * signatures exist. + */ + activeSignature: number | null + /** + * The active parameter of the active signature. Set to `null` + * if the active signature has no parameters. + */ + activeParameter: number | null + } + /** + * Additional information about the context in which a signature help request was triggered. + * + * @since 3.15.0 + */ + export interface SignatureHelpContext { + /** + * Action that caused signature help to be triggered. + */ + triggerKind: SignatureHelpTriggerKind + /** + * Character that caused signature help to be triggered. + * + * This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` + */ + triggerCharacter?: string + /** + * `true` if signature help was already showing when it was triggered. + * + * Retriggers occur when the signature help is already active and can be caused by actions such as + * typing a trigger character, a cursor move, or document content changes. + */ + isRetrigger: boolean + /** + * The currently active `SignatureHelp`. + * + * The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on + * the user navigating through available signatures. + */ + activeSignatureHelp?: SignatureHelp + } + + /** + * Represents a folding range. + */ + export interface FoldingRange { + /** + * The zero-based line number from where the folded range starts. + */ + startLine: number + /** + * The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + */ + startCharacter?: number + /** + * The zero-based line number where the folded range ends. + */ + endLine: number + /** + * The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + */ + endCharacter?: number + /** + * Describes the kind of the folding range such as `comment' or 'region'. The kind + * is used to categorize folding ranges and used by commands like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + */ + kind?: string + } + + /** + * A symbol kind. + */ + export namespace SymbolKind { + const File: 1 + const Module: 2 + const Namespace: 3 + const Package: 4 + const Class: 5 + const Method: 6 + const Property: 7 + const Field: 8 + const Constructor: 9 + const Enum: 10 + const Interface: 11 + const Function: 12 + const Variable: 13 + const Constant: 14 + const String: 15 + const Number: 16 + const Boolean: 17 + const Array: 18 + const Object: 19 + const Key: 20 + const Null: 21 + const EnumMember: 22 + const Struct: 23 + const Event: 24 + const Operator: 25 + const TypeParameter: 26 + } + + export type SymbolKind = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 + + /** + * Represents information about programming constructs like variables, classes, + * interfaces etc. + */ + export interface SymbolInformation { + /** + * The name of this symbol. + */ + name: string + /** + * The kind of this symbol. + */ + kind: SymbolKind + /** + * Indicates if this symbol is deprecated. + */ + deprecated?: boolean + /** + * The location of this symbol. The location's range is used by a tool + * to reveal the location in the editor. If the symbol is selected in the + * tool the range's start information is used to position the cursor. So + * the range usually spans more than the actual symbol's name and does + * normally include thinks like visibility modifiers. + * + * The range doesn't have to denote a node range in the sense of a abstract + * syntax tree. It can therefore not be used to re-construct a hierarchy of + * the symbols. + */ + location: Location + /** + * The name of the symbol containing this symbol. This information is for + * user interface purposes (e.g. to render a qualifier in the user interface + * if necessary). It can't be used to re-infer a hierarchy for the document + * symbols. + */ + containerName?: string + } + + /** + * Represents programming constructs like variables, classes, interfaces etc. + * that appear in a document. Document symbols can be hierarchical and they + * have two ranges: one that encloses its definition and one that points to + * its most interesting range, e.g. the range of an identifier. + */ + export interface DocumentSymbol { + /** + * The name of this symbol. Will be displayed in the user interface and therefore must not be + * an empty string or a string only consisting of white spaces. + */ + name: string + /** + * More detail for this symbol, e.g the signature of a function. + */ + detail?: string + /** + * The kind of this symbol. + */ + kind: SymbolKind + /** + * Indicates if this symbol is deprecated. + */ + deprecated?: boolean + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to determine if the the clients cursor is + * inside the symbol to reveal in the symbol in the UI. + */ + range: Range + /** + * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + * Must be contained by the the `range`. + */ + selectionRange: Range + /** + * Children of this symbol, e.g. properties of a class. + */ + children?: DocumentSymbol[] + } + + export interface FormattingOptions { + /** + * If indentation is based on spaces (`insertSpaces` = true), the number of spaces that make an indent. + */ + tabSize: number + /** + * Is indentation based on spaces? + */ + insertSpaces: boolean + /** + * Trim trailing whitespaces on a line. + * + * @since 3.15.0 + */ + trimTrailingWhitespace?: boolean + /** + * Insert a newline character at the end of the file if one does not exist. + * + * @since 3.15.0 + */ + insertFinalNewline?: boolean + /** + * Trim all newlines after the final newline at the end of the file. + * + * @since 3.15.0 + */ + trimFinalNewlines?: boolean + } + + /** + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ + export interface CodeActionContext { + /** + * An array of diagnostics known on the client side overlapping the range provided to the + * `textDocument/codeAction` request. They are provided so that the server knows which + * errors are currently presented to the user for the given range. There is no guarantee + * that these accurately reflect the error state of the resource. The primary parameter + * to compute code actions is the provided range. + */ + diagnostics: Diagnostic[] + /** + * Requested kind of actions to return. + * + * Actions not of this kind are filtered out by the client before being shown. So servers + * can omit computing them. + */ + only?: string[] + } + + + /** + * A document highlight kind. + */ + export namespace DocumentHighlightKind { + /** + * A textual occurrence. + */ + const Text: 1 + /** + * Read-access of a symbol, like reading a variable. + */ + const Read: 2 + /** + * Write-access of a symbol, like writing to a variable. + */ + const Write: 3 + } + + export type DocumentHighlightKind = 1 | 2 | 3 + /** + * A document highlight is a range inside a text document which deserves + * special attention. Usually a document highlight is visualized by changing + * the background color of its range. + */ + export interface DocumentHighlight { + /** + * The range this highlight applies to. + */ + range: Range + /** + * The highlight kind, default is [text](#DocumentHighlightKind.Text). + */ + kind?: DocumentHighlightKind + } + + /** + * A document link is a range in a text document that links to an internal or external resource, like another + * text document or a web site. + */ + export interface DocumentLink { + /** + * The range this link applies to. + */ + range: Range + /** + * The uri this link points to. + */ + target?: string + /** + * The tooltip text when you hover over this link. + * + * If a tooltip is provided, is will be displayed in a string that includes instructions on how to + * trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + * user settings, and localization. + * + * @since 3.15.0 + */ + tooltip?: string + /** + * A data entry field that is preserved on a document link between a + * DocumentLinkRequest and a DocumentLinkResolveRequest. + */ + data?: any + } + + /** + * Represents a color in RGBA space. + */ + export interface Color { + /** + * The red component of this color in the range [0-1]. + */ + readonly red: number + /** + * The green component of this color in the range [0-1]. + */ + readonly green: number + /** + * The blue component of this color in the range [0-1]. + */ + readonly blue: number + /** + * The alpha component of this color in the range [0-1]. + */ + readonly alpha: number + } + + /** + * Represents a color range from a document. + */ + export interface ColorInformation { + /** + * The range in the document where this color appears. + */ + range: Range + /** + * The actual color value for this color range. + */ + color: Color + } + + export interface ColorPresentation { + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + label: string + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + textEdit?: TextEdit + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + additionalTextEdits?: TextEdit[] + } + + /** + * A code lens represents a [command](#Command) that should be shown along with + * source text, like the number of references, a way to run tests, etc. + * + * A code lens is _unresolved_ when no command is associated to it. For performance + * reasons the creation of a code lens and resolving should be done to two stages. + */ + export interface CodeLens { + /** + * The range in which this code lens is valid. Should only span a single line. + */ + range: Range + /** + * The command this code lens represents. + */ + command?: Command + /** + * An data entry field that is preserved on a code lens item between + * a [CodeLensRequest](#CodeLensRequest) and a [CodeLensResolveRequest] + * (#CodeLensResolveRequest) + */ + data?: any + } + + /** + * Represents the connection of two locations. Provides additional metadata over normal [locations](#Location), + * including an origin range. + */ + export interface LocationLink { + /** + * Span of the origin of this link. + * + * Used as the underlined span for mouse definition hover. Defaults to the word range at + * the definition position. + */ + originSelectionRange?: Range + /** + * The target resource identifier of this link. + */ + targetUri: string + /** + * The full target range of this link. If the target for example is a symbol then target range is the + * range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to highlight the range in the editor. + */ + targetRange: Range + /** + * The range that should be selected and revealed when this link is being followed, e.g the name of a function. + * Must be contained by the the `targetRange`. See also `DocumentSymbol#range` + */ + targetSelectionRange: Range + } + + /** + * The LocationLink namespace provides helper functions to work with + * [LocationLink](#LocationLink) literals. + */ + export namespace LocationLink { + /** + * Creates a LocationLink literal. + * @param targetUri The definition's uri. + * @param targetRange The full range of the definition. + * @param targetSelectionRange The span of the symbol definition at the target. + * @param originSelectionRange The span of the symbol being defined in the originating source file. + */ + function create(targetUri: string, targetRange: Range, targetSelectionRange: Range, originSelectionRange?: Range): LocationLink + /** + * Checks whether the given literal conforms to the [LocationLink](#LocationLink) interface. + */ + function is(value: any): value is LocationLink + } + + export type MarkupKind = 'plaintext' | 'markdown' + + /** + * Describes the content type that a client supports in various + * result literals like `Hover`, `ParameterInfo` or `CompletionItem`. + * + * Please note that `MarkupKinds` must not start with a `$`. This kinds + * are reserved for internal usage. + */ + export namespace MarkupKind { + /** + * Plain text is supported as a content format + */ + const PlainText: 'plaintext' + /** + * Markdown is supported as a content format + */ + const Markdown: 'markdown' + } + /** + * A `MarkupContent` literal represents a string value which content is interpreted base on its + * kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. + * + * If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. + * See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting + * + * Here is an example how such a string can be constructed using JavaScript / TypeScript: + * ```ts + * let markdown: MarkdownContent = { + * kind: MarkupKind.Markdown, + * value: [ + * '# Header', + * 'Some text', + * '```typescript', + * 'someCode();', + * '```' + * ].join('\n') + * }; + * ``` + * + * *Please Note* that clients might sanitize the return markdown. A client could decide to + * remove HTML from the markdown to avoid script execution. + */ + export interface MarkupContent { + /** + * The type of the Markup + */ + kind: MarkupKind + /** + * The content itself + */ + value: string + } + + /** + * The kind of a completion entry. + */ + export namespace CompletionItemKind { + const Text: 1 + const Method: 2 + const Function: 3 + const Constructor: 4 + const Field: 5 + const Variable: 6 + const Class: 7 + const Interface: 8 + const Module: 9 + const Property: 10 + const Unit: 11 + const Value: 12 + const Enum: 13 + const Keyword: 14 + const Snippet: 15 + const Color: 16 + const File: 17 + const Reference: 18 + const Folder: 19 + const EnumMember: 20 + const Constant: 21 + const Struct: 22 + const Event: 23 + const Operator: 24 + const TypeParameter: 25 + } + + export type CompletionItemKind = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 + + /** + * Defines whether the insert text in a completion item should be interpreted as + * plain text or a snippet. + */ + export namespace InsertTextFormat { + /** + * The primary text to be inserted is treated as a plain string. + */ + const PlainText: 1 + /** + * The primary text to be inserted is treated as a snippet. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Placeholders with equal identifiers are linked, + * that is typing in one will update others too. + * + * See also: https://github.com/microsoft/vscode/blob/main/src/vs/editor/contrib/snippet/snippet.md + */ + const Snippet: 2 + } + export type InsertTextFormat = 1 | 2 + + /** + * A completion item represents a text snippet that is + * proposed to complete text that is being typed. + */ + export interface CompletionItem { + /** + * The label of this completion item. By default + * also the text that is inserted when selecting + * this completion. + */ + label: string + /** + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. + */ + kind?: CompletionItemKind + /** + * Tags for this completion item. + * + * @since 3.15.0 + */ + tags?: number[] + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + detail?: string + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string | MarkupContent + /** + * Indicates if this item is deprecated. + * @deprecated Use `tags` instead. + */ + deprecated?: boolean + /** + * Select this item when showing. + * + * *Note* that only one completion item can be selected and that the + * tool / client decides which item that is. The rule is that the *first* + * item of those that match best is selected. + */ + preselect?: boolean + /** + * A string that should be used when comparing this item + * with other items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + sortText?: string + /** + * A string that should be used when filtering a set of + * completion items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + filterText?: string + /** + * A string that should be inserted into a document when selecting + * this completion. When `falsy` the [label](#CompletionItem.label) + * is used. + * + * The `insertText` is subject to interpretation by the client side. + * Some tools might not take the string literally. For example + * VS Code when code complete is requested in this example `con` + * and a completion item with an `insertText` of `console` is provided it + * will only insert `sole`. Therefore it is recommended to use `textEdit` instead + * since it avoids additional client side interpretation. + */ + insertText?: string + /** + * The format of the insert text. The format applies to both the `insertText` property + * and the `newText` property of a provided `textEdit`. If omitted defaults to + * `InsertTextFormat.PlainText`. + */ + insertTextFormat?: InsertTextFormat + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this completion. When an edit is provided the value of + * [insertText](#CompletionItem.insertText) is ignored. + * + * *Note:* The text edit's range must be a [single line] and it must contain the position + * at which completion has been requested. + */ + textEdit?: TextEdit + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this completion. Edits must not overlap (including the same insert position) + * with the main [edit](#CompletionItem.textEdit) nor with themselves. + * + * Additional text edits should be used to change text unrelated to the current cursor position + * (for example adding an import statement at the top of the file if the completion item will + * insert an unqualified type). + */ + additionalTextEdits?: TextEdit[] + /** + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + commitCharacters?: string[] + /** + * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that + * additional modifications to the current document should be described with the + * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property. + */ + command?: Command + /** + * An data entry field that is preserved on a completion item between + * a [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest] + * (#CompletionResolveRequest) + */ + data?: any + } + + /** + * Represents a collection of [completion items](#CompletionItem) to be presented + * in the editor. + */ + export interface CompletionList { + /** + * This list it not complete. Further typing results in recomputing this list. + */ + isIncomplete: boolean + /** + * The completion items. + */ + items: CompletionItem[] + } + + /** + * How a completion was triggered + */ + export namespace CompletionTriggerKind { + /** + * Completion was triggered by typing an identifier (24x7 code + * complete), manual invocation (e.g Ctrl+Space) or via API. + */ + const Invoked: 1 + /** + * Completion was triggered by a trigger character specified by + * the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + */ + const TriggerCharacter: 2 + /** + * Completion was re-triggered as current completion list is incomplete + */ + const TriggerForIncompleteCompletions: 3 + } + + export type CompletionTriggerKind = 1 | 2 | 3 + + /** + * Contains additional information about the context in which a completion request is triggered. + */ + export interface CompletionContext { + /** + * How the completion was triggered. + */ + triggerKind: CompletionTriggerKind, + /** + * The trigger character (a single character) that has trigger code complete. + * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + */ + triggerCharacter?: string + + option?: CompleteOption + } + + /** + * Represents a reference to a command. Provides a title which + * will be used to represent a command in the UI and, optionally, + * an array of arguments which will be passed to the command handler + * function when invoked. + */ + export interface Command { + /** + * Title of the command, like `save`. + */ + title: string + /** + * The identifier of the actual command handler. + */ + command: string + /** + * Arguments that the command handler should be + * invoked with. + */ + arguments?: any[] + } + + export interface TextDocumentEdit { + /** + * The text document to change. + */ + textDocument: { + uri: string + version: number | null + } + /** + * The edits to be applied. + */ + edits: TextEdit[] + } + + /** + * A workspace edit represents changes to many resources managed in the workspace. The edit + * should either provide `changes` or `documentChanges`. If documentChanges are present + * they are preferred over `changes` if the client can handle versioned document edits. + */ + export interface WorkspaceEdit { + /** + * Holds changes to existing resources. + */ + changes?: { + [uri: string]: TextEdit[] + } + /** + * Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + * are either an array of `TextDocumentEdit`s to express changes to n different text documents + * where each text document edit addresses a specific version of a text document. Or it can contain + * above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + * + * Whether a client supports versioned document edits is expressed via + * `workspace.workspaceEdit.documentChanges` client capability. + * + * If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + * only plain `TextEdit`s using the `changes` property are supported. + */ + documentChanges?: (TextDocumentEdit | CreateFile | RenameFile | DeleteFile)[] + } + + interface ResourceOperation { + kind: string + } + + /** + * Delete file options + */ + export interface DeleteFileOptions { + /** + * Delete the content recursively if a folder is denoted. + */ + recursive?: boolean + /** + * Ignore the operation if the file doesn't exist. + */ + ignoreIfNotExists?: boolean + } + /** + * Delete file operation + */ + export interface DeleteFile extends ResourceOperation { + /** + * A delete + */ + kind: 'delete' + /** + * The file to delete. + */ + uri: string + /** + * Delete options. + */ + options?: DeleteFileOptions + } + + /** + * Options to create a file. + */ + export interface CreateFileOptions { + /** + * Overwrite existing file. Overwrite wins over `ignoreIfExists` + */ + overwrite?: boolean + /** + * Ignore if exists. + */ + ignoreIfExists?: boolean + } + /** + * Create file operation. + */ + export interface CreateFile extends ResourceOperation { + /** + * A create + */ + kind: 'create' + /** + * The resource to create. + */ + uri: string + /** + * Additional options + */ + options?: CreateFileOptions + } + + /** + * Rename file options + */ + export interface RenameFileOptions { + /** + * Overwrite target if existing. Overwrite wins over `ignoreIfExists` + */ + overwrite?: boolean + /** + * Ignores if target exists. + */ + ignoreIfExists?: boolean + } + /** + * Rename file operation + */ + export interface RenameFile extends ResourceOperation { + /** + * A rename + */ + kind: 'rename' + /** + * The old (existing) location. + */ + oldUri: string + /** + * The new location. + */ + newUri: string + /** + * Rename options. + */ + options?: RenameFileOptions + } + /** + * Represents a related message and source code location for a diagnostic. This should be + * used to point to code locations that cause or related to a diagnostics, e.g when duplicating + * a symbol in a scope. + */ + export interface DiagnosticRelatedInformation { + /** + * The location of this related diagnostic information. + */ + location: Location + /** + * The message of this related diagnostic information. + */ + message: string + } + + /** + * The diagnostic's severity. + */ + export namespace DiagnosticSeverity { + /** + * Reports an error. + */ + const Error: 1 + /** + * Reports a warning. + */ + const Warning: 2 + /** + * Reports an information. + */ + const Information: 3 + /** + * Reports a hint. + */ + const Hint: 4 + } + + export type DiagnosticSeverity = 1 | 2 | 3 | 4 + + /** + * The diagnostic tags. + * + * @since 3.15.0 + */ + export namespace DiagnosticTag { + /** + * Unused or unnecessary code. + * + * Clients are allowed to render diagnostics with this tag faded out instead of having + * an error squiggle. + */ + const Unnecessary: 1 + /** + * Deprecated or obsolete code. + * + * Clients are allowed to rendered diagnostics with this tag strike through. + */ + const Deprecated: 2 + } + + export type DiagnosticTag = 1 | 2 + + /** + * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects + * are only valid in the scope of a resource. + */ + export interface Diagnostic { + /** + * The range at which the message applies + */ + range: Range + /** + * The diagnostic's severity. Can be omitted. If omitted it is up to the + * client to interpret diagnostics as error, warning, info or hint. + */ + severity?: DiagnosticSeverity + /** + * The diagnostic's code, which usually appear in the user interface. + */ + code?: number | string + /** + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. It usually + * appears in the user interface. + */ + source?: string + /** + * The diagnostic's message. It usually appears in the user interface + */ + message: string + /** + * Additional metadata about the diagnostic. + */ + tags?: DiagnosticTag[] + /** + * An array of related diagnostic information, e.g. when symbol-names within + * a scope collide all definitions can be marked via this property. + */ + relatedInformation?: DiagnosticRelatedInformation[] + } + + /** + * The Diagnostic namespace provides helper functions to work with + * [Diagnostic](#Diagnostic) literals. + */ + export namespace Diagnostic { + /** + * Creates a new Diagnostic literal. + */ + function create(range: Range, message: string, severity?: DiagnosticSeverity, code?: number | string, source?: string, relatedInformation?: DiagnosticRelatedInformation[]): Diagnostic + /** + * Checks whether the given literal conforms to the [Diagnostic](#Diagnostic) interface. + */ + function is(value: any): value is Diagnostic + } + + /** + * A code action represents a change that can be performed in code, e.g. to fix a problem or + * to refactor code. + * + * A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. + */ + export interface CodeAction { + /** + * A short, human-readable, title for this code action. + */ + title: string + /** + * The kind of the code action. + * + * Used to filter code actions. + */ + kind?: CodeActionKind + /** + * The diagnostics that this code action resolves. + */ + diagnostics?: Diagnostic[] + /** + * Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + * by keybindings. + * + * A quick fix should be marked preferred if it properly addresses the underlying error. + * A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + * + * @since 3.15.0 + */ + isPreferred?: boolean + /** + * The workspace edit this code action performs. + */ + edit?: WorkspaceEdit + /** + * A command this code action executes. If a code action + * provides a edit and a command, first the edit is + * executed and then the command. + */ + command?: Command + /** + * Id of client that provide codeAction. + */ + clientId?: string + } + + /** + * The kind of a code action. + * + * Kinds are a hierarchical list of identifiers separated by `.`, e.g. `"refactor.extract.function"`. + * + * The set of kinds is open and client needs to announce the kinds it supports to the server during + * initialization. + */ + export type CodeActionKind = string + /** + * A set of predefined code action kinds + */ + export namespace CodeActionKind { + /** + * Empty kind. + */ + const Empty: CodeActionKind + /** + * Base kind for quickfix actions: 'quickfix' + */ + const QuickFix: CodeActionKind + /** + * Base kind for refactoring actions: 'refactor' + */ + const Refactor: CodeActionKind + /** + * Base kind for refactoring extraction actions: 'refactor.extract' + * + * Example extract actions: + * + * - Extract method + * - Extract function + * - Extract variable + * - Extract interface from class + * - ... + */ + const RefactorExtract: CodeActionKind + /** + * Base kind for refactoring inline actions: 'refactor.inline' + * + * Example inline actions: + * + * - Inline function + * - Inline variable + * - Inline constant + * - ... + */ + const RefactorInline: CodeActionKind + /** + * Base kind for refactoring rewrite actions: 'refactor.rewrite' + * + * Example rewrite actions: + * + * - Convert JavaScript function to class + * - Add or remove parameter + * - Encapsulate field + * - Make method static + * - Move method to base class + * - ... + */ + const RefactorRewrite: CodeActionKind + /** + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. + */ + const Source: CodeActionKind + /** + * Base kind for an organize imports source action: `source.organizeImports` + */ + const SourceOrganizeImports: CodeActionKind + /** + * Base kind for auto-fix source actions: `source.fixAll`. + * + * Fix all actions automatically fix errors that have a clear fix that do not require user input. + * They should not suppress errors or perform unsafe fixes such as generating new types or classes. + * + * @since 3.15.0 + */ + const SourceFixAll: CodeActionKind + } + + /** + * Position in a text document expressed as zero-based line and character offset. + * The offsets are based on a UTF-16 string representation. So a string of the form + * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀` + * is 1 and the character offset of b is 3 since `𐐀` is represented using two code + * units in UTF-16. + * + * Positions are line end character agnostic. So you can not specify a position that + * denotes `\r|\n` or `\n|` where `|` represents the character offset. + */ + export interface Position { + /** + * Line position in a document (zero-based). + * If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. + * If a line number is negative, it defaults to 0. + */ + line: number + /** + * Character offset on a line in a document (zero-based). Assuming that the line is + * represented as a string, the `character` value represents the gap between the + * `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back to the + * line length. + * If a line number is negative, it defaults to 0. + */ + character: number + } + + /** + * The Position namespace provides helper functions to work with + * [Position](#Position) literals. + */ + export namespace Position { + /** + * Creates a new Position literal from the given line and character. + * @param line The position's line. + * @param character The position's character. + */ + function create(line: number, character: number): Position + /** + * Checks whether the given liternal conforms to the [Position](#Position) interface. + */ + function is(value: any): value is Position + } + + /** + * Represents a typed event. + * + * A function that represents an event to which you subscribe by calling it with + * a listener function as argument. + * + * @example + * item.onDidChange(function(event) { console.log("Event happened: " + event); }); + */ + export interface Event { + + /** + * A function that represents an event to which you subscribe by calling it with + * a listener function as argument. + * + * @param listener The listener function will be called when the event happens. + * @param thisArgs The `this`-argument which will be used when calling the event listener. + * @param disposables An array to which a [disposable](#Disposable) will be added. + * @return A disposable which unsubscribes the event listener. + */ + (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]): Disposable + } + + export namespace Event { + const None: Event + } + + export interface EmitterOptions { + onFirstListenerAdd?: Function + onLastListenerRemove?: Function + } + + export class Emitter { + constructor(_options?: EmitterOptions | undefined) + /** + * For the public to allow to subscribe + * to events from this Emitter + */ + get event(): Event + /** + * To be kept private to fire an event to + * subscribers + */ + fire(event: T): any + dispose(): void + } + + /** + * Represents a location inside a resource, such as a line + * inside a text file. + */ + export interface Location { + uri: string + range: Range + } + + /** + * The Location namespace provides helper functions to work with + * [Location](#Location) literals. + */ + export namespace Location { + /** + * Creates a Location literal. + * @param uri The location's uri. + * @param range The location's range. + */ + function create(uri: string, range: Range): Location + /** + * Checks whether the given literal conforms to the [Location](#Location) interface. + */ + function is(value: any): value is Location + } + + /** + * A range in a text document expressed as (zero-based) start and end positions. + * + * If you want to specify a range that contains a line including the line ending + * character(s) then use an end position denoting the start of the next line. + * For example: + * ```ts + * { + * start: { line: 5, character: 23 } + * end : { line 6, character : 0 } + * } + * ``` + */ + export interface Range { + /** + * The range's start position + */ + start: Position + /** + * The range's end position. + */ + end: Position + } + + /** + * The Range namespace provides helper functions to work with + * [Range](#Range) literals. + */ + export namespace Range { + /** + * Create a new Range liternal. + * @param start The range's start position. + * @param end The range's end position. + */ + function create(start: Position, end: Position): Range + /** + * Create a new Range liternal. + * @param startLine The start line number. + * @param startCharacter The start character. + * @param endLine The end line number. + * @param endCharacter The end character. + */ + function create(startLine: number, startCharacter: number, endLine: number, endCharacter: number): Range + /** + * Checks whether the given literal conforms to the [Range](#Range) interface. + */ + function is(value: any): value is Range + } + + /** + * A text edit applicable to a text document. + */ + export interface TextEdit { + /** + * The range of the text document to be manipulated. To insert + * text into a document create a range where start === end. + */ + range: Range + /** + * The string to be inserted. For delete operations use an + * empty string. + */ + newText: string + } + + /** + * The TextEdit namespace provides helper function to create replace, + * insert and delete edits more easily. + */ + export namespace TextEdit { + /** + * Creates a replace text edit. + * @param range The range of text to be replaced. + * @param newText The new text. + */ + function replace(range: Range, newText: string): TextEdit + /** + * Creates a insert text edit. + * @param position The position to insert the text at. + * @param newText The text to be inserted. + */ + function insert(position: Position, newText: string): TextEdit + /** + * Creates a delete text edit. + * @param range The range of text to be deleted. + */ + function del(range: Range): TextEdit + function is(value: any): value is TextEdit + } + + /** + * Defines a CancellationToken. This interface is not + * intended to be implemented. A CancellationToken must + * be created via a CancellationTokenSource. + */ + export interface CancellationToken { + /** + * Is `true` when the token has been cancelled, `false` otherwise. + */ + readonly isCancellationRequested: boolean + /** + * An [event](#Event) which fires upon cancellation. + */ + readonly onCancellationRequested: Event + } + + export namespace CancellationToken { + const None: CancellationToken + const Cancelled: CancellationToken + function is(value: any): value is CancellationToken + } + + export class CancellationTokenSource { + get token(): CancellationToken + cancel(): void + dispose(): void + } + + /** + * Represents a line of text, such as a line of source code. + * + * TextLine objects are __immutable__. When a {@link LinesTextDocument document} changes, + * previously retrieved lines will not represent the latest state. + */ + export interface TextLine { + /** + * The zero-based line number. + */ + readonly lineNumber: number + + /** + * The text of this line without the line separator characters. + */ + readonly text: string + + /** + * The range this line covers without the line separator characters. + */ + readonly range: Range + + /** + * The range this line covers with the line separator characters. + */ + readonly rangeIncludingLineBreak: Range + + /** + * The offset of the first character which is not a whitespace character as defined + * by `/\s/`. **Note** that if a line is all whitespace the length of the line is returned. + */ + readonly firstNonWhitespaceCharacterIndex: number + + /** + * Whether this line is whitespace only, shorthand + * for {@link TextLine.firstNonWhitespaceCharacterIndex} === {@link TextLine.text TextLine.text.length}. + */ + readonly isEmptyOrWhitespace: boolean + } + + /** + * A simple text document. Not to be implemented. The document keeps the content + * as string. + */ + export interface TextDocument { + /** + * The associated URI for this document. Most documents have the __file__-scheme, indicating that they + * represent files on disk. However, some documents may have other schemes indicating that they are not + * available on disk. + * + * @readonly + */ + readonly uri: string + /** + * The identifier of the language associated with this document. + * + * @readonly + */ + readonly languageId: string + /** + * The version number of this document (it will increase after each + * change, including undo/redo). + * + * @readonly + */ + readonly version: number + /** + * Get the text of this document. A substring can be retrieved by + * providing a range. + * + * @param range (optional) An range within the document to return. + * If no range is passed, the full content is returned. + * Invalid range positions are adjusted as described in [Position.line](#Position.line) + * and [Position.character](#Position.character). + * If the start range position is greater than the end range position, + * then the effect of getText is as if the two positions were swapped. + + * @return The text of this document or a substring of the text if a + * range is provided. + */ + getText(range?: Range): string + /** + * Converts a zero-based offset to a position. + * + * @param offset A zero-based offset. + * @return A valid [position](#Position). + */ + positionAt(offset: number): Position + /** + * Converts the position to a zero-based offset. + * Invalid positions are adjusted as described in [Position.line](#Position.line) + * and [Position.character](#Position.character). + * + * @param position A position. + * @return A valid zero-based offset. + */ + offsetAt(position: Position): number + /** + * The number of lines in this document. + * + * @readonly + */ + readonly lineCount: number + } + + export interface LinesTextDocument extends TextDocument { + /** + * Total length of TextDocument. + */ + readonly length: number + /** + * End position of TextDocument. + */ + readonly end: Position + /** + * 'eol' option of related buffer. When enabled additional `\n` will be + * added to the end of document content + */ + readonly rol: boolean + /** + * Lines of TextDocument. + */ + readonly lines: ReadonlyArray + /** + * Returns a text line denoted by the line number. Note + * that the returned object is *not* live and changes to the + * document are not reflected. + * + * @param line or position + * @return A {@link TextLine line}. + */ + lineAt(lineOrPos: number | Position): TextLine + } + + /** + * @since 3.16.0 + */ + export interface SemanticTokensLegend { + /** + * The token types a server uses. + */ + tokenTypes: string[] + /** + * The token modifiers a server uses. + */ + tokenModifiers: string[] + } + + /** + * @since 3.16.0 + */ + export interface SemanticTokens { + /** + * An optional result id. If provided and clients support delta updating + * the client will include the result id in the next semantic token request. + * A server can then instead of computing all semantic tokens again simply + * send a delta. + */ + resultId?: string + /** + * The actual tokens. + */ + data: number[] + } + + /** + * @since 3.16.0 + */ + export interface SemanticTokensEdit { + /** + * The start offset of the edit. + */ + start: number + /** + * The count of elements to remove. + */ + deleteCount: number + /** + * The elements to insert. + */ + data?: number[] + } + + /** + * @since 3.16.0 + */ + export interface SemanticTokensDelta { + readonly resultId?: string + /** + * The semantic token edits to transform a previous result into a new result. + */ + edits: SemanticTokensEdit[] + } + + /** + * The result of a linked editing range request. + * + * @since 3.16.0 + */ + export interface LinkedEditingRanges { + /** + * A list of ranges that can be edited together. The ranges must have + * identical length and contain identical text content. The ranges cannot overlap. + */ + ranges: Range[] + /** + * An optional word pattern (regular expression) that describes valid contents for + * the given ranges. If no pattern is provided, the client configuration's word + * pattern will be used. + */ + wordPattern?: string + } + + /** + * Represents programming constructs like functions or constructors in the context + * of call hierarchy. + * + * @since 3.16.0 + */ + export interface CallHierarchyItem { + /** + * The name of this item. + */ + name: string + /** + * The kind of this item. + */ + kind: SymbolKind + /** + * Tags for this item. + */ + tags?: number[] + /** + * More detail for this item, e.g. the signature of a function. + */ + detail?: string + /** + * The resource identifier of this item. + */ + uri: string + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + */ + range: Range + /** + * The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + * Must be contained by the [`range`](#CallHierarchyItem.range). + */ + selectionRange: Range + /** + * A data entry field that is preserved between a call hierarchy prepare and + * incoming calls or outgoing calls requests. + */ + data?: unknown + } + + /** + * Represents an incoming call, e.g. a caller of a method or constructor. + * + * @since 3.16.0 + */ + export interface CallHierarchyIncomingCall { + /** + * The item that makes the call. + */ + from: CallHierarchyItem + /** + * The ranges at which the calls appear. This is relative to the caller + * denoted by [`this.from`](#CallHierarchyIncomingCall.from). + */ + fromRanges: Range[] + } + /** + * Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. + * + * @since 3.16.0 + */ + export interface CallHierarchyOutgoingCall { + /** + * The item that is called. + */ + to: CallHierarchyItem + /** + * The range at which this item is called. This is the range relative to the caller, e.g the item + * passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) + * and not [`this.to`](#CallHierarchyOutgoingCall.to). + */ + fromRanges: Range[] + } + + /** + * Moniker uniqueness level to define scope of the moniker. + * + * @since 3.16.0 + */ + export namespace UniquenessLevel { + /** + * The moniker is only unique inside a document + */ + export const document = 'document' + + /** + * The moniker is unique inside a project for which a dump got created + */ + export const project = 'project' + + /** + * The moniker is unique inside the group to which a project belongs + */ + export const group = 'group' + + /** + * The moniker is unique inside the moniker scheme. + */ + export const scheme = 'scheme' + + /** + * The moniker is globally unique + */ + export const global = 'global' + } + + export type UniquenessLevel = 'document' | 'project' | 'group' | 'scheme' | 'global' + + /** + * The moniker kind. + * + * @since 3.16.0 + */ + export enum MonikerKind { + /** + * The moniker represent a symbol that is imported into a project + */ + import = 'import', + + /** + * The moniker represents a symbol that is exported from a project + */ + export = 'export', + + /** + * The moniker represents a symbol that is local to a project (e.g. a local + * variable of a function, a class not visible outside the project, ...) + */ + local = 'local' + } + + /** + * Moniker definition to match LSIF 0.5 moniker definition. + * + * @since 3.16.0 + */ + export interface Moniker { + /** + * The scheme of the moniker. For example tsc or .Net + */ + scheme: string + + /** + * The identifier of the moniker. The value is opaque in LSIF however + * schema owners are allowed to define the structure if they want. + */ + identifier: string + + /** + * The scope in which the moniker is unique + */ + unique: UniquenessLevel + + /** + * The moniker kind if known. + */ + kind?: MonikerKind + } + + export type InlayHintKind = 1 | 2 + + /** + * An inlay hint label part allows for interactive and composite labels + * of inlay hints. + * + * @since 3.17.0 + * @proposed + */ + export interface InlayHintLabelPart { + + /** + * The value of this label part. + */ + value: string + + /** + * The tooltip text when you hover over this label part. Depending on + * the client capability `inlayHint.resolveSupport` clients might resolve + * this property late using the resolve request. + */ + tooltip?: string | MarkupContent + + /** + * An optional source code location that represents this + * label part. + * + * The editor will use this location for the hover and for code navigation + * features: This part will become a clickable link that resolves to the + * definition of the symbol at the given location (not necessarily the + * location itself), it shows the hover that shows at the given location, + * and it shows a context menu with further code navigation commands. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + location?: Location + + /** + * An optional command for this label part. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + command?: Command + } + + /** + * Inlay hint information. + * + * @since 3.17.0 + * @proposed + */ + export interface InlayHint { + + /** + * The position of this hint. + */ + position: Position + + /** + * The label of this hint. A human readable string or an array of + * InlayHintLabelPart label parts. + * + * *Note* that neither the string nor the label part can be empty. + */ + label: string | InlayHintLabelPart[] + + /** + * The kind of this hint. Can be omitted in which case the client + * should fall back to a reasonable default. + */ + kind?: InlayHintKind + + /** + * Optional text edits that are performed when accepting this inlay hint. + * + * *Note* that edits are expected to change the document so that the inlay + * hint (or its nearest variant) is now part of the document and the inlay + * hint itself is now obsolete. + */ + textEdits?: TextEdit[] + + /** + * The tooltip text when you hover over this item. + */ + tooltip?: string | MarkupContent + + /** + * Render padding before the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + paddingLeft?: boolean + + /** + * Render padding after the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + paddingRight?: boolean + + /** + * A data entry field that is preserved on a inlay hint between + * a `textDocument/inlayHint` and a `inlayHint/resolve` request. + */ + data?: any + } + // }} + + // nvim interfaces {{ + type VimValue = + | number + | boolean + | string + | number[] + | { [key: string]: any } + + // see `:h nvim_set_client_info()` for details. + export interface VimClientInfo { + name: string + version: { + major?: number + minor?: number + patch?: number + prerelease?: string + commit?: string + } + type: 'remote' | 'embedder' | 'host' + methods?: { + [index: string]: any + } + attributes?: { + [index: string]: any + } + } + + export interface UiAttachOptions { + rgb?: boolean + ext_popupmenu?: boolean + ext_tabline?: boolean + ext_wildmenu?: boolean + ext_cmdline?: boolean + ext_linegrid?: boolean + ext_hlstate?: boolean + } + + export interface ChanInfo { + id: number + stream: 'stdio' | 'stderr' | 'socket' | 'job' + mode: 'bytes' | 'terminal' | 'rpc' + pty?: number + buffer?: number + client?: VimClientInfo + } + + /** + * Returned by nvim_get_commands api. + */ + export interface VimCommandDescription { + name: string + bang: boolean + bar: boolean + register: boolean + definition: string + count?: number | null + script_id: number + complete?: string + nargs?: string + range?: string + complete_arg?: string + } + + export interface NvimFloatOptions { + standalone?: boolean + focusable?: boolean + relative?: 'editor' | 'cursor' | 'win' + anchor?: 'NW' | 'NE' | 'SW' | 'SE' + height: number + width: number + row: number + col: number + } + + export interface ExtmarkOptions { + id?: number + // 0-based inclusive. + end_line?: number + // 0-based exclusive. + end_col?: number + // name of the highlight group used to highlight this mark. + hl_group?: string + hl_mode?: 'replace' | 'combine' | 'blend' + hl_eol?: boolean + // A list of [text, highlight] tuples + virt_text?: [string, string | string[]][] + virt_text_pos?: 'eol' | 'overlay' | 'right_align' + virt_text_win_col?: number + virt_text_hide?: boolean + virt_lines?: [string, string | string[]][][] + virt_lines_above?: boolean + virt_lines_leftcol?: boolean + right_gravity?: boolean + end_right_gravity?: boolean + priority?: number + } + + export interface ExtmarkDetails { + end_col: number + end_row: number + priority: number + hl_group?: string + virt_text?: [string, string][] + virt_lines?: [string, string | string][][] + } + + export interface NvimProc { + ppid: number + name: string + pid: number + } + + export interface SignPlaceOption { + id?: number + group?: string + name: string + lnum: number + priority?: number + } + + export interface SignUnplaceOption { + group?: string + id?: number + } + + export interface SignPlacedOption { + /** + * Use '*' for all group, default to '' as unnamed group. + */ + group?: string + id?: number + lnum?: number + } + + export interface SignItem { + group: string + id: number + lnum: number + name: string + priority: number + } + + export interface HighlightItem { + hlGroup: string + /** + * 0 based + */ + lnum: number + /** + * 0 based + */ + colStart: number + /** + * 0 based + */ + colEnd: number + } + + export interface ExtendedHighlightItem extends HighlightItem { + combine?: boolean + start_incl?: boolean + end_incl?: boolean + } + + export interface HighlightOption { + /** + * 0 based start line, default to 0. + */ + start?: number + /** + * 0 based end line, default to 0. + */ + end?: number + /** + * Default to 0 on vim8, 4096 on neovim + */ + priority?: number + /** + * Buffer changedtick to match. + */ + changedtick?: number + } + + export interface BufferKeymapOption { + nowait?: boolean + silent?: boolean + script?: boolean + expr?: boolean + unique?: boolean + } + + export interface BufferHighlight { + /** + * Name of the highlight group to use + */ + hlGroup?: string + /** + * Namespace to use or -1 for ungrouped highlight + */ + srcId?: number + /** + * Line to highlight (zero-indexed) + */ + line?: number + /** + * Start of (byte-indexed) column range to highlight + */ + colStart?: number + /** + * End of (byte-indexed) column range to highlight, or -1 to highlight to end of line + */ + colEnd?: number + } + + export interface BufferClearHighlight { + srcId?: number + lineStart?: number + lineEnd?: number + } + + interface BaseApi { + /** + * unique identify number + */ + id: number + + /** + * Check if same by compare id. + */ + equals(other: T): boolean + + /** + * Request to vim, name need to be nvim_ prefixed and supported by vim. + * + * @param {string} name - nvim function name + * @param {VimValue[]} args + * @returns {Promise} + */ + request(name: string, args?: VimValue[]): Promise + + /** + * Send notification to vim, name need to be nvim_ prefixed and supported + * by vim + */ + notify(name: string, args?: VimValue[]): void + + /** + * Retrieves scoped variable, returns null when value doesn't exist. + */ + getVar(name: string): Promise + + /** + * Set scoped variable by request. + * + * @param {string} name + * @param {VimValue} value + * @returns {Promise} + */ + setVar(name: string, value: VimValue): Promise + + /** + * Set scoped variable by notification. + */ + setVar(name: string, value: VimValue, isNotify: true): void + + /** + * Delete scoped variable by notification. + */ + deleteVar(name: string): void + + /** + * Retrieves a scoped option, doesn't exist for tabpage. + */ + getOption(name: string): Promise + + /** + * Set scoped option by request, doesn't exist for tabpage. + */ + setOption(name: string, value: VimValue): Promise + + /** + * Set scoped variable by notification, doesn't exist for tabpage. + */ + setOption(name: string, value: VimValue, isNotify: true): void + } + + export interface Neovim extends BaseApi { + + /** + * Echo error message to vim and log error stack. + */ + echoError(msg: unknown): void + + /** + * Check if `nvim_` function exists. + */ + hasFunction(name: string): boolean + + /** + * Get channelid used by coc.nvim. + */ + channelId: Promise + + /** + * Create buffer instance by id. + */ + createBuffer(id: number): Buffer + + /** + * Create window instance by id. + */ + createWindow(id: number): Window + + /** + * Create tabpage instance by id. + */ + createTabpage(id: number): Tabpage + + /** + * Stop send subsequent notifications. + * This method **must** be paired with `nvim.resumeNotification` in a sync manner. + */ + pauseNotification(): void + + /** + * Send paused notifications by nvim_call_atomic request + * + * @param {boolean} redrawVim Redraw vim on vim8 to update the screen + * + * **Note**: avoid call async function between pauseNotification and + * resumeNotification. + */ + resumeNotification(redrawVim?: boolean): Promise<[VimValue[], [string, number, string] | null]> + + /** + * Send paused notifications by nvim_call_atomic notification + * + * @param {boolean} redrawVim Redraw vim to update the screen + * @param {true} notify + * @returns {void} + */ + resumeNotification(redrawVim: boolean, notify: true): void + + /** + * Send redraw command to vim, does nothing on neovim since it's not necessary on most cases. + */ + redrawVim(): void + + /** + * Get list of current buffers. + */ + buffers: Promise + + /** + * Get current buffer. + */ + buffer: Promise + + /** + * Set current buffer + */ + setBuffer(buffer: Buffer): Promise + + /** + * Get list of current tabpages. + */ + tabpages: Promise + + /** + * Get current tabpage. + */ + tabpage: Promise + + /** + * Set current tabpage + */ + setTabpage(tabpage: Tabpage): Promise + + /** + * Get list of current windows. + */ + windows: Promise + + /** + * Get current window. + */ + window: Promise + + /** + * Set current window. + */ + setWindow(window: Window): Promise + + /** + * Get information of all channels, + * **Note:** works on neovim only. + */ + chans: Promise + + /** + * Get information of channel by id, + * **Note:** works on neovim only. + */ + getChanInfo(id: number): Promise + + /** + * Creates a new namespace, or gets an existing one. + * `:h nvim_create_namespace()` + */ + createNamespace(name?: string): Promise + + /** + * Gets existing, non-anonymous namespaces. + * + * @return dict that maps from names to namespace ids. + */ + namespaces: Promise<{ [name: string]: number }> + + /** + * Gets a map of global (non-buffer-local) Ex commands. + * + * @return Map of maps describing commands. + */ + getCommands(opt?: { builtin: boolean }): Promise<{ [name: string]: VimCommandDescription }> + + /** + * Get list of all runtime paths + */ + runtimePaths: Promise + + /** + * Set global working directory. + * **Note:** works on neovim only. + */ + setDirectory(dir: string): Promise + + /** + * Get current line. + */ + line: Promise + + /** + * Creates a new, empty, unnamed buffer. + * + * **Note:** works on neovim only. + */ + createNewBuffer(listed?: boolean, scratch?: boolean): Promise + + /** + * Create float window of neovim. + * + * **Note:** works on neovim only, use high level api provided by window + * module is recommended. + */ + openFloatWindow(buffer: Buffer, enter: boolean, options: NvimFloatOptions): Promise + + /** + * Set current line. + */ + setLine(line: string): Promise + + /** + * Gets a list of global (non-buffer-local) |mapping| definitions. + * `:h nvim_get_keymap` + * + * **Note:** works on neovim only. + */ + getKeymap(mode: string): Promise + + /** + * Gets the current mode. |mode()| "blocking" is true if Nvim is waiting for input. + * + * **Note:** blocking would always be false when used with vim. + */ + mode: Promise<{ mode: string; blocking: boolean }> + + /** + * Returns a map of color names and RGB values. + * + * **Note:** works on neovim only. + */ + colorMap(): Promise<{ [name: string]: number }> + + /** + * Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or + * "#rrggbb" hexadecimal string. + * + * **Note:** works on neovim only. + */ + getColorByName(name: string): Promise + + /** + * Gets a highlight definition by id. |hlID()| + * + * **Note:** works on neovim only. + */ + getHighlight(nameOrId: string | number, isRgb?: boolean): Promise + + /** + * Get a highlight by name, return rgb by default. + * + * **Note:** works on neovim only. + */ + getHighlightByName(name: string, isRgb?: boolean): Promise + + /** + * Get a highlight by id, return rgb by default. + * + * **Note:** works on neovim only. + */ + getHighlightById(id: number, isRgb?: boolean): Promise + + /** + * Delete current line in buffer. + */ + deleteCurrentLine(): Promise + + /** + * Evaluates a VimL expression (:help expression). Dictionaries + * and Lists are recursively expanded. On VimL error: Returns a + * generic error; v:errmsg is not updated. + * + */ + eval(expr: string): Promise + + /** + * Executes lua, it's possible neovim client does not support this + * + * **Note:** works on neovim only. + */ + lua(code: string, args?: VimValue[]): Promise + + /** + * Calls a VimL |Dictionary-function| with the given arguments. + */ + callDictFunction(dict: object | string, fname: string, args: VimValue | VimValue[]): Promise + + /** + * Call a vim function. + * + * @param {string} fname - function name + * @param {VimValue | VimValue[]} args + * @returns {Promise} + */ + call(fname: string, args?: VimValue | VimValue[]): Promise + + /** + * Call a vim function by notification. + */ + call(fname: string, args: VimValue | VimValue[], isNotify: true): void + + /** + * Call a vim function with timer of timeout 0. + * + * @param {string} fname - function name + * @param {VimValue | VimValue[]} args + * @returns {Promise} + */ + callTimer(fname: string, args?: VimValue | VimValue[]): Promise + + /** + * Call a vim function with timer of timeout 0 by notification. + */ + callTimer(fname: string, args: VimValue | VimValue[], isNotify: true): void + + /** + * Call async vim function that accept callback as argument + * by using notifications. + */ + callAsync(fname: string, args?: VimValue | VimValue[]): Promise + + /** + * Calls many API methods atomically. + */ + callAtomic(calls: [string, VimValue[]][]): Promise<[any[], any[] | null]> + + /** + * Executes an ex-command by request. + */ + command(arg: string): Promise + + /** + * Executes an ex-command by notification. + */ + command(arg: string, isNotify: true): void + + /** + * Runs a command and returns output. + * + * @deprecated Use exec() instead. + */ + commandOutput(arg: string): Promise + + /** + * Executes Vimscript (multiline block of Ex-commands), like + * anonymous |:source| + */ + exec(src: string, output?: boolean): Promise + + /** + * Gets a v: variable. + */ + getVvar(name: string): Promise + + /** + * `:h nvim_feedkeys` + */ + feedKeys(keys: string, mode: string, escapeCsi: boolean): Promise + + /** + * Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a + * low-level input buffer and the call is non-blocking (input is + * processed asynchronously by the eventloop). + * + * On execution error: does not fail, but updates v:errmsg. + * + * **Note:** works on neovim only. + */ + input(keys: string): Promise + + /** + * Parse a VimL Expression. + */ + parseExpression(expr: string, flags: string, highlight: boolean): Promise + + /** + * Get process info, neovim only. + * + * **Note:** works on neovim only. + */ + getProc(pid: number): Promise + + /** + * Gets the immediate children of process `pid`. + * + * **Note:** works on neovim only. + */ + getProcChildren(pid: number): Promise + + /** + * Replaces terminal codes and |keycodes| (, , ...) + * in a string with the internal representation. + * + * **Note:** works on neovim only. + */ + replaceTermcodes(str: string, fromPart: boolean, doIt: boolean, special: boolean): Promise + + /** + * Gets width(display cells) of string. + */ + strWidth(str: string): Promise + + /** + * Gets a list of dictionaries representing attached UIs. + * + * **Note:** works on neovim only. + */ + uis: Promise + + /** + * Subscribe to nvim event broadcasts. + * + * **Note:** works on neovim only. + */ + subscribe(event: string): Promise + + /** + * Unsubscribe to nvim event broadcasts + * + * **Note:** works on neovim only. + */ + unsubscribe(event: string): Promise + + /** + * Activates UI events on the channel. + * + * **Note:** works on neovim only. + */ + uiAttach(width: number, height: number, options: UiAttachOptions): Promise + + /** + * `:h nvim_ui_try_resize` + * + * **Note:** works on neovim only. + */ + uiTryResize(width: number, height: number): Promise + + /** + * Deactivates UI events on the channel. + * + * **Note:** works on neovim only. + */ + uiDetach(): Promise + + /** + * Quit vim. + */ + quit(): Promise + } + + export interface Buffer extends BaseApi { + id: number + + /** Total number of lines in buffer */ + length: Promise + + /** + * Get lines of buffer. + */ + lines: Promise + + /** + * Get changedtick of buffer. + */ + changedtick: Promise + + /** + * Add buffer keymap by notification. + */ + setKeymap(mode: string, lhs: string, rhs: string, opts?: BufferKeymapOption): void + + /** + * Removes an ext mark by notification. + * + * @public + * @param {number} ns_id - Namespace id + * @param {number} id - Extmark id + */ + deleteExtMark(ns_id: number, id: number): void + + /** + * Gets the position (0-indexed) of an extmark. + * + * @param {number} ns_id - Namespace id + * @param {number} id - Extmark id + * @param {Object} opts - Optional parameters. + * @returns {Promise<[] | [number, number] | [number, number, ExtmarkDetails]>} + */ + getExtMarkById(ns_id: number, id: number, opts?: { + details?: boolean + }): Promise<[] | [number, number] | [number, number, ExtmarkDetails]> + + /** + * Gets extmarks in "traversal order" from a |charwise| region defined by + * buffer positions (inclusive, 0-indexed |api-indexing|). + * + * Region can be given as (row,col) tuples, or valid extmark ids (whose + * positions define the bounds). 0 and -1 are understood as (0,0) and (-1,-1) + * respectively, thus the following are equivalent: + * + * nvim_buf_get_extmarks(0, my_ns, 0, -1, {}) + * nvim_buf_get_extmarks(0, my_ns, [0,0], [-1,-1], {}) + * + * @param {number} ns_id - Namespace id + * @param {[number, number] | number} start + * @param {[number, number] | number} end + * @param {Object} opts + * @returns {Promise<[number, number, number, ExtmarkDetails?][]>} + */ + getExtMarks(ns_id: number, start: [number, number] | number, end: [number, number] | number, opts?: { + details?: boolean + limit?: number + }): Promise<[number, number, number, ExtmarkDetails?][]> + + /** + * Creates or updates an extmark by notification, `:h nvim_buf_set_extmark`. + * + * @param {number} ns_id + * @param {number} line + * @param {number} col + * @param {ExtmarkOptions} opts + * @returns {void} + */ + setExtMark(ns_id: number, line: number, col: number, opts?: ExtmarkOptions): void + + /** + * Add sign to buffer by notification. + * + * @param {SignPlaceOption} sign + */ + placeSign(sign: SignPlaceOption): void + + /** + * Unplace signs by notification + */ + unplaceSign(opts: SignUnplaceOption): void + + /** + * Get signs by group name or id and lnum. + * + * @param {SignPlacedOption} opts + */ + getSigns(opts: SignPlacedOption): Promise + + /** + * Get highlight items by namespace (end inclusive). + * + * @param {string} ns Namespace key or id. + * @param {number} start 0 based line number, default to 0. + * @param {number} end 0 based line number, default to -1. + */ + getHighlights(ns: string, start?: number, end?: number): Promise + + /** + * Update namespaced highlights in range by notification. + * Priority default to 0 on vim and 4096 on neovim. + * Note: timer used for whole buffer highlights for better performance. + * + * @param {string} ns Namespace key. + * @param {HighlightItem[]} highlights Highlight items. + * @param {HighlightOption} opts Highlight options. + */ + updateHighlights(ns: string, highlights: ExtendedHighlightItem[], opts?: HighlightOption): void + + /** + * Gets a map of buffer-local |user-commands|. + * + * **Note:** works on neovim only. + */ + getCommands(options?: {}): Promise + + /** + * Get lines of buffer, get all lines by default. + */ + getLines(opts?: { start: number, end: number, strictIndexing?: boolean }): Promise + + /** + * Set lines of buffer given indices use request. + */ + setLines(lines: string[], opts?: { start: number, end: number, strictIndexing?: boolean }): Promise + + /** + * Set lines of buffer given indices use notification. + */ + setLines(lines: string[], opts: { start: number, end: number, strictIndexing?: boolean }, isNotify: true): void + + /** + * Set virtual text for a line + * + * @public + * @deprecated Use `setExtMark()` instead. + * @param {number} src_id - Source group to use or 0 to use a new group, or -1 + * @param {number} line - Line to annotate with virtual text (zero-indexed) + * @param {Chunk[]} chunks - List with [text, hl_group] + * @param {[index} opts + * @returns {Promise} + */ + setVirtualText(src_id: number, line: number, chunks: [string, string][], opts?: { [index: string]: any }): Promise + + /** + * Append a string or list of lines to end of buffer + */ + append(lines: string[] | string): Promise + + /** + * Get buffer name. + */ + name: Promise + + /** + * Set buffer name. + */ + setName(name: string): Promise + + /** + * Check if buffer valid. + */ + valid: Promise + + /** + * Get mark position given mark name + * + * **Note:** works on neovim only. + */ + mark(name: string): Promise<[number, number]> + + /** + * Gets a list of buffer-local |mapping| definitions. + * + * @return Array of maparg()-like dictionaries describing mappings. + * The "buffer" key holds the associated buffer handle. + */ + getKeymap(mode: string): Promise + + /** + * Check if buffer loaded. + */ + loaded: Promise + + /** + * Returns the byte offset for a line. + * + * Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is + * one byte. 'fileformat' and 'fileencoding' are ignored. The + * line index just after the last line gives the total byte-count + * of the buffer. A final EOL byte is counted if it would be + * written, see 'eol'. + * + * Unlike |line2byte()|, throws error for out-of-bounds indexing. + * Returns -1 for unloaded buffer. + * + * @return {Number} Integer byte offset, or -1 for unloaded buffer. + */ + getOffset(index: number): Promise + + /** + * Adds a highlight to buffer, checkout |nvim_buf_add_highlight|. + * + * Note: when `srcId = 0`, request is made for new `srcId`, otherwire, use notification. + * Note: `hlGroup` as empty string is not supported. + * + * @deprecated use `highlightRanges()` instead. + */ + addHighlight(opts: BufferHighlight): Promise + + /** + * Clear highlights of specified lins. + * + * @deprecated use clearNamespace() instead. + */ + clearHighlight(args?: BufferClearHighlight) + + /** + * Add highlight to ranges by notification, works on both vim & neovim. + * + * Works on neovim and `workspace.isVim && workspace.env.textprop` is true + * + * @param {string | number} srcId Unique key or namespace number. + * @param {string} hlGroup Highlight group. + * @param {Range[]} ranges List of highlight ranges + */ + highlightRanges(srcId: string | number, hlGroup: string, ranges: Range[]): void + + /** + * Clear namespace by id or name by notification, works on both vim & neovim. + * + * Works on neovim and `workspace.isVim && workspace.env.textprop` is true + * + * @param key Unique key or namespace number, use -1 for all namespaces + * @param lineStart Start of line, 0 based, default to 0. + * @param lineEnd End of line, 0 based, default to -1. + */ + clearNamespace(key: number | string, lineStart?: number, lineEnd?: number) + } + + export interface Window extends BaseApi { + /** + * The windowid that not change within a Vim session + */ + id: number + + /** + * Buffer in window. + */ + buffer: Promise + + /** + * Tabpage contains window. + */ + tabpage: Promise + + /** + * Cursor position as [line, col], 1 based. + */ + cursor: Promise<[number, number]> + + /** + * Window height. + */ + height: Promise + + /** + * Window width. + */ + width: Promise + + /** + * Set cursor position by request. + */ + setCursor(pos: [number, number]): Promise + + /** + * Set cursor position by notification. + */ + setCursor(pos: [number, number], isNotify: true): void + + /** + * Set height + */ + setHeight(height: number): Promise + + /** + * Set height by notification. + */ + setHeight(height: number, isNotify: true): void + + /** + * Set width. + */ + setWidth(width: number): Promise + + /** + * Set width by notification. + */ + setWidth(width: number, isNotify: true): void + + /** + * Get window position, not work with vim8's popup. + */ + position: Promise<[number, number]> + + /** 0-indexed, on-screen window position(row) in display cells. */ + row: Promise + + /** 0-indexed, on-screen window position(col) in display cells. */ + col: Promise + + /** + * Check if window valid. + */ + valid: Promise + + /** + * Get window number, throws for invalid window. + */ + number: Promise + + /** + * Config float window with options. + * + * **Note:** works on neovim only. + */ + setConfig(options: NvimFloatOptions): Promise + + /** + * Config float window with options by send notification. + * + * **Note:** works on neovim only. + */ + setConfig(options: NvimFloatOptions, isNotify: true): void + + /** + * Gets window configuration. + * + * **Note:** works on neovim only. + * + * @returns Map defining the window configuration, see |nvim_open_win()| + */ + getConfig(): Promise + + /** + * Close window by send request. + */ + close(force: boolean): Promise + + /** + * Close window by send notification. + */ + close(force: boolean, isNotify: true): void + + /** + * Add highlight to ranges by request (matchaddpos is used) + * + * @return {Promise} match ids. + */ + highlightRanges(hlGroup: string, ranges: Range[], priority?: number): Promise + + /** + * Add highlight to ranges by notification (matchaddpos is used) + */ + highlightRanges(hlGroup: string, ranges: Range[], priority: number, isNotify: true): void + + /** + * Clear match of highlight group by send notification. + */ + clearMatchGroup(hlGroup: string): void + + /** + * Clear match of match ids by send notification. + */ + clearMatches(ids: number[]): void + } + + export interface Tabpage extends BaseApi { + /** + * tabpage number. + */ + number: Promise + + /** + * Is current tabpage valid. + */ + valid: Promise + + /** + * Returns all windows of tabpage. + */ + windows: Promise + + /** + * Current window of tabpage. + */ + window: Promise + } + // }} + + // vscode-uri {{ + export interface UriComponents { + scheme: string + authority: string + path: string + query: string + fragment: string + } + /** + * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. + * This class is a simple parser which creates the basic component parts + * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation + * and encoding. + * + * ```txt + * foo://example.com:8042/over/there?name=ferret#nose + * \_/ \______________/\_________/ \_________/ \__/ + * | | | | | + * scheme authority path query fragment + * | _____________________|__ + * / \ / \ + * urn:example:animal:ferret:nose + * ``` + */ + export class Uri implements UriComponents { + static isUri(thing: any): thing is Uri + /** + * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. + * The part before the first colon. + */ + readonly scheme: string + /** + * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'. + * The part between the first double slashes and the next slash. + */ + readonly authority: string + /** + * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'. + */ + readonly path: string + /** + * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'. + */ + readonly query: string + /** + * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'. + */ + readonly fragment: string + /** + * @internal + */ + protected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean) + /** + * @internal + */ + protected constructor(components: UriComponents) + /** + * Returns a string representing the corresponding file system path of this URI. + * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the + * platform specific path separator. + * + * * Will *not* validate the path for invalid characters and semantics. + * * Will *not* look at the scheme of this URI. + * * The result shall *not* be used for display purposes but for accessing a file on disk. + * + * + * The *difference* to `URI#path` is the use of the platform specific separator and the handling + * of UNC paths. See the below sample of a file-uri with an authority (UNC path). + * + * ```ts + const u = URI.parse('file://server/c$/folder/file.txt') + u.authority === 'server' + u.path === '/shares/c$/file.txt' + u.fsPath === '\\server\c$\folder\file.txt' + ``` + * + * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path, + * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working + * with URIs that represent files on disk (`file` scheme). + */ + readonly fsPath: string + with(change: { + scheme?: string + authority?: string | null + path?: string | null + query?: string | null + fragment?: string | null + }): Uri + /** + * Creates a new URI from a string, e.g. `http://www.msft.com/some/path`, + * `file:///usr/home`, or `scheme:with/path`. + * + * @param value A string which represents an URI (see `URI#toString`). + */ + static parse(value: string, _strict?: boolean): Uri + /** + * Creates a new URI from a file system path, e.g. `c:\my\files`, + * `/usr/home`, or `\\server\share\some\path`. + * + * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument + * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as** + * `URI.parse('file://' + path)` because the path might contain characters that are + * interpreted (# and ?). See the following sample: + * ```ts + const good = URI.file('/coding/c#/project1'); + good.scheme === 'file'; + good.path === '/coding/c#/project1'; + good.fragment === ''; + const bad = URI.parse('file://' + '/coding/c#/project1'); + bad.scheme === 'file'; + bad.path === '/coding/c'; // path is now broken + bad.fragment === '/project1'; + ``` + * + * @param path A file system path (see `URI#fsPath`) + */ + static file(path: string): Uri + static from(components: { + scheme: string + authority?: string + path?: string + query?: string + fragment?: string + }): Uri + /** + * Creates a string representation for this URI. It's guaranteed that calling + * `URI.parse` with the result of this function creates an URI which is equal + * to this URI. + * + * * The result shall *not* be used for display purposes but for externalization or transport. + * * The result will be encoded using the percentage encoding and encoding happens mostly + * ignore the scheme-specific encoding rules. + * + * @param skipEncoding Do not encode the result, default is `false` + */ + toString(skipEncoding?: boolean): string + toJSON(): UriComponents + } + // }} + + // vim interfaces {{ + /** + * See `:h complete-items` + */ + export interface VimCompleteItem { + word: string + abbr?: string + menu?: string + info?: string + kind?: string + icase?: number + equal?: number + dup?: number + empty?: number + user_data?: string + } + + export interface LocationListItem { + bufnr: number + lnum: number + end_lnum: number + col: number + end_col: number + text: string + type: string + } + + export interface QuickfixItem { + uri?: string + module?: string + range?: Range + text?: string + type?: string + filename?: string + bufnr?: number + lnum?: number + end_lnum?: number + col?: number + end_col?: number + valid?: boolean + nr?: number + } + // }} + + // provider interfaces {{ + /** + * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves + * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a + * thenable. + * + * The snippets below are all valid implementations of the [`HoverProvider`](#HoverProvider): + * + * ```ts + * let a: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Hover('Hello World') + * } + * } + * + * let b: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return new Promise(resolve => { + * resolve(new Hover('Hello World')) + * }) + * } + * } + * + * let c: HoverProvider = { + * provideHover(doc, pos, token): ProviderResult { + * return; // undefined + * } + * } + * ``` + */ + export type ProviderResult = + | T + | undefined + | null + | Thenable + + /** + * Supported provider names. + */ + export type ProviderName = 'rename' | 'onTypeEdit' | 'documentLink' | 'documentColor' + | 'foldingRange' | 'format' | 'codeAction' | 'workspaceSymbols' | 'formatRange' | 'formatOnType' + | 'hover' | 'signature' | 'documentSymbol' | 'documentHighlight' | 'definition' + | 'declaration' | 'typeDefinition' | 'reference' | 'implementation' + | 'codeLens' | 'selectionRange' | 'callHierarchy' | 'semanticTokens' | 'linkedEditing' + + /** + * The completion item provider interface defines the contract between extensions and + * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). + * + * Providers can delay the computation of the [`detail`](#CompletionItem.detail) + * and [`documentation`](#CompletionItem.documentation) properties by implementing the + * [`resolveCompletionItem`](#CompletionItemProvider.resolveCompletionItem)-function. However, properties that + * are needed for the initial sorting and filtering, like `sortText`, `filterText`, `insertText`, and `range`, must + * not be changed during resolve. + * + * Providers are asked for completions either explicitly by a user gesture or -depending on the configuration- + * implicitly when typing words or trigger characters. + */ + export interface CompletionItemProvider { + /** + * Provide completion items for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @param context How the completion was triggered. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideCompletionItems( + document: LinesTextDocument, + position: Position, + token: CancellationToken, + context?: CompletionContext + ): ProviderResult + + /** + * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) + * or [details](#CompletionItem.detail). + * + * The editor will only resolve a completion item once. + * + * @param item A completion item currently active in the UI. + * @param token A cancellation token. + * @return The resolved completion item or a thenable that resolves to of such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveCompletionItem?( + item: CompletionItem, + token: CancellationToken + ): ProviderResult + } + + /** + * The hover provider interface defines the contract between extensions and + * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ + export interface HoverProvider { + /** + * Provide a hover for the given position and document. Multiple hovers at the same + * position will be merged by the editor. A hover can have a range which defaults + * to the word range at the position when omitted. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A hover or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideHover( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The definition provider interface defines the contract between extensions and + * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) + * and peek definition features. + */ + export interface DefinitionProvider { + /** + * Provide the definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideDefinition( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The definition provider interface defines the contract between extensions and + * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition) + * and peek definition features. + */ + export interface DeclarationProvider { + /** + * Provide the declaration of the symbol at the given position and document. + */ + provideDeclaration( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The signature help provider interface defines the contract between extensions and + * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature. + */ + export interface SignatureHelpProvider { + /** + * Provide help for the signature at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return Signature help or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideSignatureHelp( + document: LinesTextDocument, + position: Position, + token: CancellationToken, + context: SignatureHelpContext + ): ProviderResult + } + + /** + * The type definition provider defines the contract between extensions and + * the go to type definition feature. + */ + export interface TypeDefinitionProvider { + /** + * Provide the type definition of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideTypeDefinition( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * Value-object that contains additional information when + * requesting references. + */ + export interface ReferenceContext { + /** + * Include the declaration of the current symbol. + */ + includeDeclaration: boolean + } + + /** + * The reference provider interface defines the contract between extensions and + * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature. + */ + export interface ReferenceProvider { + /** + * Provide a set of project-wide references for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param context + * @param token A cancellation token. + * @return An array of locations or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideReferences( + document: LinesTextDocument, + position: Position, + context: ReferenceContext, + token: CancellationToken + ): ProviderResult + } + + /** + * Folding context (for future use) + */ + export interface FoldingContext {} + + /** + * The folding range provider interface defines the contract between extensions and + * [Folding](https://code.visualstudio.com/docs/editor/codebasics#_folding) in the editor. + */ + export interface FoldingRangeProvider { + /** + * Returns a list of folding ranges or null and undefined if the provider + * does not want to participate or was cancelled. + * + * @param document The document in which the command was invoked. + * @param context Additional context information (for future use) + * @param token A cancellation token. + */ + provideFoldingRanges( + document: LinesTextDocument, + context: FoldingContext, + token: CancellationToken + ): ProviderResult + } + + /** + * The document symbol provider interface defines the contract between extensions and + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. + */ + export interface DocumentSymbolProvider { + /** + * Provide symbol information for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentSymbols( + document: LinesTextDocument, + token: CancellationToken + ): ProviderResult + } + + /** + * The implementation provider interface defines the contract between extensions and + * the go to implementation feature. + */ + export interface ImplementationProvider { + /** + * Provide the implementations of the symbol at the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return A definition or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideImplementation( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The workspace symbol provider interface defines the contract between extensions and + * the [symbol search](https://code.visualstudio.com/docs/editor/editingevolved#_open-symbol-by-name)-feature. + */ + export interface WorkspaceSymbolProvider { + /** + * Project-wide search for a symbol matching the given query string. It is up to the provider + * how to search given the query string, like substring, indexOf etc. To improve performance implementors can + * skip the [location](#SymbolInformation.location) of symbols and implement `resolveWorkspaceSymbol` to do that + * later. + * + * The `query`-parameter should be interpreted in a *relaxed way* as the editor will apply its own highlighting + * and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the + * characters of *query* appear in their order in a candidate symbol. Don't use prefix, substring, or similar + * strict matching. + * + * @param query A non-empty query string. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideWorkspaceSymbols( + query: string, + token: CancellationToken + ): ProviderResult + + /** + * Given a symbol fill in its [location](#SymbolInformation.location). This method is called whenever a symbol + * is selected in the UI. Providers can implement this method and return incomplete symbols from + * [`provideWorkspaceSymbols`](#WorkspaceSymbolProvider.provideWorkspaceSymbols) which often helps to improve + * performance. + * + * @param symbol The symbol that is to be resolved. Guaranteed to be an instance of an object returned from an + * earlier call to `provideWorkspaceSymbols`. + * @param token A cancellation token. + * @return The resolved symbol or a thenable that resolves to that. When no result is returned, + * the given `symbol` is used. + */ + resolveWorkspaceSymbol?( + symbol: SymbolInformation, + token: CancellationToken + ): ProviderResult + } + + /** + * The rename provider interface defines the contract between extensions and + * the [rename](https://code.visualstudio.com/docs/editor/editingevolved#_rename-symbol)-feature. + */ + export interface RenameProvider { + /** + * Provide an edit that describes changes that have to be made to one + * or many resources to rename a symbol to a different name. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param newName The new name of the symbol. If the given name is not valid, the provider must return a rejected promise. + * @param token A cancellation token. + * @return A workspace edit or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideRenameEdits( + document: LinesTextDocument, + position: Position, + newName: string, + token: CancellationToken + ): ProviderResult + + /** + * Optional function for resolving and validating a position *before* running rename. The result can + * be a range or a range and a placeholder text. The placeholder text should be the identifier of the symbol + * which is being renamed - when omitted the text in the returned range is used. + * + * @param document The document in which rename will be invoked. + * @param position The position at which rename will be invoked. + * @param token A cancellation token. + * @return The range or range and placeholder text of the identifier that is to be renamed. The lack of a result can signaled by returning `undefined` or `null`. + */ + prepareRename?( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface DocumentFormattingEditProvider { + /** + * Provide formatting edits for a whole document. + * + * @param document The document in which the command was invoked. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentFormattingEdits( + document: LinesTextDocument, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface DocumentRangeFormattingEditProvider { + /** + * Provide formatting edits for a range in a document. + * + * The given range is a hint and providers can decide to format a smaller + * or larger range. Often this is done by adjusting the start and end + * of the range to full syntax nodes. + * + * @param document The document in which the command was invoked. + * @param range The range which should be formatted. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentRangeFormattingEdits( + document: LinesTextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): ProviderResult + } + + /** + * The code action interface defines the contract between extensions and + * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + * + * A code action can be any command that is [known](#commands.getCommands) to the system. + */ + export interface CodeActionProvider { + /** + * Provide commands for the given document and range. + * + * @param document The document in which the command was invoked. + * @param range The selector or range for which the command was invoked. This will always be a selection if + * there is a currently active editor. + * @param context Context carrying additional information. + * @param token A cancellation token. + * @return An array of commands, quick fixes, or refactorings or a thenable of such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeActions( + document: LinesTextDocument, + range: Range, + context: CodeActionContext, + token: CancellationToken + ): ProviderResult<(Command | CodeAction)[]> + + /** + * Given a code action fill in its [`edit`](#CodeAction.edit)-property. Changes to + * all other properties, like title, are ignored. A code action that has an edit + * will not be resolved. + * + * @param codeAction A code action. + * @param token A cancellation token. + * @return The resolved code action or a thenable that resolves to such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveCodeAction?(codeAction: T, token: CancellationToken): ProviderResult + } + + /** + * Metadata about the type of code actions that a [CodeActionProvider](#CodeActionProvider) providers + */ + export interface CodeActionProviderMetadata { + /** + * [CodeActionKinds](#CodeActionKind) that this provider may return. + * + * The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the provider + * may list our every specific kind they provide, such as `CodeActionKind.Refactor.Extract.append('function`)` + */ + readonly providedCodeActionKinds?: ReadonlyArray + } + + /** + * The document highlight provider interface defines the contract between extensions and + * the word-highlight-feature. + */ + export interface DocumentHighlightProvider { + + /** + * Provide a set of document highlights, like all occurrences of a variable or + * all exit-points of a function. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentHighlights( + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + /** + * The document link provider defines the contract between extensions and feature of showing + * links in the editor. + */ + export interface DocumentLinkProvider { + + /** + * Provide links for the given document. Note that the editor ships with a default provider that detects + * `http(s)` and `file` links. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [document links](#DocumentLink) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentLinks(document: LinesTextDocument, token: CancellationToken): ProviderResult + + /** + * Given a link fill in its [target](#DocumentLink.target). This method is called when an incomplete + * link is selected in the UI. Providers can implement this method and return incomple links + * (without target) from the [`provideDocumentLinks`](#DocumentLinkProvider.provideDocumentLinks) method which + * often helps to improve performance. + * + * @param link The link that is to be resolved. + * @param token A cancellation token. + */ + resolveDocumentLink?(link: DocumentLink, token: CancellationToken): ProviderResult + } + + /** + * A code lens provider adds [commands](#Command) to source text. The commands will be shown + * as dedicated horizontal lines in between the source text. + */ + export interface CodeLensProvider { + + /** + * Compute a list of [lenses](#CodeLens). This call should return as fast as possible and if + * computing the commands is expensive implementors should only return code lens objects with the + * range set and implement [resolve](#CodeLensProvider.resolveCodeLens). + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of code lenses or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideCodeLenses(document: LinesTextDocument, token: CancellationToken): ProviderResult + + /** + * This function will be called for each visible code lens, usually when scrolling and after + * calls to [compute](#CodeLensProvider.provideCodeLenses)-lenses. + * + * @param codeLens code lens that must be resolved. + * @param token A cancellation token. + * @return The given, resolved code lens or thenable that resolves to such. + */ + resolveCodeLens?(codeLens: CodeLens, token: CancellationToken): ProviderResult + } + + /** + * The document formatting provider interface defines the contract between extensions and + * the formatting-feature. + */ + export interface OnTypeFormattingEditProvider { + + /** + * Provide formatting edits after a character has been typed. + * + * The given position and character should hint to the provider + * what range the position to expand to, like find the matching `{` + * when `}` has been entered. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param ch The character that has been typed. + * @param options Options controlling formatting. + * @param token A cancellation token. + * @return A set of text edits or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined`, `null`, or an empty array. + */ + provideOnTypeFormattingEdits(document: LinesTextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult + } + + /** + * The document color provider defines the contract between extensions and feature of + * picking and modifying colors in the editor. + */ + export interface DocumentColorProvider { + + /** + * Provide colors for the given document. + * + * @param document The document in which the command was invoked. + * @param token A cancellation token. + * @return An array of [color information](#ColorInformation) or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideDocumentColors(document: LinesTextDocument, token: CancellationToken): ProviderResult + + /** + * Provide [representations](#ColorPresentation) for a color. + * + * @param color The color to show and insert. + * @param context A context object with additional information + * @param token A cancellation token. + * @return An array of color presentations or a thenable that resolves to such. The lack of a result + * can be signaled by returning `undefined`, `null`, or an empty array. + */ + provideColorPresentations(color: Color, context: { document: LinesTextDocument; range: Range }, token: CancellationToken): ProviderResult + } + + export interface TextDocumentContentProvider { + + /** + * An event to signal a resource has changed. + */ + onDidChange?: Event + + /** + * Provide textual content for a given uri. + * + * The editor will use the returned string-content to create a readonly + * [document](#LinesTextDocument). Resources allocated should be released when + * the corresponding document has been [closed](#workspace.onDidCloseTextDocument). + * + * @param uri An uri which scheme matches the scheme this provider was [registered](#workspace.registerTextDocumentContentProvider) for. + * @param token A cancellation token. + * @return A string or a thenable that resolves to such. + */ + provideTextDocumentContent(uri: Uri, token: CancellationToken): ProviderResult + } + + export interface SelectionRangeProvider { + /** + * Provide selection ranges starting at a given position. The first range must [contain](#Range.contains) + * position and subsequent ranges must contain the previous range. + */ + provideSelectionRanges(document: LinesTextDocument, positions: Position[], token: CancellationToken): ProviderResult + } + + /** + * The call hierarchy provider interface describes the contract between extensions + * and the call hierarchy feature which allows to browse calls and caller of function, + * methods, constructor etc. + */ + export interface CallHierarchyProvider { + + /** + * Bootstraps call hierarchy by returning the item that is denoted by the given document + * and position. This item will be used as entry into the call graph. Providers should + * return `undefined` or `null` when there is no item at the given location. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @returns A call hierarchy item or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + prepareCallHierarchy(document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + + /** + * Provide all incoming calls for an item, e.g all callers for a method. In graph terms this describes directed + * and annotated edges inside the call graph, e.g the given item is the starting node and the result is the nodes + * that can be reached. + * + * @param item The hierarchy item for which incoming calls should be computed. + * @param token A cancellation token. + * @returns A set of incoming calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult + + /** + * Provide all outgoing calls for an item, e.g call calls to functions, methods, or constructors from the given item. In + * graph terms this describes directed and annotated edges inside the call graph, e.g the given item is the starting + * node and the result is the nodes that can be reached. + * + * @param item The hierarchy item for which outgoing calls should be computed. + * @param token A cancellation token. + * @returns A set of outgoing calls or a thenable that resolves to such. The lack of a result can be + * signaled by returning `undefined` or `null`. + */ + provideCallHierarchyOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult + } + + /** + * The document semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentSemanticTokensProvider { + /** + * An optional event to signal that the semantic tokens from this provider have changed. + */ + // TODO: SemantiTokens + onDidChangeSemanticTokens?: Event + + /** + * Tokens in a file are represented as an array of integers. The position of each token is expressed relative to + * the token before it, because most tokens remain stable relative to each other when edits are made in a file. + * + * --- + * In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices: + * + * - at index `5*i` - `deltaLine`: token line number, relative to the previous token + * - at index `5*i+1` - `deltaStart`: token start character, relative to the previous token (relative to 0 or the previous token's start if they are on the same line) + * - at index `5*i+2` - `length`: the length of the token. A token cannot be multiline. + * - at index `5*i+3` - `tokenType`: will be looked up in `SemanticTokensLegend.tokenTypes`. We currently ask that `tokenType` < 65536. + * - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + * + * --- + * ### How to encode tokens + * + * Here is an example for encoding a file with 3 tokens in a uint32 array: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 2, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 5, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * + * 1. First of all, a legend must be devised. This legend must be provided up-front and capture all possible token types. + * For this example, we will choose the following legend which must be passed in when registering the provider: + * ``` + * tokenTypes: ['property', 'type', 'class'], + * tokenModifiers: ['private', 'static'] + * ``` + * + * 2. The first transformation step is to encode `tokenType` and `tokenModifiers` as integers using the legend. Token types are looked + * up by index, so a `tokenType` value of `1` means `tokenTypes[1]`. Multiple token modifiers can be set by using bit flags, + * so a `tokenModifier` value of `3` is first viewed as binary `0b00000011`, which means `[tokenModifiers[0], tokenModifiers[1]]` because + * bits 0 and 1 are set. Using this legend, the tokens now are: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { line: 2, startChar: 10, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { line: 5, startChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 3. The next step is to represent each token relative to the previous token in the file. In this case, the second token + * is on the same line as the first token, so the `startChar` of the second token is made relative to the `startChar` + * of the first token, so it will be `10 - 5`. The third token is on a different line than the second token, so the + * `startChar` of the third token will not be altered: + * ``` + * { deltaLine: 2, deltaStartChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { deltaLine: 0, deltaStartChar: 5, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { deltaLine: 3, deltaStartChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 4. Finally, the last step is to inline each of the 5 fields for a token in a single array, which is a memory friendly representation: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to encode tokens as integers. + * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. + * *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'. + */ + provideDocumentSemanticTokens(document: LinesTextDocument, token: CancellationToken): ProviderResult + + /** + * Instead of always returning all the tokens in a file, it is possible for a `DocumentSemanticTokensProvider` to implement + * this method (`provideDocumentSemanticTokensEdits`) and then return incremental updates to the previously provided semantic tokens. + * + * --- + * ### How tokens change when the document changes + * + * Suppose that `provideDocumentSemanticTokens` has previously returned the following semantic tokens: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * + * Also suppose that after some edits, the new semantic tokens in a file are: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + * It is possible to express these new tokens in terms of an edit applied to the previous tokens: + * ``` + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens + * [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // new tokens + * + * edit: { start: 0, deleteCount: 1, data: [3] } // replace integer at offset 0 with 3 + * ``` + * + * *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again. + * *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state. + */ + provideDocumentSemanticTokensEdits?(document: LinesTextDocument, previousResultId: string, token: CancellationToken): ProviderResult + } + + /** + * The document range semantic tokens provider interface defines the contract between extensions and + * semantic tokens. + */ + export interface DocumentRangeSemanticTokensProvider { + /** + * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens). + */ + provideDocumentRangeSemanticTokens(document: LinesTextDocument, range: Range, token: CancellationToken): ProviderResult + } + + export interface LinkedEditingRangeProvider { + /** + * For a given position in a document, returns the range of the symbol at the position and all ranges + * that have the same content. A change to one of the ranges can be applied to all other ranges if the new content + * is valid. An optional word pattern can be returned with the result to describe valid contents. + * If no result-specific word pattern is provided, the word pattern from the language configuration is used. + * + * @param document The document in which the provider was invoked. + * @param position The position at which the provider was invoked. + * @param token A cancellation token. + * @return A list of ranges that can be edited together + */ + provideLinkedEditingRanges(document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + /** + * The inlay hints provider interface defines the contract between extensions and + * the inlay hints feature. + */ + export interface InlayHintsProvider { + + /** + * An optional event to signal that inlay hints from this provider have changed. + */ + onDidChangeInlayHints?: Event + + /** + * Provide inlay hints for the given range and document. + * + * *Note* that inlay hints that are not {@link Range.contains contained} by the given range are ignored. + * + * @param document The document in which the command was invoked. + * @param range The range for which inlay hints should be computed. + * @param token A cancellation token. + * @return An array of inlay hints or a thenable that resolves to such. + */ + provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): ProviderResult + + /** + * Given an inlay hint fill in {@link InlayHint.tooltip tooltip}, {@link InlayHint.textEdits text edits}, + * or complete label {@link InlayHintLabelPart parts}. + * + * *Note* that the editor will resolve an inlay hint at most once. + * + * @param hint An inlay hint. + * @param token A cancellation token. + * @return The resolved inlay hint or a thenable that resolves to such. It is OK to return the given `item`. When no result is returned, the given `item` will be used. + */ + resolveInlayHint?(hint: T, token: CancellationToken): ProviderResult + } + // }} + + // Classes {{ + /** + * A semantic tokens builder can help with creating a `SemanticTokens` instance + * which contains delta encoded semantic tokens. + */ + export class SemanticTokensBuilder { + constructor(legend?: SemanticTokensLegend) + + /** + * Add another token. + * + * @public + * @param line The token start line number (absolute value). + * @param char The token start character (absolute value). + * @param length The token length in characters. + * @param tokenType The encoded token type. + * @param tokenModifiers The encoded token modifiers. + */ + push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void + /** + * Add another token. Use only when providing a legend. + * + * @public + * @param range The range of the token. Must be single-line. + * @param tokenType The token type. + * @param tokenModifiers The token modifiers. + */ + push(range: Range, tokenType: string, tokenModifiers?: string[]): void + + /** + * Finish and create a `SemanticTokens` instance. + * + * @public + */ + build(resultId?: string): SemanticTokens + } + + export interface Document { + readonly buffer: Buffer + /** + * Document is attached to vim. + */ + readonly attached: boolean + /** + * Is command line document. + */ + readonly isCommandLine: boolean + /** + * `buftype` option of buffer. + */ + readonly buftype: string + /** + * Text document that synchronized. + */ + readonly textDocument: LinesTextDocument + /** + * Fired when document change. + */ + readonly onDocumentChange: Event + /** + * Get current buffer changedtick. + */ + readonly changedtick: number + /** + * Scheme of document. + */ + readonly schema: string + /** + * Line count of current buffer. + */ + readonly lineCount: number + /** + * Window ID when buffer create, could be -1 when no window associated. + */ + readonly winid: number + /** + * Returns if current document is opended with previewwindow + */ + readonly previewwindow: boolean + /** + * Check if document changed after last synchronize + */ + readonly dirty: boolean + /** + * Buffer number + */ + readonly bufnr: number + /** + * Content of textDocument. + */ + readonly content: string + /** + * Converted filetype. + */ + readonly filetype: string + /** + * Main filetype of buffer, first part when buffer filetype contains dots. + * Same as filetype most of the time. + */ + readonly languageId: string + readonly uri: string + readonly version: number + /** + * Apply text edits to document. `nvim_buf_set_text()` is used when possible + * + * @param {TextEdit[]} edits + * @param {boolean} joinUndo - Join further changes with the previous undo block by `:undojoin`. + * @param {boolean | Position} move - Move the cursor when true or from custom position. + * @returns {Promise} + */ + applyEdits(edits: TextEdit[], joinUndo?: boolean, move?: boolean | Position): Promise + + /** + * Change individual lines. + * + * @param {[number, string][]} lines + * @returns {void} + */ + changeLines(lines: [number, string][]): Promise + + /** + * Get offset from lnum & col + */ + getOffset(lnum: number, col: number): number + + /** + * Check string is word. + */ + isWord(word: string): boolean + + /** + * Word range at position. + * + * @param {Position} position + * @param {string} extraChars Extra characters that should be keyword. + * @param {boolean} current Use current lines instead of textDocument, default to true. + * @returns {Range | null} + */ + getWordRangeAtPosition(position: Position, extraChars?: string, current?: boolean): Range | null + + /** + * Get ranges of word in textDocument. + */ + getSymbolRanges(word: string): Range[] + + /** + * Get line for buffer + * + * @param {number} line 0 based line index. + * @param {boolean} current Use textDocument lines when false, default to true. + * @returns {string} + */ + getline(line: number, current?: boolean): string + + /** + * Get range of current lines, zero indexed, end exclude. + */ + getLines(start?: number, end?: number): string[] + + /** + * Get variable value by key, defined by `b:coc_{key}` + */ + getVar(key: string, defaultValue?: T): T + + /** + * Get position from lnum & col + */ + getPosition(lnum: number, col: number): Position + + /** + * Adjust col with new valid character before position. + */ + fixStartcol(position: Position, valids: string[]): number + + /** + * Get current content text. + */ + getDocumentContent(): string + } + + /** + * Represents a {@link TextEditor text editor}'s {@link TextEditor.options options}. + */ + export interface TextEditorOptions { + /** + * The size in spaces a tab takes. This is used for two purposes: + * - the rendering width of a tab character; + * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true. + * + * When getting a text editor's options, this property will always be a number (resolved). + */ + tabSize: number + /** + * When pressing Tab insert {@link TextEditorOptions.tabSize n} spaces. + * When getting a text editor's options, this property will always be a boolean (resolved). + */ + insertSpaces: boolean + } + + /** + * Represents an editor that is attached to a {@link TextDocument document}. + */ + export interface TextEditor { + /** + * The tabpagenr of current editor. + */ + readonly tabpagenr: number + /** + * The window id of current editor. + */ + readonly winid: number + /** + * The window number of current editor. + */ + readonly winnr: number + /** + * The document associated with this text editor. The document will be the same for the entire lifetime of this text editor. + */ + readonly document: Document + /** + * The current visible ranges in the editor (vertically). + * This accounts only for vertical scrolling, and not for horizontal scrolling. + */ + readonly visibleRanges: readonly Range[] + /** + * Text editor options. + */ + readonly options: TextEditorOptions + } + + export interface FloatWinConfig { + maxHeight?: number + maxWidth?: number + preferTop?: boolean + autoHide?: boolean + offsetX?: number + title?: string + border?: number[] + cursorline?: boolean + close?: boolean + highlight?: string + borderhighlight?: string + modes?: string[] + shadow?: boolean + winblend?: number + focusable?: boolean + excludeImages?: boolean + } + + export interface Documentation { + /** + * Filetype used for highlight, markdown is supported. + */ + filetype: string + /** + * Content of document. + */ + content: string + /** + * Byte offset (0 based) that should be undelined. + */ + active?: [number, number] + highlights?: HighlightItem[] + } + + /** + * Float window factory for create float around current cursor, works on vim and neovim. + * Use `workspace.floatSupported` to check if float could work. + * + * Float windows are automatic reused and hidden on specific events including: + * - BufEnter + * - InsertEnter + * - InsertLeave + * - MenuPopupChanged + * - CursorMoved + * - CursorMovedI + */ + export class FloatFactory implements Disposable { + get bufnr(): number | undefined + get buffer(): Buffer | null + get window(): Window | null + activated(): Promise + + constructor(nvim: Neovim) + + /** + * Show documentations in float window/popup around cursor. + * Window and buffer are reused when possible. + * Window is closed automatically on change buffer, InsertEnter, CursorMoved and CursorMovedI. + * + * @param docs List of documentations. + * @param config Configuration for floating window/popup. + */ + show(docs: Documentation[], config?: FloatWinConfig): Promise + + /** + * Close float window. + */ + close(): void + dispose(): void + } + + + /** + * A file glob pattern to match file paths against. This can either be a glob pattern string + * (like `**​/*.{ts,js}` or `*.{ts,js}`) or a {@link RelativePattern relative pattern}. + * + * Glob patterns can have the following syntax: + * * `*` to match one or more characters in a path segment + * * `?` to match on one character in a path segment + * * `**` to match any number of path segments, including none + * * `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) + * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + * + * Note: a backslash (`\`) is not valid within a glob pattern. If you have an existing file + * path to match against, consider to use the {@link RelativePattern relative pattern} support + * that takes care of converting any backslash into slash. Otherwise, make sure to convert + * any backslash to slash when creating the glob pattern. + */ + export type GlobPattern = string | RelativePattern + + /** + * A relative pattern is a helper to construct glob patterns that are matched + * relatively to a base file path. The base path can either be an absolute file + * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the + * preferred way of creating the relative pattern. + */ + export class RelativePattern { + + /** + * A base file path to which this pattern will be matched against relatively. + */ + baseUri: Uri + + /** + * A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + * + * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`, + * the file glob pattern will match on `index.js`. + */ + pattern: string + + /** + * Creates a new relative pattern object with a base file path and pattern to match. This pattern + * will be matched on file paths relative to the base. + * + * Example: + * ```ts + * const folder = vscode.workspace.workspaceFolders?.[0]; + * if (folder) { + * + * // Match any TypeScript file in the root of this workspace folder + * const pattern1 = new vscode.RelativePattern(folder, '*.ts'); + * + * // Match any TypeScript file in `someFolder` inside this workspace folder + * const pattern2 = new vscode.RelativePattern(folder, 'someFolder/*.ts'); + * } + * ``` + * + * @param base A base to which this pattern will be matched against relatively. It is recommended + * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace. + * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace. + * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base. + */ + constructor(base: WorkspaceFolder | Uri | string, pattern: string) + } + + /** + * Build buffer with lines and highlights + */ + export class Highlighter { + constructor(srcId?: number) + /** + * Add a line with highlight group. + */ + addLine(line: string, hlGroup?: string): void + /** + * Add lines without highlights. + */ + addLines(lines: string[]): void + /** + * Add text with highlight. + */ + addText(text: string, hlGroup?: string): void + /** + * Get line count + */ + get length(): number + /** + * Render lines to buffer at specified range. + * Since notifications is used, use `nvim.pauseNotification` & `nvim.resumeNotification` + * when you need to wait for the request finish. + * + * @param {Buffer} buffer + * @param {number} start + * @param {number} end + * @returns {void} + */ + render(buffer: Buffer, start?: number, end?: number): void + } + + export interface ListConfiguration { + get(key: string, defaultValue?: T): T + previousKey(): string + nextKey(): string + dispose(): void + } + + export interface ListActionOptions { + /** + * No prompt stop and window switch when invoked. + */ + persist?: boolean + /** + * Reload list after action invoked. + */ + reload?: boolean + /** + * Support multiple items as execute argument. + */ + parallel?: boolean + /** + * Tab positioned list should be persisted (no window switch) on action invoke. + */ + tabPersist?: boolean + } + + export interface CommandTaskOption { + /** + * Command to run. + */ + cmd: string + /** + * Arguments of command. + */ + args: string[] + /** + * Current working directory. + */ + cwd?: string + env?: NodeJS.ProcessEnv + /** + * Runs for each line, return undefined for invalid item. + */ + onLine: (line: string) => ListItem | undefined + } + + export abstract class BasicList implements IList { + /** + * Unique name, must be provided by implementation class. + */ + name: string + /** + * Default action name invoked by by default, must be provided by implementation class. + */ + defaultAction: string + /** + * Registered actions. + */ + readonly actions: ListAction[] + /** + * Arguments configuration of list. + */ + options: ListArgument[] + protected nvim: Neovim + protected disposables: Disposable[] + protected config: ListConfiguration + constructor(nvim: Neovim) + /** + * Should align columns when true. + */ + get alignColumns(): boolean + get hlGroup(): string + get previewHeight(): string + get splitRight(): boolean + /** + * Parse argument string array for argument object from `this.options`. + * Could be used inside `this.loadItems()` + */ + protected parseArguments(args: string[]): { [key: string]: string | boolean } + /** + * Get configurations of current list + */ + protected getConfig(): WorkspaceConfiguration + /** + * Add an action + */ + protected addAction(name: string, fn: (item: ListItem, context: ListContext) => ProviderResult, options?: ListActionOptions): void + /** + * Add action that support multiple selection. + */ + protected addMultipleAction(name: string, fn: (item: ListItem[], context: ListContext) => ProviderResult, options?: ListActionOptions): void + /** + * Create task from command task option. + */ + protected createCommandTask(opt: CommandTaskOption): ListTask + /** + * Add location related actions, should be called in constructor. + */ + protected addLocationActions(): void + protected convertLocation(location: Location | LocationWithLine | string): Promise + /** + * Jump to location + * + * @method + */ + protected jumpTo(location: Location | LocationWithLine | string, command?: string): Promise + /** + * Preview location. + * + * @method + */ + protected previewLocation(location: Location, context: ListContext): Promise + /** + * Preview lines. + * + * @method + */ + protected preview(options: PreviewOptions, context: ListContext): Promise + /** + * Use for syntax highlights, invoked after buffer loaded. + */ + doHighlight(): void + /** + * Invoked for listItems or listTask, could throw error when failed to load. + */ + abstract loadItems(context: ListContext, token?: CancellationToken): Promise + } + + export class Mutex { + /** + * Returns true when task is running. + */ + get busy(): boolean + /** + * Resolved release function that must be called after task finish. + */ + acquire(): Promise<() => void> + /** + * Captrue the async task function that ensures to be executed one by one. + */ + use(f: () => Promise): Promise + } + // }} + + // functions {{ + + export interface AnsiItem { + foreground?: string + background?: string + bold?: boolean + italic?: boolean + underline?: boolean + text: string + } + + export interface ParsedUrlQueryInput { + [key: string]: unknown + } + + export interface FetchOptions { + /** + * Default to 'GET' + */ + method?: string + /** + * Default no timeout + */ + timeout?: number + /** + * Always return buffer instead of parsed response. + */ + buffer?: boolean + /** + * Data send to server. + */ + data?: string | { [key: string]: any } | Buffer + /** + * Plain object added as query of url + */ + query?: ParsedUrlQueryInput + headers?: any + /** + * User for http basic auth, should use with password + */ + user?: string + /** + * Password for http basic auth, should use with user + */ + password?: string + } + + export interface DownloadOptions extends Omit { + /** + * Folder that contains downloaded file or extracted files by untar or unzip + */ + dest: string + /** + * Remove the specified number of leading path elements for *untar* only, default to `1`. + */ + strip?: number + /** + * If true, use untar for `.tar.gz` filename + */ + extract?: boolean | 'untar' | 'unzip' + onProgress?: (percent: string) => void + } + + export type ResponseResult = string | Buffer | { + [name: string]: any + } + + /** + * Parse ansi result from string contains ansi characters. + */ + export function ansiparse(str: string): AnsiItem[] + + /** + * Send request to server for response, supports: + * + * - Send json data and parse json response. + * - Throw error for failed response statusCode. + * - Timeout support (no timeout by default). + * - Send buffer (as data) and receive data (as response). + * - Proxy support from user configuration & environment. + * - Redirect support, limited to 3. + * - Support of gzip & deflate response content. + * + * @return Parsed object if response content type is application/json, text if content type starts with `text/` + */ + export function fetch(url: string, options?: FetchOptions, token?: CancellationToken): Promise + + /** + * Download file from url, with optional untar/unzip support. + * + * Note: you may need to set `strip` to 0 when using untar as extract method. + * + * @param {string} url + * @param {DownloadOptions} options contains dest folder and optional onProgress callback + */ + export function download(url: string, options: DownloadOptions, token?: CancellationToken): Promise + + interface ExecOptions { + cwd?: string + env?: NodeJS.ProcessEnv + shell?: string + timeout?: number + maxBuffer?: number + killSignal?: string + uid?: number + gid?: number + windowsHide?: boolean + } + + /** + * Dispose all disposables. + */ + export function disposeAll(disposables: Disposable[]): void + + /** + * Concurrent run async functions with limit support. + */ + export function concurrent(arr: T[], fn: (val: T) => Promise, limit?: number): Promise + + /** + * Create promise resolved after ms milliseconds. + */ + export function wait(ms: number): Promise + + /** + * Run command with `child_process.exec` + */ + export function runCommand(cmd: string, opts?: ExecOptions, timeout?: number): Promise + + /** + * Check if process with pid is running + */ + export function isRunning(pid: number): boolean + + /** + * Check if command is executable. + */ + export function executable(command: string): boolean + + /** + * Watch single file for change, the filepath needs to be exists file. + * + * @param filepath Full path of file. + * @param onChange Handler on file change detected. + */ + export function watchFile(filepath: string, onChange: () => void): Disposable + // }} + + // commands module {{ + export interface CommandItem { + id: string + internal?: boolean + execute(...args: any[]): any + } + /** + * Namespace for dealing with commands of coc.nvim + */ + export namespace commands { + /** + * Registered commands. + */ + export const commandList: CommandItem[] + + /** + * Execute specified command. + * + * @deprecated use `executeCommand()` instead. + */ + export function execute(command: { name: string, arguments?: any[] }): void + + /** + * Check if command is registered. + * + * @param id Unique id of command. + */ + export function has(id: string): boolean + + /** + * Registers a command that can be invoked via a keyboard shortcut, + * a menu item, an action, or directly. + * + * Registering a command with an existing command identifier twice + * will cause an error. + * + * @param command A unique identifier for the command. + * @param impl A command handler function. + * @param thisArg The `this` context used when invoking the handler function. + * @return Disposable which unregisters this command on disposal. + */ + export function registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any, internal?: boolean): Disposable + + /** + * Executes the command denoted by the given command identifier. + * + * * *Note 1:* When executing an editor command not all types are allowed to + * be passed as arguments. Allowed are the primitive types `string`, `boolean`, + * `number`, `undefined`, and `null`, as well as [`Position`](#Position), [`Range`](#Range), [`URI`](#URI) and [`Location`](#Location). + * * *Note 2:* There are no restrictions when executing commands that have been contributed + * by extensions. + * + * @param command Identifier of the command to execute. + * @param rest Parameters passed to the command function. + * @return A promise that resolves to the returned value of the given command. `undefined` when + * the command handler function doesn't return anything. + */ + export function executeCommand(command: string, ...rest: any[]): Promise + + /** + * Open uri with external tool, use `open` on mac, use `xdg-open` on linux. + */ + export function executeCommand(command: 'vscode.open', uri: string | Uri): Promise + + /** + * Reload current buffer by `:edit` command. + */ + export function executeCommand(command: 'workbench.action.reloadWindow'): Promise + + /** + * Insert snippet at range of current buffer. + * + * @param edit Contains snippet text and range to replace. + */ + export function executeCommand(command: 'editor.action.insertSnippet', edit: TextEdit, ultisnip?: UltiSnippetOption): Promise + + /** + * Invoke specified code action. + */ + export function executeCommand(command: 'editor.action.doCodeAction', action: CodeAction): Promise + + /** + * Trigger coc.nvim's completion at current cursor position. + */ + export function executeCommand(command: 'editor.action.triggerSuggest'): Promise + + /** + * Trigger signature help at current cursor position. + */ + export function executeCommand(command: 'editor.action.triggerParameterHints'): Promise + + /** + * Add ranges to cursors session for multiple cursors. + */ + export function executeCommand(command: 'editor.action.addRanges', ranges: Range[]): Promise + + /** + * Restart coc.nvim service by `:CocRestart` command. + */ + export function executeCommand(command: 'editor.action.restart'): Promise + + /** + * Show locations by location list or vim's quickfix list. + */ + export function executeCommand(command: 'editor.action.showReferences', filepath: string | undefined, position: Position | undefined, locations: Location[]): Promise + + /** + * Invoke rename action at position of specified uri. + */ + export function executeCommand(command: 'editor.action.rename', uri: string, position: Position): Promise + + /** + * Run format action for current buffer. + */ + export function executeCommand(command: 'editor.action.format'): Promise + } + // }} + + // events module {{ + type EventResult = void | Promise + type MoveEvents = 'CursorMoved' | 'CursorMovedI' | 'CursorHold' | 'CursorHoldI' + type BufEvents = 'BufHidden' | 'BufEnter' | 'BufWritePost' + | 'InsertLeave' | 'TermOpen' | 'InsertEnter' + | 'BufCreate' | 'BufUnload' | 'BufWritePre' | 'Enter' + type EmptyEvents = 'FocusGained' | 'FocusLost' | 'InsertSnippet' + type InsertChangeEvents = 'TextChangedP' | 'TextChangedI' + type TaskEvents = 'TaskExit' | 'TaskStderr' | 'TaskStdout' + type WindowEvents = 'WinLeave' | 'WinEnter' + type AllEvents = BufEvents | EmptyEvents | MoveEvents | TaskEvents | WindowEvents | InsertChangeEvents | 'CompleteDone' | 'TextChanged' | 'MenuPopupChanged' | 'InsertCharPre' | 'FileType' | 'BufWinEnter' | 'BufWinLeave' | 'VimResized' | 'DirChanged' | 'OptionSet' | 'Command' | 'BufReadCmd' | 'GlobalChange' | 'InputChar' | 'WinLeave' | 'MenuInput' | 'PromptInsert' | 'FloatBtnClick' | 'InsertSnippet' | 'PromptKeyPress' + type OptionValue = string | number | boolean + type PromptWidowKeys = 'C-j' | 'C-k' | 'C-n' | 'C-p' | 'up' | 'down' + + export interface CursorPosition { + readonly bufnr: number + readonly lnum: number + readonly col: number + readonly insert: boolean + } + + export interface InsertChange { + /** + * 1 based line number + */ + readonly lnum: number + /** + * 1 based column number + */ + readonly col: number + /** + * Text before cursor. + */ + readonly pre: string + /** + * Insert character that cause change of this time. + */ + readonly insertChar: string | undefined + readonly changedtick: number + } + + export interface PopupChangeEvent { + readonly completed_item: VimCompleteItem + readonly height: number + readonly width: number + readonly row: number + readonly col: number + readonly size: number + readonly scrollbar: boolean + } + + /** + * Used for listen to events send from vim. + */ + export namespace events { + /** + * Latest cursor position. + */ + export const cursor: Readonly + /** + * Latest pum position, is true when pum positioned above current line. + */ + export const pumAlignTop: boolean + /** + * Insert mode detected by latest events. + */ + export const insertMode: boolean + + /** + * Popup menu is visible. + */ + export const pumvisible: boolean + + /** + * Wait for any of event in events to fire, resolve undefined when timeout or CancellationToken requested. + * @param events Event names to wait. + * @param timeoutOrToken Timeout in miniseconds or CancellationToken. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function race(events: AllEvents[], timeoutOrToken?: number | CancellationToken): Promise<{ name: AllEvents, args: unknown[] } | undefined> + + /** + * Attach handler to buffer events. + */ + export function on(event: BufEvents, handler: (bufnr: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Attach handler to mouse move events. + */ + export function on(event: MoveEvents, handler: (bufnr: number, cursor: [number, number]) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Attach handler to TextChangedI or TextChangedP. + */ + export function on(event: InsertChangeEvents, handler: (bufnr: number, info: InsertChange) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Attach handler to window event. + */ + export function on(event: WindowEvents, handler: (winid: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Attach handler to float button click. + */ + export function on(event: 'FloatBtnClick', handler: (bufnr: number, index: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Attach handler to keypress in prompt window. + * Key could only be 'C-j', 'C-k', 'C-n', 'C-p', 'up' and 'down' + */ + export function on(event: 'PromptKeyPress', handler: (bufnr: number, key: PromptWidowKeys) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Fired on vim's TextChanged event. + */ + export function on(event: 'TextChanged', handler: (bufnr: number, changedtick: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'TaskExit', handler: (id: string, code: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'TaskStderr' | 'TaskStdout', handler: (id: string, lines: string[]) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Fired on vim's BufReadCmd event. + */ + export function on(event: 'BufReadCmd', handler: (scheme: string, fullpath: string) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + /** + * Fired on vim's VimResized event. + */ + export function on(event: 'VimResized', handler: (columns: number, lines: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'MenuPopupChanged', handler: (event: PopupChangeEvent, cursorline: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'CompleteDone', handler: (item: VimCompleteItem) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'InsertCharPre', handler: (character: string) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'FileType', handler: (filetype: string, bufnr: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'BufWinEnter' | 'BufWinLeave', handler: (bufnr: number, winid: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'DirChanged', handler: (cwd: string) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'OptionSet' | 'GlobalChange', handler: (option: string, oldVal: OptionValue, newVal: OptionValue) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'InputChar', handler: (session: string, character: string, mode: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'PromptInsert', handler: (value: string, bufnr: number) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + export function on(event: 'Command', handler: (name: string) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + + /** + * Fired after user insert character and made change to the buffer. + * Fired after TextChangedI & TextChangedP event. + */ + export function on(event: 'TextInsert', handler: (bufnr: number, info: InsertChange, character: string) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + + export function on(event: EmptyEvents, handler: () => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + + export function on(event: AllEvents[], handler: (...args: unknown[]) => EventResult, thisArg?: any, disposables?: Disposable[]): Disposable + } + // }} + + // file events {{ + /** + * An event that is fired after files are created. + */ + export interface FileCreateEvent { + + /** + * The files that got created. + */ + readonly files: ReadonlyArray + } + + /** + * An event that is fired when files are going to be created. + * + * To make modifications to the workspace before the files are created, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillCreateEvent { + + /** + * A cancellation token. + */ + readonly token: CancellationToken + + /** + * The files that are going to be created. + */ + readonly files: ReadonlyArray + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void + } + + /** + * An event that is fired when files are going to be deleted. + * + * To make modifications to the workspace before the files are deleted, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillDeleteEvent { + + /** + * The files that are going to be deleted. + */ + readonly files: ReadonlyArray + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void + } + + /** + * An event that is fired after files are deleted. + */ + export interface FileDeleteEvent { + + /** + * The files that got deleted. + */ + readonly files: ReadonlyArray + } + + /** + * An event that is fired after files are renamed. + */ + export interface FileRenameEvent { + + /** + * The files that got renamed. + */ + readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }> + } + + /** + * An event that is fired when files are going to be renamed. + * + * To make modifications to the workspace before the files are renamed, + * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a + * thenable that resolves to a [workspace edit](#WorkspaceEdit). + */ + export interface FileWillRenameEvent { + + /** + * The files that are going to be renamed. + */ + readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }> + + /** + * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillCreateFiles(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that delays saving. + */ + waitUntil(thenable: Thenable): void + } + // }} + + // languages module {{ + export interface DocumentSymbolProviderMetadata { + /** + * A human-readable string that is shown when multiple outlines trees show for one document. + */ + label?: string + } + + export namespace languages { + /** + * Create a diagnostics collection. + * + * @param name The [name](#DiagnosticCollection.name) of the collection. + * @return A new diagnostic collection. + */ + export function createDiagnosticCollection(name?: string): DiagnosticCollection + + /** + * Register a formatting provider that works on type. The provider is active when the user enables the setting `coc.preferences.formatOnType`. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An on type formatting edit provider. + * @param triggerCharacters Trigger character that should trigger format on type. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerOnTypeFormattingEditProvider(selector: DocumentSelector, provider: OnTypeFormattingEditProvider, triggerCharacters: string[]): Disposable + + /** + * Register a completion provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and groups of equal score are sequentially asked for + * completion items. The process stops when one or many providers of a group return a + * result. A failing provider (rejected promise or exception) will not fail the whole + * operation. + * + * A completion item provider can be associated with a set of `triggerCharacters`. When trigger + * characters are being typed, completions are requested but only from providers that registered + * the typed character. Because of that trigger characters should be different than [word characters](#LanguageConfiguration.wordPattern), + * a common trigger character is `.` to trigger member completions. + * + * @param name Name of completion source. + * @param shortcut Shortcut used in completion menu. + * @param selector Document selector of created completion source. + * @param provider A completion provider. + * @param triggerCharacters Trigger completion when the user types one of the characters. + * @param priority Higher priority would shown first. + * @param allCommitCharacters Commit characters of completion source. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCompletionItemProvider(name: string, shortcut: string, selector: DocumentSelector | null, provider: CompletionItemProvider, triggerCharacters?: string[], priority?: number, allCommitCharacters?: string[]): Disposable + + /** + * Register a code action provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A code action provider. + * @param clientId Optional id of language client. + * @param codeActionKinds Optional supported code action kinds. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCodeActionProvider(selector: DocumentSelector, provider: CodeActionProvider, clientId: string | undefined, codeActionKinds?: string[]): Disposable + + /** + * Register a hover provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A hover provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable + + /** + * Register a selection range provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A selection range provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable + + /** + * Register a signature help provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and called sequentially until a provider returns a + * valid result. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A signature help provider. + * @param triggerCharacters Trigger signature help when the user types one of the characters, like `,` or `(`. + * @param metadata Information about the provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerSignatureHelpProvider(selector: DocumentSelector, provider: SignatureHelpProvider, triggerCharacters?: string[]): Disposable + + /** + * Register a document symbol provider. + * + * Multiple providers can be registered for a language. In that case providers only first provider + * are asked for result. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document symbol provider. + * @param metadata Optional meta data. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentSymbolProvider(selector: DocumentSelector, provider: DocumentSymbolProvider, metadata?: DocumentSymbolProviderMetadata): Disposable + + /** + * Register a folding range provider. + * + * Multiple providers can be registered for a language. In that case providers only first provider + * are asked for result. + * + * A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A folding range provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerFoldingRangeProvider(selector: DocumentSelector, provider: FoldingRangeProvider): Disposable + + /** + * Register a document highlight provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#languages.match) and groups sequentially asked for document highlights. + * The process stops when a provider returns a `non-falsy` or `non-failure` result. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document highlight provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentHighlightProvider(selector: DocumentSelector, provider: any): Disposable + + /** + * Register a code lens provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A code lens provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable + + /** + * Register a document link provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document link provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable + + /** + * Register a color provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A color provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable + + /** + * Register a definition provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A definition provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable + + /** + * Register a declaration provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A declaration provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDeclarationProvider(selector: DocumentSelector, provider: DeclarationProvider): Disposable + + + /** + * Register a type definition provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A type definition provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable + + /** + * Register an implementation provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An implementation provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerImplementationProvider(selector: DocumentSelector, provider: ImplementationProvider): Disposable + + /** + * Register a reference provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A reference provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerReferencesProvider(selector: DocumentSelector, provider: ReferenceProvider): Disposable + + /** + * Register a rename provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their [score](#workspace.match) and asked in sequence. The first provider producing a result + * defines the result of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A rename provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerRenameProvider(selector: DocumentSelector, provider: RenameProvider): Disposable + + /** + * Register a workspace symbol provider. + * + * Multiple providers can be registered. In that case providers are asked in parallel and + * the results are merged. A failing provider (rejected promise or exception) will not cause + * a failure of the whole operation. + * + * @param provider A workspace symbol provider. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerWorkspaceSymbolProvider(provider: WorkspaceSymbolProvider): Disposable + + /** + * Register a formatting provider for a document. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their priority. Failure of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document formatting edit provider. + * @param priority default to 0. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentFormatProvider(selector: DocumentSelector, provider: DocumentFormattingEditProvider, priority?: number): Disposable + + /** + * Register a formatting provider for a document range. + * + * *Note:* A document range provider is also a [document formatter](#DocumentFormattingEditProvider) + * which means there is no need to [register](#languages.registerDocumentFormattingEditProvider) a document + * formatter when also registering a range provider. + * + * Multiple providers can be registered for a language. In that case provider with highest priority is used. + * Failure of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document range formatting edit provider. + * @param priority default to 0. + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerDocumentRangeFormatProvider(selector: DocumentSelector, provider: DocumentRangeFormattingEditProvider, priority?: number): Disposable + + /** + * Register a call hierarchy provider. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A call hierarchy provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable + + /** + * Register a semantic tokens provider for a whole document. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their {@link languages.match score} and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document semantic tokens provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerDocumentSemanticTokensProvider(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend): Disposable + + /** + * Register a semantic tokens provider for a document range. + * + * *Note:* If a document has both a `DocumentSemanticTokensProvider` and a `DocumentRangeSemanticTokensProvider`, + * the range provider will be invoked only initially, for the time in which the full document provider takes + * to resolve the first request. Once the full document provider resolves the first request, the semantic tokens + * provided via the range provider will be discarded and from that point forward, only the document provider + * will be used. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their {@link languages.match score} and the best-matching provider is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A document range semantic tokens provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerDocumentRangeSemanticTokensProvider(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable + + /** + * Register a linked editing range provider. + * + * Multiple providers can be registered for a language. In that case providers are sorted + * by their {@link languages.match score} and the best-matching provider that has a result is used. Failure + * of the selected provider will cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider A linked editing range provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerLinkedEditingRangeProvider(selector: DocumentSelector, provider: LinkedEditingRangeProvider): Disposable + + /** + * Register a inlay hints provider. + * + * Multiple providers can be registered for a language. In that case providers are asked in + * parallel and the results are merged. A failing provider (rejected promise or exception) will + * not cause a failure of the whole operation. + * + * @param selector A selector that defines the documents this provider is applicable to. + * @param provider An inlay hints provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerInlayHintsProvider(selector: DocumentSelector, provider: InlayHintsProvider): Disposable + } + // }} + + // services module {{ + export enum ServiceStat { + Initial, + Starting, + StartFailed, + Running, + Stopping, + Stopped, + } + + export interface IServiceProvider { + // unique service id + id: string + name: string + client?: LanguageClient + selector: DocumentSelector + // current state + state: ServiceStat + start(): Promise + dispose(): void + stop(): Promise | void + restart(): Promise | void + onServiceReady: Event + } + + export namespace services { + /** + * Register languageClient as service provider. + */ + export function registLanguageClient(client: LanguageClient): Disposable + /** + * Register service, nothing happens when `service.id` already exists. + */ + export function regist(service: IServiceProvider): Disposable + /** + * Get service by id. + */ + export function getService(id: string): IServiceProvider + /** + * Stop service by id. + */ + export function stop(id: string): Promise + /** + * Stop running service or start stopped service. + */ + export function toggle(id: string): Promise + } + // }} + + // sources module {{ + /** + * Source options to create source that could respect configuration from `coc.source.{name}` + */ + export type SourceConfig = Omit + + export interface SourceStat { + name: string + priority: number + triggerCharacters: string[] + type: 'native' | 'remote' | 'service' + shortcut: string + filepath: string + disabled: boolean + filetypes: string[] + } + + export enum SourceType { + Native, + Remote, + Service, + } + + export interface CompleteResult { + items: VimCompleteItem[] + isIncomplete?: boolean + startcol?: number + source?: string + priority?: number + } + + // option on complete & should_complete + export interface CompleteOption { + /** + * Current buffer number. + */ + readonly bufnr: number + /** + * Current line. + */ + readonly line: string + /** + * Column to start completion, determined by iskeyword options of buffer. + */ + readonly col: number + /** + * Input text. + */ + readonly input: string + readonly filetype: string + readonly filepath: string + /** + * Word under cursor. + */ + readonly word: string + /** + * Trigger character, could be empty string. + */ + readonly triggerCharacter: string + /** + * Col of cursor, 1 based. + */ + readonly colnr: number + readonly linenr: number + readonly synname: string + /** + * Black list words specified by user. + */ + readonly blacklist: string[] + /** + * Buffer changetick + */ + readonly changedtick: number + /** + * Is trigger for in complete completion. + */ + readonly triggerForInComplete?: boolean + } + + export interface ISource { + /** + * Identifier name + */ + name: string + /** + * @deprecated use documentSelector instead. + */ + filetypes?: string[] + /** + * Filters of document. + */ + documentSelector?: DocumentSelector + enable?: boolean + shortcut?: string + priority?: number + sourceType?: SourceType + /** + * Should only be used when completion is triggered, requirs `triggerPatterns` or `triggerCharacters` defined. + */ + triggerOnly?: boolean + triggerCharacters?: string[] + // regex to detect trigger completion, ignored when triggerCharacters exists. + triggerPatterns?: RegExp[] + disableSyntaxes?: string[] + filepath?: string + // should the first character always match + firstMatch?: boolean + refresh?(): Promise + /** + * For disable/enable + */ + toggle?(): void + + /** + * Triggered on BufEnter, used for cache normally + */ + onEnter?(bufnr: number): void + + /** + * Check if this source should doComplete + * + * @public + * @param {CompleteOption} opt + * @returns {Promise } + */ + shouldComplete?(opt: CompleteOption): Promise + + /** + * Run completion + * + * @public + * @param {CompleteOption} opt + * @param {CancellationToken} token + * @returns {Promise} + */ + doComplete(opt: CompleteOption, token: CancellationToken): ProviderResult + + /** + * Action for complete item on complete item selected + * + * @public + * @param {VimCompleteItem} item + * @param {CancellationToken} token + * @returns {Promise} + */ + onCompleteResolve?(item: VimCompleteItem, token: CancellationToken): ProviderResult + + /** + * Action for complete item on complete done + * + * @public + * @param {VimCompleteItem} item + * @returns {Promise} + */ + onCompleteDone?(item: VimCompleteItem, opt: CompleteOption): ProviderResult + + shouldCommit?(item: VimCompleteItem, character: string): boolean + } + + export namespace sources { + /** + * Names of registered sources. + */ + export const names: ReadonlyArray + export const sources: ReadonlyArray + /** + * Check if source exists by name. + */ + export function has(name: string): boolean + /** + * Get source by name. + */ + export function getSource(name: string): ISource | null + + /** + * Add source to sources list. + * + * Note: Use `sources.createSource()` for regist new source is recommended for + * user configuration support. + */ + export function addSource(source: ISource): Disposable + + /** + * Create source by source config, configurations starts with `coc.source.{name}` + * are automatically supported. + * + * `name` and `doComplete()` must be provided in config. + */ + export function createSource(config: SourceConfig): Disposable + + /** + * Get list of all source stats. + */ + export function sourceStats(): SourceStat[] + + /** + * Call refresh for _name_ source or all sources. + */ + export function refresh(name?: string): Promise + + /** + * Toggle state of _name_ source. + */ + export function toggleSource(name: string): void + + /** + * Remove source by name. + */ + export function removeSource(name: string): void + } + // }} + + // TreeView related {{ + export interface TreeItemLabel { + label: string + highlights?: [number, number][] + } + + export interface TreeItemIcon { + text: string + hlGroup: string + } + + /** + * Collapsible state of the tree item + */ + export enum TreeItemCollapsibleState { + /** + * Determines an item can be neither collapsed nor expanded. Implies it has no children. + */ + None = 0, + /** + * Determines an item is collapsed + */ + Collapsed = 1, + /** + * Determines an item is expanded + */ + Expanded = 2 + } + + export class TreeItem { + /** + * A human-readable string describing this item. When `falsy`, it is derived from {@link TreeItem.resourceUri resourceUri}. + */ + label?: string | TreeItemLabel + + /** + * Description rendered less prominently after label. + */ + description?: string + + /** + * The icon path or {@link ThemeIcon} for the tree item. + * When `falsy`, {@link ThemeIcon.Folder Folder Theme Icon} is assigned, if item is collapsible otherwise {@link ThemeIcon.File File Theme Icon}. + * When a file or folder {@link ThemeIcon} is specified, icon is derived from the current file icon theme for the specified theme icon using {@link TreeItem.resourceUri resourceUri} (if provided). + */ + icon?: TreeItemIcon + + /** + * Optional id for the tree item that has to be unique across tree. The id is used to preserve the selection and expansion state of the tree item. + * + * If not provided, an id is generated using the tree item's resourceUri when exists. **Note** that when labels change, ids will change and that selection and expansion state cannot be kept stable anymore. + */ + id?: string + + /** + * The {@link Uri} of the resource representing this item. + * + * Will be used to derive the {@link TreeItem.label label}, when it is not provided. + * Will be used to derive the icon from current file icon theme, when {@link TreeItem.iconPath iconPath} has {@link ThemeIcon} value. + */ + resourceUri?: Uri + + /** + * The tooltip text when you hover over this item. + */ + tooltip?: string | MarkupContent + + /** + * The {@link Command} that should be executed when the tree item is selected. + * + * Please use `vscode.open` or `vscode.diff` as command IDs when the tree item is opening + * something in the editor. Using these commands ensures that the resulting editor will + * appear consistent with how other built-in trees open editors. + */ + command?: Command + + /** + * {@link TreeItemCollapsibleState} of the tree item. + */ + collapsibleState?: TreeItemCollapsibleState + + /** + * @param label A human-readable string describing this item + * @param collapsibleState {@link TreeItemCollapsibleState} of the tree item. Default is {@link TreeItemCollapsibleState.None} + */ + constructor(label: string | TreeItemLabel, collapsibleState?: TreeItemCollapsibleState) + + /** + * @param resourceUri The {@link Uri} of the resource representing this item. + * @param collapsibleState {@link TreeItemCollapsibleState} of the tree item. Default is {@link TreeItemCollapsibleState.None} + */ + constructor(resourceUri: Uri, collapsibleState?: TreeItemCollapsibleState) + } + + /** + * Action resolved by {@link TreeDataProvider} + */ + export interface TreeItemAction { + /** + * Label text in menu. + */ + title: string + handler: (item: T) => ProviderResult + } + + /** + * Options for creating a {@link TreeView} + */ + export interface TreeViewOptions { + /** + * bufhidden option for TreeView, default to 'wipe' + */ + bufhidden?: 'hide' | 'unload' | 'delete' | 'wipe' + /** + * Fixed width for window, default to true + */ + winfixwidth?: boolean + /** + * Enable filter feature, default to false + */ + enableFilter?: boolean + /** + * Disable indent of leaves without children, default to false + */ + disableLeafIndent?: boolean + /** + * A data provider that provides tree data. + */ + treeDataProvider: TreeDataProvider + /** + * Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree, + * the first argument to the command is the tree item that the command was executed on and the second argument is an + * array containing all selected tree items. + */ + canSelectMany?: boolean + } + + /** + * The event that is fired when an element in the {@link TreeView} is expanded or collapsed + */ + export interface TreeViewExpansionEvent { + + /** + * Element that is expanded or collapsed. + */ + readonly element: T + + } + + /** + * The event that is fired when there is a change in {@link TreeView.selection tree view's selection} + */ + export interface TreeViewSelectionChangeEvent { + + /** + * Selected elements. + */ + readonly selection: T[] + + } + + /** + * The event that is fired when there is a change in {@link TreeView.visible tree view's visibility} + */ + export interface TreeViewVisibilityChangeEvent { + + /** + * `true` if the {@link TreeView tree view} is visible otherwise `false`. + */ + readonly visible: boolean + + } + + /** + * Represents a Tree view + */ + export interface TreeView extends Disposable { + + /** + * Event that is fired when an element is expanded + */ + readonly onDidExpandElement: Event> + + /** + * Event that is fired when an element is collapsed + */ + readonly onDidCollapseElement: Event> + + /** + * Currently selected elements. + */ + readonly selection: T[] + + /** + * Event that is fired when the {@link TreeView.selection selection} has changed + */ + readonly onDidChangeSelection: Event> + + /** + * Event that is fired when {@link TreeView.visible visibility} has changed + */ + readonly onDidChangeVisibility: Event + + /** + * `true` if the {@link TreeView tree view} is visible otherwise `false`. + * + * **NOTE:** is `true` when TreeView visible on other tab. + */ + readonly visible: boolean + + /** + * Window id used by TreeView. + */ + readonly windowId: number | undefined + + /** + * An optional human-readable message that will be rendered in the view. + * Setting the message to null, undefined, or empty string will remove the message from the view. + */ + message?: string + + /** + * The tree view title is initially taken from viewId of TreeView + * Changes to the title property will be properly reflected in the UI in the title of the view. + */ + title?: string + + /** + * An optional human-readable description which is rendered less prominently in the title of the view. + * Setting the title description to null, undefined, or empty string will remove the description from the view. + */ + description?: string + + /** + * Reveals the given element in the tree view. + * If the tree view is not visible then the tree view is shown and element is revealed. + * + * By default revealed element is selected. + * In order to not to select, set the option `select` to `false`. + * In order to focus, set the option `focus` to `true`. + * In order to expand the revealed element, set the option `expand` to `true`. To expand recursively set `expand` to the number of levels to expand. + * **NOTE:** You can expand only to 3 levels maximum. + * + * **NOTE:** The {@link TreeDataProvider} that the `TreeView` {@link window.createTreeView is registered with} with must implement {@link TreeDataProvider.getParent getParent} method to access this API. + */ + reveal(element: T, options?: { select?: boolean, focus?: boolean, expand?: boolean | number }): Thenable + + /** + * Create tree view in new window. + * + * **NOTE:** TreeView with same viewId in current tab would be disposed. + * + * @param splitCommand The command to open TreeView window, default to 'belowright 30vs' + * @return `true` if window shown. + */ + show(splitCommand?: string): Promise + } + + /** + * A data provider that provides tree data + */ + export interface TreeDataProvider { + /** + * An optional event to signal that an element or root has changed. + * This will trigger the view to update the changed element/root and its children recursively (if shown). + * To signal that root has changed, do not pass any argument or pass `undefined` or `null`. + */ + onDidChangeTreeData?: Event + + /** + * Get {@link TreeItem} representation of the `element` + * + * @param element The element for which {@link TreeItem} representation is asked for. + * @return {@link TreeItem} representation of the element + */ + getTreeItem(element: T): TreeItem | Thenable + + /** + * Get the children of `element` or root if no element is passed. + * + * @param element The element from which the provider gets children. Can be `undefined`. + * @return Children of `element` or root if no element is passed. + */ + getChildren(element?: T): ProviderResult + + /** + * Optional method to return the parent of `element`. + * Return `null` or `undefined` if `element` is a child of root. + * + * **NOTE:** This method should be implemented in order to access {@link TreeView.reveal reveal} API. + * + * @param element The element for which the parent has to be returned. + * @return Parent of `element`. + */ + getParent?(element: T): ProviderResult + + /** + * Called on hover to resolve the {@link TreeItem.tooltip TreeItem} property if it is undefined. + * Called on tree item click/open to resolve the {@link TreeItem.command TreeItem} property if it is undefined. + * Only properties that were undefined can be resolved in `resolveTreeItem`. + * Functionality may be expanded later to include being called to resolve other missing + * properties on selection and/or on open. + * + * Will only ever be called once per TreeItem. + * + * onDidChangeTreeData should not be triggered from within resolveTreeItem. + * + * *Note* that this function is called when tree items are already showing in the UI. + * Because of that, no property that changes the presentation (label, description, etc.) + * can be changed. + * + * @param item Undefined properties of `item` should be set then `item` should be returned. + * @param element The object associated with the TreeItem. + * @param token A cancellation token. + * @return The resolved tree item or a thenable that resolves to such. It is OK to return the given + * `item`. When no result is returned, the given `item` will be used. + */ + resolveTreeItem?(item: TreeItem, element: T, token: CancellationToken): ProviderResult + + /** + * Called with current element to resolve actions. + * Called when user press 'actions' key. + * + * @param item Resolved item. + * @param element The object under cursor. + */ + resolveActions?(item: TreeItem, element: T): ProviderResult[]> + } + // }} + + // workspace module {{ + /** + * An event describing the change in Configuration + */ + export interface ConfigurationChangeEvent { + + /** + * Returns `true` if the given section for the given resource (if provided) is affected. + * + * @param section Configuration name, supports _dotted_ names. + * @param resource A resource URI. + * @return `true` if the given section for the given resource (if provided) is affected. + */ + affectsConfiguration(section: string, resource?: string): boolean + } + + export interface WillSaveEvent extends TextDocumentWillSaveEvent { + /** + * Allows to pause the event loop and to apply [pre-save-edits](#TextEdit). + * Edits of subsequent calls to this function will be applied in order. The + * edits will be *ignored* if concurrent modifications of the document happened. + * + * *Note:* This function can only be called during event dispatch and not + * in an asynchronous manner: + * + * ```ts + * workspace.onWillSaveTextDocument(event => { + * // async, will *throw* an error + * setTimeout(() => event.waitUntil(promise)); + * + * // sync, OK + * event.waitUntil(promise); + * }) + * ``` + * + * @param thenable A thenable that resolves to [pre-save-edits](#TextEdit). + */ + waitUntil(thenable: Thenable): void + } + + export interface KeymapOption { + /** + * Use request instead of notify, default true + */ + sync: boolean + /** + * Cancel completion before invoke callback, default true + */ + cancel: boolean + /** + * Use for keymap, default false + */ + silent: boolean + /** + * Enable repeat support for repeat.vim, default false + */ + repeat: boolean + } + + export interface DidChangeTextDocumentParams { + /** + * The document that did change. The version number points + * to the version after all provided content changes have + * been applied. + */ + readonly textDocument: { + version: number + uri: string + } + /** + * The actual content changes. The content changes describe single state changes + * to the document. So if there are two content changes c1 (at array index 0) and + * c2 (at array index 1) for a document in state S then c1 moves the document from + * S to S' and c2 from S' to S''. So c1 is computed on the state S and c2 is computed + * on the state S'. + */ + readonly contentChanges: ReadonlyArray + /** + * Buffer number of document. + */ + readonly bufnr: number + /** + * Original content before change + */ + readonly original: string + /** + * Original lines before change + */ + readonly originalLines: ReadonlyArray + } + + export interface EditerState { + document: LinesTextDocument + position: Position + } + + export type MapMode = 'n' | 'i' | 'v' | 'x' | 's' | 'o' + + export interface Autocmd { + /** + * Vim event or event set. + */ + event: string | string[] + /** + * Callback functions that called with evaled arguments. + */ + callback: Function + /** + * Match pattern, default to `*`. + */ + pattern?: string + /** + * Vim expression that eval to arguments of callback, default to `[]` + */ + arglist?: string[] + /** + * Use request when `true`, use notification by default. + */ + request?: boolean + /** + * `this` of callback. + */ + thisArg?: any + } + + export interface Env { + /** + * |completeopt| option of (neo)vim. + */ + readonly completeOpt: string + /** + * |runtimepath| option of (neo)vim. + */ + readonly runtimepath: string + /** + * |guicursor| option of (neo)vim + */ + readonly guicursor: string + /** + * Could use float window on neovim, always false on vim. + */ + readonly floating: boolean + /** + * |sign_place()| and |sign_unplace()| can be used when true. + */ + readonly sign: boolean + /** + * Root directory of extensions. + */ + readonly extensionRoot: string + /** + * Process id of (neo)vim. + */ + readonly pid: number + /** + * Total columns of screen. + */ + readonly columns: number + /** + * Total lines of screen. + */ + readonly lines: number + /** + * Is true when |CompleteChanged| event is supported. + */ + readonly pumevent: boolean + /** + * |cmdheight| option of (neo)vim. + */ + readonly cmdheight: number + /** + * Value of |g:coc_filetype_map| + */ + readonly filetypeMap: { [index: string]: string } + /** + * Is true when not using neovim. + */ + readonly isVim: boolean + /** + * Is cygvim when true. + */ + readonly isCygwin: boolean + /** + * Is macvim when true. + */ + readonly isMacvim: boolean + /** + * Is true when iTerm.app is used on mac. + */ + readonly isiTerm: boolean + /** + * version of (neo)vim, on vim it's like: 8020750, on neoivm it's like: 0.5.0 + */ + readonly version: string + /** + * |v:progpath| value, could be empty. + */ + readonly progpath: string + /** + * Is true when dialog feature is supported, which need vim >= 8.2.750 or neovim >= 0.4.0 + */ + readonly dialog: boolean + /** + * Is true when vim's textprop is supported. + */ + readonly textprop: boolean + } + + /** + * Store & retrieve most recent used items. + */ + export interface Mru { + /** + * Load iems from mru file + */ + + load(): Promise + /** + * Add item to mru file. + */ + add(item: string): Promise + + /** + * Remove item from mru file. + */ + + remove(item: string): Promise + + /** + * Remove the data file. + */ + clean(): Promise + } + + /** + * Option to create task that runs in (neo)vim. + */ + export interface TaskOptions { + /** + * The command to run, without arguments + */ + cmd: string + /** + * Arguments of command. + */ + args?: string[] + /** + * Current working directory of the task, Default to current vim's cwd. + */ + cwd?: string + /** + * Additional environment key-value pairs. + */ + env?: { [key: string]: string } + /** + * Use pty when true. + */ + pty?: boolean + /** + * Detach child process when true. + */ + detach?: boolean + } + + /** + * Controls long running task started by (neo)vim. + * Useful to keep the task running after CocRestart. + */ + export interface Task extends Disposable { + /** + * Fired on task exit with exit code. + */ + onExit: Event + /** + * Fired with lines on stdout received. + */ + onStdout: Event + /** + * Fired with lines on stderr received. + */ + onStderr: Event + /** + * Start task, task will be restarted when already running. + * + * @param {TaskOptions} opts + * @returns {Promise} + */ + start(opts: TaskOptions): Promise + /** + * Stop task by SIGTERM or SIGKILL + */ + stop(): Promise + /** + * Check if the task is running. + */ + running: Promise + } + + /** + * A simple json database. + */ + export interface JsonDB { + filepath: string + /** + * Get data by key. + * + * @param {string} key unique key allows dot notation. + * @returns {any} + */ + fetch(key: string): any + /** + * Check if key exists + * + * @param {string} key unique key allows dot notation. + */ + exists(key: string): boolean + /** + * Delete data by key + * + * @param {string} key unique key allows dot notation. + */ + delete(key: string): void + /** + * Save data with key + */ + push(key: string, data: number | null | boolean | string | { [index: string]: any }): void + /** + * Empty db file. + */ + clear(): void + /** + * Remove db file. + */ + destroy(): void + } + + export interface RenameEvent { + oldUri: Uri + newUri: Uri + } + + export interface FileSystemWatcher { + readonly ignoreCreateEvents: boolean + readonly ignoreChangeEvents: boolean + readonly ignoreDeleteEvents: boolean + readonly onDidCreate: Event + readonly onDidChange: Event + readonly onDidDelete: Event + readonly onDidRename: Event + dispose(): void + } + + export interface ConfigurationInspect { + key: string + defaultValue?: T + globalValue?: T + workspaceValue?: T + } + + export interface WorkspaceConfiguration { + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @return The value `section` denotes or `undefined`. + */ + get(section: string): T | undefined + + /** + * Return a value from this configuration. + * + * @param section Configuration name, supports _dotted_ names. + * @param defaultValue A value should be returned when no value could be found, is `undefined`. + * @return The value `section` denotes or the default. + */ + get(section: string, defaultValue: T): T + + /** + * Check if this configuration has a certain value. + * + * @param section Configuration name, supports _dotted_ names. + * @return `true` if the section doesn't resolve to `undefined`. + */ + has(section: string): boolean + + /** + * Retrieve all information about a configuration setting. A configuration value + * often consists of a *default* value, a global or installation-wide value, + * a workspace-specific value + * + * *Note:* The configuration name must denote a leaf in the configuration tree + * (`editor.fontSize` vs `editor`) otherwise no result is returned. + * + * @param section Configuration name, supports _dotted_ names. + * @return Information about a configuration setting or `undefined`. + */ + inspect(section: string): ConfigurationInspect | undefined + /** + * Update a configuration value. The updated configuration values are persisted. + * + * + * @param section Configuration name, supports _dotted_ names. + * @param value The new value. + * @param isUser if true, always update user configuration + */ + update(section: string, value: any, isUser?: boolean): void + + /** + * Readable dictionary that backs this configuration. + */ + readonly [key: string]: any + } + + export interface BufferSyncItem { + /** + * Called on buffer unload. + */ + dispose: () => void + /** + * Called on buffer content change. + */ + onChange?(e: DidChangeTextDocumentParams): void + /** + * Called on TextChangedI & TextChanged events. + */ + onTextChange?(): void + } + + export interface BufferSync { + /** + * Current items. + */ + readonly items: Iterable + /** + * Get created item by uri + */ + getItem(uri: string): T | undefined + /** + * Get created item by bufnr + */ + getItem(bufnr: number): T | undefined + dispose: () => void + } + + export namespace workspace { + export const nvim: Neovim + /** + * Current buffer number, could be wrong since vim could not send autocmd as expected. + * + * @deprecated will be removed in the feature. + */ + export const bufnr: number + /** + * Current document. + */ + export const document: Promise + /** + * Environments or current (neo)vim. + */ + export const env: Env + /** + * Float window or popup can work. + */ + export const floatSupported: boolean + /** + * Current working directory of vim. + */ + export const cwd: string + /** + * Current workspace root. + */ + export const root: string + /** + * @deprecated aliased to root. + */ + export const rootPath: string + /** + * Not neovim when true. + */ + export const isVim: boolean + /** + * Is neovim when true. + */ + export const isNvim: boolean + /** + * All filetypes of loaded documents. + */ + export const filetypes: ReadonlySet + /** + * All languageIds of loaded documents. + */ + export const languageIds: ReadonlySet + /** + * Root directory of coc.nvim + */ + export const pluginRoot: string + /** + * Current `&completeopt` of vim, may not correct. + */ + export const completeOpt: string + /** + * Exists channel names. + */ + export const channelNames: ReadonlyArray + /** + * Loaded documents that attached. + */ + export const documents: ReadonlyArray + /** + * Current document array. + */ + export const textDocuments: ReadonlyArray + /** + * Current workspace folders. + */ + export const workspaceFolders: ReadonlyArray + /** + * Directory paths of workspaceFolders. + */ + export const folderPaths: ReadonlyArray + /** + * Current workspace folder, could be null when vim started from user's home. + * + * @deprecated + */ + export const workspaceFolder: WorkspaceFolder | null + export const onDidCreateFiles: Event + export const onDidRenameFiles: Event + export const onDidDeleteFiles: Event + export const onWillCreateFiles: Event + export const onWillRenameFiles: Event + export const onWillDeleteFiles: Event + /** + * Event fired on workspace folder change. + */ + export const onDidChangeWorkspaceFolders: Event + /** + * Event fired after document create. + */ + export const onDidOpenTextDocument: Event + /** + * Event fired after document unload. + */ + export const onDidCloseTextDocument: Event + /** + * Event fired on document change. + */ + export const onDidChangeTextDocument: Event + /** + * Event fired before document save. + */ + export const onWillSaveTextDocument: Event + /** + * Event fired after document save. + */ + export const onDidSaveTextDocument: Event + + /** + * Event fired on configuration change. Configuration change could by many + * reasons, including: + * + * - Changes detected from `coc-settings.json`. + * - Change to document that using another configuration file. + * - Configuration change by call update API of WorkspaceConfiguration. + */ + export const onDidChangeConfiguration: Event + + /** + * Fired when vim's runtimepath change detected. + */ + export const onDidRuntimePathChange: Event> + + /** + * Returns a path that is relative to the workspace folder or folders. + * + * When there are no {@link workspace.workspaceFolders workspace folders} or when the path + * is not contained in them, the input is returned. + * + * @param pathOrUri A path or uri. When a uri is given its {@link Uri.fsPath fsPath} is used. + * @param includeWorkspaceFolder When `true` and when the given path is contained inside a + * workspace folder the name of the workspace is prepended. Defaults to `true` when there are + * multiple workspace folders and `false` otherwise. + * @return A path relative to the root or the input. + */ + export function asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string + + /** + * Opens a document. Will return early if this document is already open. Otherwise + * the document is loaded and the {@link workspace.onDidOpenTextDocument didOpen}-event fires. + * + * The document is denoted by an {@link Uri}. Depending on the {@link Uri.scheme scheme} the + * following rules apply: + * * `file`-scheme: Open a file on disk (`openTextDocument(Uri.file(path))`). Will be rejected if the file + * does not exist or cannot be loaded. + * * `untitled`-scheme: Open a blank untitled file with associated path (`openTextDocument(Uri.file(path).with({ scheme: 'untitled' }))`). + * The language will be derived from the file name. + * * For all other schemes contributed {@link TextDocumentContentProvider text document content providers} and + * {@link FileSystemProvider file system providers} are consulted. + * + * *Note* that the lifecycle of the returned document is owned by the editor and not by the extension. That means an + * {@linkcode workspace.onDidCloseTextDocument onDidClose}-event can occur at any time after opening it. + * + * @param uri Identifies the resource to open. + * @return A promise that resolves to a {@link Document document}. + */ + export function openTextDocument(uri: Uri): Thenable + + /** + * A short-hand for `openTextDocument(Uri.file(fileName))`. + * + * @see {@link openTextDocument} + * @param fileName A name of a file on disk. + * @return A promise that resolves to a {@link Document document}. + */ + export function openTextDocument(fileName: string): Thenable + + /** + * Create new namespace id by name. + * + * @deprecated Latest neovim requires namespace created by neoivm. + */ + export function createNameSpace(name: string): number + + /** + * Like vim's has(), but for version check only. + * Check patch on neovim and check nvim on vim would return false. + * + * For example: + * - has('nvim-0.6.0') + * - has('patch-7.4.248') + */ + export function has(feature: string): boolean + + /** + * Register autocmd on vim. + * + * Note: avoid request autocmd when possible since vim could be blocked + * forever when request triggered during request. + */ + export function registerAutocmd(autocmd: Autocmd): Disposable + + /** + * Watch for vim's global option change. + */ + export function watchOption(key: string, callback: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void + + /** + * Watch for vim's global variable change, works on neovim only. + */ + export function watchGlobal(key: string, callback?: (oldValue: any, newValue: any) => Thenable | void, disposables?: Disposable[]): void + + /** + * Check if selector match document. + */ + export function match(selector: DocumentSelector, document: LinesTextDocument): number + + /** + * Findup from filename or filenames from current filepath or root. + * + * @return fullpath of file or null when not found. + */ + export function findUp(filename: string | string[]): Promise + + /** + * Get possible watchman binary path. + */ + export function getWatchmanPath(): string | null + + /** + * Get configuration by section and optional resource uri. + */ + export function getConfiguration(section?: string, resource?: string): WorkspaceConfiguration + + /** + * Get created document by uri or bufnr. + */ + export function getDocument(uri: number | string): Document + + /** + * Apply WorkspaceEdit. + */ + export function applyEdit(edit: WorkspaceEdit): Promise + + /** + * Convert location to quickfix item. + */ + export function getQuickfixItem(loc: Location | LocationLink, text?: string, type?: string, module?: string): Promise + + /** + * Convert locations to quickfix list. + */ + export function getQuickfixList(locations: Location[]): Promise> + + /** + * Populate locations to UI. + */ + export function showLocations(locations: Location[]): Promise + + /** + * Get content of line by uri and line. + */ + export function getLine(uri: string, line: number): Promise + + /** + * Get WorkspaceFolder of uri + */ + export function getWorkspaceFolder(uri: string): WorkspaceFolder | undefined + + /** + * Get content from buffer or file by uri. + */ + export function readFile(uri: string): Promise + + /** + * Get current document and position. + */ + export function getCurrentState(): Promise + + /** + * Get format options of uri or current buffer. + */ + export function getFormatOptions(uri?: string): Promise + + /** + * Jump to location. + */ + export function jumpTo(uri: string, position?: Position | null, openCommand?: string): Promise + + /** + * Create a file in vim and disk + */ + export function createFile(filepath: string, opts?: CreateFileOptions): Promise + + /** + * Load uri as document, buffer would be invisible if not loaded. + */ + export function loadFile(uri: string): Promise + + /** + * Load the files that not loaded + */ + export function loadFiles(uris: string[]): Promise + + /** + * Rename file in vim and disk + */ + export function renameFile(oldPath: string, newPath: string, opts?: RenameFileOptions): Promise + + /** + * Delete file from vim and disk. + */ + export function deleteFile(filepath: string, opts?: DeleteFileOptions): Promise + + /** + * Open resource by uri + */ + export function openResource(uri: string): Promise + + /** + * Resolve full path of module from yarn or npm global directory. + */ + export function resolveModule(name: string): Promise + + /** + * Run nodejs command + */ + export function runCommand(cmd: string, cwd?: string, timeout?: number): Promise + + /** + * Expand filepath with `~` and/or environment placeholders + */ + export function expand(filepath: string): string + + /** + * Call a function by use notifications, useful for functions like |input| that could block vim. + */ + export function callAsync(method: string, args: any[]): Promise + + /** + * registerTextDocumentContentProvider + */ + export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable + + /** + * Register unique keymap uses `(coc-{key})` as lhs + * Throw error when {key} already exists. + * + * @param {MapMode[]} modes - array of 'n' | 'i' | 'v' | 'x' | 's' | 'o' + * @param {string} key - unique name + * @param {Function} fn - callback function + * @param {Partial} opts + * @returns {Disposable} + */ + export function registerKeymap(modes: MapMode[], key: string, fn: () => ProviderResult, opts?: Partial): Disposable + + /** + * Register expr key-mapping. + */ + export function registerExprKeymap(mode: 'i' | 'n' | 'v' | 's' | 'x', key: string, fn: () => ProviderResult, buffer?: boolean): Disposable + + /** + * Register local key-mapping. + */ + export function registerLocalKeymap(mode: 'n' | 'v' | 's' | 'x', key: string, fn: () => ProviderResult, notify?: boolean): Disposable + + /** + * Register for buffer sync objects, created item should be disposable + * and provide optional `onChange` which called when document change. + * + * The document is always attached and not command line buffer. + * + * @param create Called for each attached document and on document create. + * @returns Disposable + */ + export function registerBufferSync(create: (doc: Document) => T | undefined): BufferSync + + /** + * Create a FileSystemWatcher instance, when watchman doesn't exist, the + * returned FileSystemWatcher can still be used, but not work at all. + */ + export function createFileSystemWatcher(globPattern: string, ignoreCreate?: boolean, ignoreChange?: boolean, ignoreDelete?: boolean): FileSystemWatcher + /** + * Find files across all {@link workspace.workspaceFolders workspace folders} in the workspace. + * + * @example + * findFiles('**​/*.js', '**​/node_modules/**', 10) + * + * @param include A {@link GlobPattern glob pattern} that defines the files to search for. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. + * Use a {@link RelativePattern relative pattern} to restrict the search results to a {@link WorkspaceFolder workspace folder}. + * @param exclude A {@link GlobPattern glob pattern} that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` or`null`, + * no excludes will apply. + * @param maxResults An upper-bound for the result. + * @param token A token that can be used to signal cancellation to the underlying search engine. + * @return A thenable that resolves to an array of resource identifiers. Will return no results if no + * {@link workspace.workspaceFolders workspace folders} are opened. + */ + export function findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Thenable + + /** + * Create persistence Mru instance. + */ + export function createMru(name: string): Mru + + /** + * Create Task instance that runs in (neo)vim, no shell. + * + * @param id Unique id string, like `TSC` + */ + export function createTask(id: string): Task + + /** + * Create DB instance at extension root. + */ + export function createDatabase(name: string): JsonDB + } + // }} + + // window module {{ + /** + * Represents how a terminal exited. + */ + export interface TerminalExitStatus { + /** + * The exit code that a terminal exited with, it can have the following values: + * - Zero: the terminal process or custom execution succeeded. + * - Non-zero: the terminal process or custom execution failed. + * - `undefined`: the user forcibly closed the terminal or a custom execution exited + * without providing an exit code. + */ + readonly code: number | undefined + } + + export interface TerminalOptions { + /** + * A human-readable string which will be used to represent the terminal in the UI. + */ + name?: string + + /** + * A path to a custom shell executable to be used in the terminal. + */ + shellPath?: string + + /** + * Args for the custom shell executable, this does not work on Windows (see #8429) + */ + shellArgs?: string[] + + /** + * A path or URI for the current working directory to be used for the terminal. + */ + cwd?: string + + /** + * Object with environment variables that will be added to the VS Code process. + */ + env?: { [key: string]: string | null } + + /** + * Whether the terminal process environment should be exactly as provided in + * `TerminalOptions.env`. When this is false (default), the environment will be based on the + * window's environment and also apply configured platform settings like + * `terminal.integrated.windows.env` on top. When this is true, the complete environment + * must be provided as nothing will be inherited from the process or any configuration. + * Neovim only. + */ + strictEnv?: boolean + } + + /** + * An individual terminal instance within the integrated terminal. + */ + export interface Terminal { + + /** + * The bufnr of terminal buffer. + */ + readonly bufnr: number + + /** + * The name of the terminal. + */ + readonly name: string + + /** + * The process ID of the shell process. + */ + readonly processId: Promise + + /** + * The exit status of the terminal, this will be undefined while the terminal is active. + * + * **Example:** Show a notification with the exit code when the terminal exits with a + * non-zero exit code. + * ```typescript + * window.onDidCloseTerminal(t => { + * if (t.exitStatus && t.exitStatus.code) { + * vscode.window.showInformationMessage(`Exit code: ${t.exitStatus.code}`); + * } + * }); + * ``` + */ + readonly exitStatus: TerminalExitStatus | undefined + + /** + * Send text to the terminal. The text is written to the stdin of the underlying pty process + * (shell) of the terminal. + * + * @param text The text to send. + * @param addNewLine Whether to add a new line to the text being sent, this is normally + * required to run a command in the terminal. The character(s) added are \n or \r\n + * depending on the platform. This defaults to `true`. + */ + sendText(text: string, addNewLine?: boolean): void + + /** + * Show the terminal panel and reveal this terminal in the UI, return false when failed. + * + * @param preserveFocus When `true` the terminal will not take focus. + */ + show(preserveFocus?: boolean): Promise + + /** + * Hide the terminal panel if this terminal is currently showing. + */ + hide(): void + + /** + * Dispose and free associated resources. + */ + dispose(): void + } + + /** + * Option for create status item. + */ + export interface StatusItemOption { + progress?: boolean + } + + /** + * Status item that included in `g:coc_status` + */ + export interface StatusBarItem { + /** + * The priority of this item. Higher value means the item should + * be shown more to the left. + */ + readonly priority: number + + isProgress: boolean + + /** + * The text to show for the entry. You can embed icons in the text by leveraging the syntax: + * + * `My text $(icon-name) contains icons like $(icon-name) this one.` + * + * Where the icon-name is taken from the [octicon](https://octicons.github.com) icon set, e.g. + * `light-bulb`, `thumbsup`, `zap` etc. + */ + text: string + + /** + * Shows the entry in the status bar. + */ + show(): void + + /** + * Hide the entry in the status bar. + */ + hide(): void + + /** + * Dispose and free associated resources. Call + * [hide](#StatusBarItem.hide). + */ + dispose(): void + } + + /** + * Value-object describing where and how progress should show. + */ + export interface ProgressOptions { + + /** + * A human-readable string which will be used to describe the + * operation. + */ + title?: string + + /** + * Controls if a cancel button should show to allow the user to + * cancel the long running operation. + */ + cancellable?: boolean + } + + /** + * Defines a generalized way of reporting progress updates. + */ + export interface Progress { + + /** + * Report a progress update. + * + * @param value A progress item, like a message and/or an + * report on how much work finished + */ + report(value: T): void + } + + /** + * Represents an action that is shown with an information, warning, or + * error message. + * + * @see [showInformationMessage](#window.showInformationMessage) + * @see [showWarningMessage](#window.showWarningMessage) + * @see [showErrorMessage](#window.showErrorMessage) + */ + export interface MessageItem { + + /** + * A short title like 'Retry', 'Open Log' etc. + */ + title: string + + /** + * A hint for modal dialogs that the item should be triggered + * when the user cancels the dialog (e.g. by pressing the ESC + * key). + * + * Note: this option is ignored for non-modal messages. + * Note: not used by coc.nvim for now. + */ + isCloseAffordance?: boolean + } + + export interface DialogButton { + /** + * Use by callback, should >= 0 + */ + index: number + text: string + /** + * Not shown when true + */ + disabled?: boolean + } + + export interface DialogConfig { + /** + * Content shown in window. + */ + content: string + /** + * Optional title text. + */ + title?: string + /** + * show close button, default to true when not specified. + */ + close?: boolean + /** + * highlight group for dialog window, default to `"dialog.floatHighlight"` or 'CocFlating' + */ + highlight?: string + /** + * highlight items of content. + */ + highlights?: ReadonlyArray + /** + * highlight groups for border, default to `"dialog.borderhighlight"` or 'CocFlating' + */ + borderhighlight?: string + /** + * Buttons as bottom of dialog. + */ + buttons?: DialogButton[] + /** + * index is -1 for window close without button click + */ + callback?: (index: number) => void + } + + export type NotificationKind = 'error' | 'info' | 'warning' | 'progress' + + export interface NotificationConfig { + kind?: NotificationKind + + content?: string + /** + * Optional title text. + */ + title?: string + /** + * Buttons as bottom of dialog. + */ + buttons?: DialogButton[] + /** + * index is -1 for window close without button click + */ + callback?: (index: number) => void + } + + /** + * Options to configure the behavior of the quick pick UI. + */ + export interface QuickPickOptions { + + /** + * An optional string that represents the title of the quick pick. + */ + title?: string + + /** + * An optional flag to include the description when filtering the picks. + */ + matchOnDescription?: boolean + + /** + * An optional flag to make the picker accept multiple selections, if true the result is an array of picks. + */ + canPickMany?: boolean + } + + /** + * Represents an item that can be selected from + * a list of items. + */ + export interface QuickPickItem { + /** + * A human-readable string which is rendered prominent + */ + label: string + /** + * A human-readable string which is rendered less prominent in the same line + */ + description?: string + /** + * Optional flag indicating if this item is picked initially. + */ + picked?: boolean + } + + export interface QuickPickConfig { + /** + * An optional title. + */ + title?: string + /** + * Items to pick from. + */ + items: readonly T[] + /** + * Initial value of the filter text. + */ + value?: string + /** + * If multiple items can be selected at the same time. Defaults to false. + */ + canSelectMany?: boolean + /** + * Max height of list window. + */ + maxHeight?: number + } + + export interface QuickPick { + /** + * An optional title. + */ + title: string | undefined + /** + * If the UI should show a progress indicator. Defaults to false. + * + * Change this to true, e.g., while loading more data or validating + * user input. + */ + loading: boolean + /** + * Items to pick from. This can be read and updated by the extension. + */ + items: readonly T[] + /** + * Active items. This can be read and updated by the extension. + */ + activeItems: readonly T[] + /** + * If the filter text should also be matched against the description of the items. Defaults to false. + */ + matchOnDescription: boolean + /** + * Current input value + */ + readonly value: string + /** + * An event signaling when QuickPick closed, fired with selected items or null when canceled. + */ + readonly onDidFinish: Event + /** + * An event signaling when the value of the filter text has changed. + */ + readonly onDidChangeValue: Event + /** + * An event signaling when the selected items have changed. + */ + readonly onDidChangeSelection: Event + } + + export interface ScreenPosition { + row: number + col: number + } + + export type MsgTypes = 'error' | 'warning' | 'more' + + export interface OpenTerminalOption { + /** + * Cwd of terminal, default to result of |getcwd()| + */ + cwd?: string + /** + * Close terminal on job finish, default to true. + */ + autoclose?: boolean + /** + * Keep focus current window, default to false. + */ + keepfocus?: boolean + /** + * Position of terminal window, default to 'right'. + */ + position?: 'bottom' | 'right' + } + + /** + * An output channel is a container for readonly textual information. + * + * To get an instance of an `OutputChannel` use + * [createOutputChannel](#window.createOutputChannel). + */ + export interface OutputChannel { + + /** + * The human-readable name of this output channel. + */ + readonly name: string + + readonly content: string + /** + * Append the given value to the channel. + * + * @param value A string, falsy values will not be printed. + */ + append(value: string): void + + /** + * Append the given value and a line feed character + * to the channel. + * + * @param value A string, falsy values will be printed. + */ + appendLine(value: string): void + + /** + * Removes output from the channel. Latest `keep` lines will be remained. + */ + clear(keep?: number): void + + /** + * Reveal this channel in the UI. + * + * @param preserveFocus When `true` the channel will not take focus. + */ + show(preserveFocus?: boolean): void + + /** + * Hide this channel from the UI. + */ + hide(): void + + /** + * Dispose and free associated resources. + */ + dispose(): void + } + + export interface TerminalResult { + bufnr: number + success: boolean + content?: string + } + + export interface Dialog { + /** + * Buffer number of dialog. + */ + bufnr: number + /** + * Window id of dialog. + */ + winid: Promise + dispose: () => void + } + + export type HighlightItemDef = [string, number, number, number, number?, number?, number?] + + export interface HighlightDiff { + remove: number[] + removeMarkers: number[] + add: HighlightItemDef[] + } + + export interface MenuItem { + text: string + disabled?: boolean | { reason: string } + } + + export interface MenuOption { + /** + * Title in menu window. + */ + title?: string, + /** + * Content in menu window as normal text. + */ + content?: string + /** + * Create and highlight shortcut characters. + */ + shortcuts?: boolean + /** + * Position of menu, default to 'cursor' + */ + position?: 'center' | 'cursor' + } + + export interface InputOptions { + /** + * Position to show input, default to 'cursor' + */ + position?: 'cursor' | 'center' + /** + * Margin top editor when position is 'center' + */ + marginTop?: number + /** + * Border highlight of float window/popup, configuration `dialog.borderhighlight` used as default. + */ + borderhighlight?: string + /** + * Create key-mappings for quickpick list. + */ + list?: boolean + } + + export interface InputPreference extends InputOptions { + /** + * Top, right, bottom, left border existence, default to [1,1,1,1] + */ + border?: [0 | 1, 0 | 1, 0 | 1, 0 | 1] + /** + * Rounded border, default to true, configuration `dialog.rounded` used as default. + */ + rounded?: boolean + /** + * Minimal window width, `g:coc_prompt_win_width` or 32 used as default. + */ + minWidth?: number + /** + * Maximum window width, configuration `dialog.maxWidth` used as default. + */ + maxWidth?: number + } + + export interface InputDimension { + readonly width: number + readonly height: number + /** + * 0 based screen row + */ + readonly row: number + /** + * O based screen col + */ + readonly col: number + } + + export interface InputBox { + /** + * Change or get title of input box. + */ + title: string + /** + * Change or get loading state of input box. + */ + loading: boolean + /** + * Change or get borderhighlight of input box. + */ + borderhighlight: string + /** + * Dimension of float window/popup + */ + readonly dimension: InputDimension + /** + * Buffer number of float window/popup + */ + readonly bufnr: number + /** + * An event signaling when the value has changed. + */ + readonly onDidChange: Event + /** + * An event signaling input finished, emit input value or null when canceled. + */ + readonly onDidFinish: Event + } + + export namespace window { + /** + * The currently active editor or `undefined`. The active editor is the one + * that currently has focus or, when none has focus, the one that has changed + * input most recently. + */ + export const activeTextEditor: TextEditor | undefined + + /** + * The currently visible editors or an empty array. + */ + export const visibleTextEditors: readonly TextEditor[] + + /** + * An {@link Event} which fires when the {@link window.activeTextEditor active editor} + * has changed. *Note* that the event also fires when the active editor changes + * to `undefined`. + */ + export const onDidChangeActiveTextEditor: Event + + /** + * An {@link Event} which fires when the array of {@link window.visibleTextEditors visible editors} + * has changed. + */ + export const onDidChangeVisibleTextEditors: Event + + /** + * The currently opened terminals or an empty array. + */ + export const terminals: readonly Terminal[] + /** + * onDidChangeTerminalState doesn't exist since we can't detect window resize on vim. + */ + /** + * Event fired after terminal created, only fired with Terminal that + * created by `window.createTerminal` + */ + export const onDidOpenTerminal: Event + /** + * Event fired on terminal close, only fired with Terminal that created by + * `window.createTerminal` + */ + export const onDidCloseTerminal: Event + /** + * Creates a {@link Terminal} with a backing shell process. + * The terminal is created by (neo)vim. + * + * @param options A TerminalOptions object describing the characteristics of the new terminal. + * @return A new Terminal. + * @throws When running in an environment where a new process cannot be started. + */ + export function createTerminal(opts: TerminalOptions): Promise + + /** + * Reveal message with message type. + * + * @deprecated Use `window.showErrorMessage`, `window.showWarningMessage` and `window.showInformationMessage` instead. + * @param msg Message text to show. + * @param messageType Type of message, could be `error` `warning` and `more`, default to `more` + */ + export function showMessage(msg: string, messageType?: MsgTypes): void + + /** + * Run command in vim terminal for result + * + * @param cmd Command to run. + * @param cwd Cwd of terminal, default to result of |getcwd()|. + */ + export function runTerminalCommand(cmd: string, cwd?: string, keepfocus?: boolean): Promise + + /** + * Open terminal window. + * + * @param cmd Command to run. + * @param opts Terminal option. + * @returns buffer number of terminal. + */ + export function openTerminal(cmd: string, opts?: OpenTerminalOption): Promise + + /** + * Show quickpick for single item, use `window.menuPick` for menu at current current position. + * Use `window.showPickerDialog()` for multiple selection. + * + * @param items Label list. + * @param placeholder Prompt text, default to 'choose by number'. + * @returns Index of selected item, or -1 when canceled. + */ + export function showQuickpick(items: string[], placeholder?: string): Promise + + /** + * Shows a selection list allowing multiple selections. + * Throw error when 'workspace.env.dialog' is not true. + * + * @param items An array of strings, or a promise that resolves to an array of strings. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showQuickPick(items: readonly string[] | Thenable, options: QuickPickOptions & { canPickMany: true }, token?: CancellationToken): Thenable + + /** + * Shows a selection list. + * Throw error when 'workspace.env.dialog' is not true. + * + * @param items An array of strings, or a promise that resolves to an array of strings. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selection or `undefined`. + */ + export function showQuickPick(items: readonly string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable + + /** + * Shows a selection list allowing multiple selections. + * Throw error when 'workspace.env.dialog' is not true. + * + * @param items An array of items, or a promise that resolves to an array of items. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showQuickPick(items: readonly T[] | Thenable, options: QuickPickOptions & { canPickMany: true }, token?: CancellationToken): Thenable + + /** + * Shows a selection list. + * Throw error when `workspace.env.dialog` not true. + * + * @param items An array of items, or a promise that resolves to an array of items. + * @param options Configures the behavior of the selection list. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected item or `undefined`. + */ + export function showQuickPick(items: readonly T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable + + /** + * Show menu picker at current cursor position, |inputlist()| is used as fallback. + * Throw error when `workspace.env.dialog` not true. + * + * @param items Array of texts or menu items. + * @param title Optional title of float/popup window. + * @param token A token that can be used to signal cancellation. + * @returns Selected index (0 based), -1 when canceled. + */ + export function showMenuPicker(items: string[] | MenuItem[], option?: MenuOption | string, token?: CancellationToken): Promise + + /** + * Prompt user for confirm, a float/popup window would be used when possible, + * use vim's |confirm()| function as callback. + * + * @param title The prompt text. + * @returns Result of confirm. + */ + export function showPrompt(title: string): Promise + + /** + * Show dialog window at the center of screen. + * Note that the dialog would always be closed after button click. + * Throw error when `workspace.env.dialog` not true. + * + * @param config Dialog configuration. + * @returns Dialog or null when dialog can't work. + */ + export function showDialog(config: DialogConfig): Promise + + /** + * Request input from user, `input()` is used when `window.env.dialog` not true. + * + * @param title Title text of prompt window. + * @param defaultValue Default value of input, empty text by default. + * @param {InputOptions} option for input window, other preferences are read from user configuration. + */ + export function requestInput(title: string, defaultValue?: string, option?: InputOptions): Promise + + /** + * Creates and show a {@link InputBox} to let the user enter some text input. + * Throw error when `workspace.env.dialog` not true. + * + * @return A new {@link InputBox}. + */ + export function createInputBox(title: string, defaultValue: string | undefined, option: InputPreference): Promise + + /** + * Creates and show a {@link QuickPick} to let the user pick an item or items from a + * list of items of type T. + * Throw error when `workspace.env.dialog` not true. + * + * Note that in many cases the more convenient {@link window.showQuickPick} + * is easier to use. {@link window.createQuickPick} should be used + * when {@link window.showQuickPick} does not offer the required flexibility. + * + * @return A new {@link QuickPick}. + */ + export function createQuickPick(config: QuickPickConfig): Promise> + + /** + * Create statusbar item that would be included in `g:coc_status`. + * + * @param priority Higher priority item would be shown right. + * @param option + * @return A new status bar item. + */ + export function createStatusBarItem(priority?: number, option?: StatusItemOption): StatusBarItem + + /** + * Open local config file + */ + export function openLocalConfig(): Promise + + /** + * Create a new output channel + * + * @param name Unique name of output channel. + * @returns A new output channel. + */ + export function createOutputChannel(name: string): OutputChannel + + /** + * Create a {@link TreeView} instance, call `show()` method to render. + * + * @param viewId Id of the view, used as title of TreeView when title doesn't exist. + * @param options Options for creating the {@link TreeView} + * @returns a {@link TreeView}. + */ + export function createTreeView(viewId: string, options: TreeViewOptions): TreeView + + /** + * Reveal buffer of output channel. + * + * @param name Name of output channel. + * @param preserveFocus Preserve window focus when true. + */ + export function showOutputChannel(name: string, preserveFocus: boolean): void + + /** + * Echo lines at the bottom of vim. + * + * @param lines Line list. + * @param truncate Truncate the lines to avoid 'press enter to continue' when true + */ + export function echoLines(lines: string[], truncate?: boolean): Promise + + /** + * Get current cursor position (line, character both 0 based). + * + * @returns Cursor position. + */ + export function getCursorPosition(): Promise + + /** + * Move cursor to position (line, character both 0 based). + * + * @param position LSP position. + */ + export function moveTo(position: Position): Promise + + /** + * Get current cursor character offset in document, + * length of line break would always be 1. + * + * @returns Character offset. + */ + export function getOffset(): Promise + + /** + * Get screen position of current cursor(relative to editor), + * both `row` and `col` are 0 based. + * + * @returns Cursor screen position. + */ + export function getCursorScreenPosition(): Promise + + /** + * Show multiple picker at center of screen. + * Use `workspace.env.dialog` to check if dialog could work. + * + * @param items A set of items that will be rendered as actions in the message. + * @param title Title of picker dialog. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showPickerDialog(items: string[], title: string, token?: CancellationToken): Promise + + /** + * Show multiple picker at center of screen. + * Use `workspace.env.dialog` to check if dialog could work. + * + * @param items A set of items that will be rendered as actions in the message. + * @param title Title of picker dialog. + * @param token A token that can be used to signal cancellation. + * @return A promise that resolves to the selected items or `undefined`. + */ + export function showPickerDialog(items: T[], title: string, token?: CancellationToken): Promise + + /** + * Show an information message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, ...items: string[]): Promise + /** + * Show an information message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showInformationMessage(message: string, ...items: T[]): Promise + + /** + * Show an warning message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, ...items: string[]): Promise + /** + * Show an warning message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showWarningMessage(message: string, ...items: T[]): Promise + + /** + * Show an error message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, ...items: string[]): Promise + /** + * Show an error message to users. Optionally provide an array of items which will be presented as + * clickable buttons. + * + * @param message The message to show. + * @param items A set of items that will be rendered as actions in the message. + * @return Promise that resolves to the selected item or `undefined` when being dismissed. + */ + export function showErrorMessage(message: string, ...items: T[]): Promise + + /** + * Show notification window at bottom right of screen. + */ + export function showNotification(config: NotificationConfig): Promise + + /** + * Show progress in the editor. Progress is shown while running the given callback + * and while the promise it returned isn't resolved nor rejected. + * + * @param task A callback returning a promise. Progress state can be reported with + * the provided [progress](#Progress)-object. + * + * To report discrete progress, use `increment` to indicate how much work has been completed. Each call with + * a `increment` value will be summed up and reflected as overall progress until 100% is reached (a value of + * e.g. `10` accounts for `10%` of work done). + * + * To monitor if the operation has been cancelled by the user, use the provided [`CancellationToken`](#CancellationToken). + * + * @return The thenable the task-callback returned. + */ + export function withProgress(options: ProgressOptions, task: (progress: Progress<{ + message?: string + increment?: number + }>, token: CancellationToken) => Thenable): Promise + + /** + * Get selected range for current document + */ + export function getSelectedRange(visualmode: string): Promise + + /** + * Visual select range of current document + */ + export function selectRange(range: Range): Promise + + /** + * Get diff between new highlight items and current highlights requested from vim + * + * @param {number} bufnr - Buffer number + * @param {string} ns - Highlight namespace + * @param {HighlightItem[]} items - Highlight items + * @param {[number, number] | undefined} - region 0 based start line and end line (end exclusive) + * @param {CancellationToken} token - CancellationToken + * @returns {Promise} + */ + export function diffHighlights(bufnr: number, ns: string, items: ExtendedHighlightItem[], region?: [number, number] | undefined, token?: CancellationToken): Promise + + /** + * Apply highlight diffs, normally used with `window.diffHighlights` + * + * Timer is used to add highlights when there're too many highlight items to add, + * the highlight process won't be finished on that case. + * + * @param {number} bufnr - Buffer name + * @param {string} ns - Namespace + * @param {number} priority + * @param {HighlightDiff} diff + * @param {boolean} notify - Use notification, default false. + * @returns {Promise} + */ + export function applyDiffHighlights(bufnr: number, ns: string, priority: number, diff: HighlightDiff, notify?: boolean): Promise + } + // }} + + // extensions module {{ + export interface Logger { + readonly category: string + readonly level: string + log(...args: any[]): void + trace(message: any, ...args: any[]): void + debug(message: any, ...args: any[]): void + info(message: any, ...args: any[]): void + warn(message: any, ...args: any[]): void + error(message: any, ...args: any[]): void + fatal(message: any, ...args: any[]): void + mark(message: any, ...args: any[]): void + } + + /** + * A memento represents a storage utility. It can store and retrieve + * values. + */ + export interface Memento { + + /** + * Return a value. + * + * @param key A string. + * @return The stored value or `undefined`. + */ + get(key: string): T | undefined + + /** + * Return a value. + * + * @param key A string. + * @param defaultValue A value that should be returned when there is no + * value (`undefined`) with the given key. + * @return The stored value or the defaultValue. + */ + get(key: string, defaultValue: T): T + + /** + * Store a value. The value must be JSON-stringifyable. + * + * @param key A string. + * @param value A value. MUST not contain cyclic references. + */ + update(key: string, value: any): Promise + } + + export type ExtensionState = 'disabled' | 'loaded' | 'activated' | 'unknown' + + export enum ExtensionType { + Global, + Local, + SingleFile, + Internal + } + + export interface ExtensionJson { + name: string + main?: string + engines: { + [key: string]: string + } + version?: string + [key: string]: any + } + + export interface ExtensionInfo { + id: string + version: string + description: string + root: string + exotic: boolean + uri?: string + state: ExtensionState + isLocal: boolean + packageJSON: Readonly + } + + /** + * Represents an extension. + * + * To get an instance of an `Extension` use [getExtension](#extensions.getExtension). + */ + export interface Extension { + + /** + * The canonical extension identifier in the form of: `publisher.name`. + */ + readonly id: string + + /** + * The absolute file path of the directory containing this extension. + */ + readonly extensionPath: string + + /** + * `true` if the extension has been activated. + */ + readonly isActive: boolean + + /** + * The parsed contents of the extension's package.json. + */ + readonly packageJSON: any + + /** + * The public API exported by this extension. It is an invalid action + * to access this field before this extension has been activated. + */ + readonly exports: T + + /** + * Activates this extension and returns its public API. + * + * @return A promise that will resolve when this extension has been activated. + */ + activate(): Promise + } + + /** + * An extension context is a collection of utilities private to an + * extension. + * + * An instance of an `ExtensionContext` is provided as the first + * parameter to the `activate`-call of an extension. + */ + export interface ExtensionContext { + + /** + * An array to which disposables can be added. When this + * extension is deactivated the disposables will be disposed. + */ + subscriptions: Disposable[] + + /** + * The absolute file path of the directory containing the extension. + */ + extensionPath: string + + /** + * Get the absolute path of a resource contained in the extension. + * + * @param relativePath A relative path to a resource contained in the extension. + * @return The absolute path of the resource. + */ + asAbsolutePath(relativePath: string): string + + /** + * The absolute directory path for extension to download persist data. + * The directory might not exist. + */ + storagePath: string + + /** + * A memento object that stores state in the context + * of the currently opened [workspace](#workspace.workspaceFolders). + */ + workspaceState: Memento + + /** + * A memento object that stores state independent + * of the current opened [workspace](#workspace.workspaceFolders). + */ + globalState: Memento + + logger: Logger + } + + export type ExtensionApi = { + [index: string]: any + } | void | null | undefined + + export interface PropertyScheme { + type: string + default: any + description: string + enum?: string[] + items?: any + [key: string]: any + } + + export namespace extensions { + /** + * Fired on extension loaded, extension not activated yet. + */ + export const onDidLoadExtension: Event> + + /** + * Fired on extension activated. + */ + export const onDidActiveExtension: Event> + + /** + * Fired with extension id on extension unload. + */ + export const onDidUnloadExtension: Event + + /** + * Get all loaded extensions, without disabled extensions, extension may not activated. + */ + export const all: ReadonlyArray> + + /** + * Get state of specific extension. + */ + export function getExtensionState(id: string): ExtensionState + + /** + * Get state of all extensions, including disabled extensions. + */ + export function getExtensionStates(): Promise + + /** + * Check if extension is activated. + */ + export function isActivated(id: string): boolean + + /** + * Dynamic add custom json schemes without using package.json. + */ + export function addSchemeProperty(key: string, def: PropertyScheme): void + } + // }} + + // listManager module {{ + export interface LocationWithLine { + uri: string + /** + * Match text of line. + */ + line: string + /** + * Highlight text in line. + */ + text?: string + } + + export interface AnsiHighlight { + /** + * Byte indexes, 0 based. + */ + span: [number, number] + hlGroup: string + } + + export interface ListItem { + label: string + preselect?: boolean + filterText?: string + /** + * A string that should be used when comparing this item + * with other items, only used for fuzzy filter. + */ + sortText?: string + location?: Location | LocationWithLine | string + data?: any + ansiHighlights?: AnsiHighlight[] + resolved?: boolean + } + + export interface ListHighlights { + /** + * Byte indexes list, 0 based. + */ + spans: [number, number][] + /** + * `CocListSearch` is used when it not exist. + */ + hlGroup?: string + } + + export type ListMode = 'normal' | 'insert' + + export type ListMatcher = 'strict' | 'fuzzy' | 'regex' + + export interface ListOptions { + position: string + reverse: boolean + input: string + ignorecase: boolean + interactive: boolean + sort: boolean + mode: ListMode + matcher: ListMatcher + autoPreview: boolean + numberSelect: boolean + noQuit: boolean + first: boolean + } + + export interface ListContext { + /** + * Input on list activated. + */ + input: string + /** + * Current work directory on activated. + */ + cwd: string + /** + * Options of list. + */ + options: ListOptions + /** + * Arguments passed to list. + */ + args: string[] + /** + * Original window on list invoke. + */ + window: Window + /** + * Original buffer on list invoke. + */ + buffer: Buffer + listWindow: Window | null + } + + export interface ListAction { + /** + * Action name + */ + name: string + /** + * Should persist list window on invoke. + */ + persist?: boolean + /** + * Should reload list after invoke. + */ + reload?: boolean + /** + * Inovke all selected items in parallel. + */ + parallel?: boolean + /** + * Support handle multiple items at once. + */ + multiple?: boolean + /** + * Tab positioned list should be persisted (no window switch) on action invoke. + */ + tabPersist?: boolean + /** + * Item is array of selected items when multiple is true. + */ + execute: (item: ListItem | ListItem[], context: ListContext) => ProviderResult + } + + export interface MultipleListAction extends Omit { + multiple: true + execute: (item: ListItem[], context: ListContext) => ProviderResult + } + + export interface ListTask { + on(event: 'data', callback: (item: ListItem) => void): void + on(event: 'end', callback: () => void): void + on(event: 'error', callback: (msg: string | Error) => void): void + dispose(): void + } + + export interface ListArgument { + key?: string + hasValue?: boolean + name: string + description: string + } + + export interface IList { + /** + * Unique name of list. + */ + name: string + /** + * Default action name. + */ + defaultAction: string + /** + * Action list. + */ + actions: ListAction[] + /** + * Load list items. + */ + loadItems(context: ListContext, token: CancellationToken): Promise + /** + * Should be true when interactive is supported. + */ + interactive?: boolean + /** + * Description of list. + */ + description?: string + /** + * Detail description, shown in help. + */ + detail?: string + /** + * Options supported by list. + */ + options?: ListArgument[] + /** + * Resolve list item. + */ + resolveItem?(item: ListItem): Promise + /** + * Highlight buffer by vim's syntax commands. + */ + doHighlight?(): void + /** + * Called on list unregistered. + */ + dispose?(): void + } + + export interface PreviewOptions { + bufname?: string + lines: string[] + filetype: string + lnum?: number + range?: Range + /** + * @deprecated not used + */ + sketch?: boolean + } + + export namespace listManager { + /** + * Registered list names set. + */ + export const names: ReadonlyArray + /** + * Register list, list session can be created by `CocList [name]` after registered. + */ + export function registerList(list: IList): Disposable + } + // }} + + // snippetManager module {{ + export interface SnippetSession { + isActive: boolean + } + + export interface UltiSnippetOption { + regex?: string + context?: string + } + + /** + * A snippet string is a template which allows to insert text + * and to control the editor cursor when insertion happens. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Variables are defined with `$name` and + * `${name:default value}`. The full snippet syntax is documented + * [here](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_creating-your-own-snippets). + */ + export class SnippetString { + /** + * The snippet string. + */ + value: string + + constructor( + /** + * The default snippet string. + */ + value?: string + ) + + /** + * Builder-function that appends the given string to + * the {@link SnippetString.value `value`} of this snippet string. + * + * @param string A value to append 'as given'. The string will be escaped. + * @return This snippet string. + */ + appendText(string: string): SnippetString + + /** + * Builder-function that appends a tabstop (`$1`, `$2` etc) to + * the {@link SnippetString.value `value`} of this snippet string. + * + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendTabstop(number?: number): SnippetString + + /** + * Builder-function that appends a placeholder (`${1:value}`) to + * the {@link SnippetString.value `value`} of this snippet string. + * + * @param value The value of this placeholder - either a string or a function + * with which a nested snippet can be created. + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendPlaceholder(value: string | ((snippet: SnippetString) => any), number?: number): SnippetString + + /** + * Builder-function that appends a choice (`${1|a,b,c|}`) to + * the {@link SnippetString.value `value`} of this snippet string. + * + * @param values The values for choices - the array of strings + * @param number The number of this tabstop, defaults to an auto-increment + * value starting at 1. + * @return This snippet string. + */ + appendChoice(values: string[], number?: number): SnippetString + + /** + * Builder-function that appends a variable (`${VAR}`) to + * the {@link SnippetString.value `value`} of this snippet string. + * + * @param name The name of the variable - excluding the `$`. + * @param defaultValue The default value which is used when the variable name cannot + * be resolved - either a string or a function with which a nested snippet can be created. + * @return This snippet string. + */ + appendVariable(name: string, defaultValue: string | ((snippet: SnippetString) => any)): SnippetString + } + /** + * Manage snippet sessions. + */ + export namespace snippetManager { + /** + * Get snippet session by bufnr. + */ + export function getSession(bufnr: number): SnippetSession | undefined + /** + * Resolve snippet string to text. + */ + export function resolveSnippet(body: string, ultisnip?: UltiSnippetOption): Promise + /** + * Insert snippet at current buffer. + * + * @param {string} snippet Textmate snippet string. + * @param {boolean} select Not select first placeholder when false, default `true`. + * @param {Range} range Repalce range, insert to current cursor position when undefined. + * @returns {Promise} true when insert success. + */ + export function insertSnippet(snippet: string | SnippetString, select?: boolean, range?: Range, ultisnip?: boolean): Promise + + /** + * Jump to next placeholder, only works when snippet session activated. + */ + export function nextPlaceholder(): Promise + /** + * Jump to previous placeholder, only works when snippet session activated. + */ + export function previousPlaceholder(): Promise + /** + * Cancel snippet session of current buffer, does nothing when no session activated. + */ + export function cancel(): void + /** + * Check if snippet activated for bufnr. + */ + export function isActivated(bufnr: number): boolean + } + // }} + + // diagnosticManager module {{ + export interface DiagnosticItem { + file: string + lnum: number + col: number + source: string + code: string | number + message: string + severity: string + level: number + location: Location + } + + export enum DiagnosticKind { + Syntax, + Semantic, + Suggestion, + } + + /** + * A diagnostics collection is a container that manages a set of + * [diagnostics](#Diagnostic). Diagnostics are always scopes to a + * diagnostics collection and a resource. + * + * To get an instance of a `DiagnosticCollection` use + * [createDiagnosticCollection](#languages.createDiagnosticCollection). + */ + export interface DiagnosticCollection { + + /** + * The name of this diagnostic collection, for instance `typescript`. Every diagnostic + * from this collection will be associated with this name. Also, the task framework uses this + * name when defining [problem matchers](https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher). + */ + readonly name: string + + /** + * Assign diagnostics for given resource. Will replace + * existing diagnostics for that resource. + * + * @param uri A resource identifier. + * @param diagnostics Array of diagnostics or `undefined` + */ + set(uri: string, diagnostics: Diagnostic[] | null): void + /** + * Replace all entries in this collection. + * + * Diagnostics of multiple tuples of the same uri will be merged, e.g + * `[[file1, [d1]], [file1, [d2]]]` is equivalent to `[[file1, [d1, d2]]]`. + * If a diagnostics item is `undefined` as in `[file1, undefined]` + * all previous but not subsequent diagnostics are removed. + * + * @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`. + */ + set(entries: [string, Diagnostic[] | null][] | string, diagnostics?: Diagnostic[]): void + + /** + * Remove all diagnostics from this collection that belong + * to the provided `uri`. The same as `#set(uri, undefined)`. + * + * @param uri A resource identifier. + */ + delete(uri: string): void + + /** + * Remove all diagnostics from this collection. The same + * as calling `#set(undefined)` + */ + clear(): void + + /** + * Iterate over each entry in this collection. + * + * @param callback Function to execute for each entry. + * @param thisArg The `this` context used when invoking the handler function. + */ + forEach(callback: (uri: string, diagnostics: Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void + + /** + * Get the diagnostics for a given resource. *Note* that you cannot + * modify the diagnostics-array returned from this call. + * + * @param uri A resource identifier. + * @returns An immutable array of [diagnostics](#Diagnostic) or `undefined`. + */ + get(uri: string): Diagnostic[] | undefined + + /** + * Check if this collection contains diagnostics for a + * given resource. + * + * @param uri A resource identifier. + * @returns `true` if this collection has diagnostic for the given resource. + */ + has(uri: string): boolean + + /** + * Dispose and free associated resources. Calls + * [clear](#DiagnosticCollection.clear). + */ + dispose(): void + } + + export interface DiagnosticEventParams { + bufnr: number + uri: string + diagnostics: ReadonlyArray + } + + export namespace diagnosticManager { + + export const onDidRefresh: Event + /** + * Create collection by name + */ + export function create(name: string): DiagnosticCollection + + /** + * Get readonly diagnostics for uri + */ + export function getDiagnostics(uri: string): { [collection: string]: Diagnostic[] } + + /** + * Get readonly diagnostics by document and range. + */ + export function getDiagnosticsInRange(doc: TextDocumentIdentifier, range: Range): ReadonlyArray + /** + * Get all sorted diagnostics + */ + export function getDiagnosticList(): Promise> + + /** + * All diagnostics at current cursor position. + */ + export function getCurrentDiagnostics(): Promise> + + /** + * Get diagnostic collection. + */ + export function getCollectionByName(name: string): DiagnosticCollection + } + // }} + + // language client {{ + /** + * An action to be performed when the connection is producing errors. + */ + export enum ErrorAction { + /** + * Continue running the server. + */ + Continue = 1, + /** + * Shutdown the server. + */ + Shutdown = 2 + } + /** + * An action to be performed when the connection to a server got closed. + */ + export enum CloseAction { + /** + * Don't restart the server. The connection stays closed. + */ + DoNotRestart = 1, + /** + * Restart the server. + */ + Restart = 2 + } + /** + * A pluggable error handler that is invoked when the connection is either + * producing errors or got closed. + */ + export interface ErrorHandler { + /** + * An error has occurred while writing or reading from the connection. + * + * @param error - the error received + * @param message - the message to be delivered to the server if know. + * @param count - a count indicating how often an error is received. Will + * be reset if a message got successfully send or received. + */ + error(error: Error, message: { jsonrpc: string }, count: number): ErrorAction + /** + * The connection to the server got closed. + */ + closed(): CloseAction + } + export interface InitializationFailedHandler { + (error: Error | any): boolean + } + + export interface SynchronizeOptions { + configurationSection?: string | string[] + fileEvents?: FileSystemWatcher | FileSystemWatcher[] + } + + export enum RevealOutputChannelOn { + Info = 1, + Warn = 2, + Error = 3, + Never = 4 + } + export interface ConfigurationItem { + /** + * The scope to get the configuration section for. + */ + scopeUri?: string + /** + * The configuration section asked for. + */ + section?: string + } + export interface ResponseError { + code: number + data: D | undefined + } + + export type HandlerResult = R | ResponseError | Thenable | Thenable> | Thenable> + + export interface RequestHandler { + (params: P, token: CancellationToken): HandlerResult + } + + export interface RequestHandler0 { + (token: CancellationToken): HandlerResult + } + /** + * The parameters of a configuration request. + */ + export interface ConfigurationParams { + items: ConfigurationItem[] + } + + export interface ConfigurationWorkspaceMiddleware { + configuration?: (params: ConfigurationParams, token: CancellationToken, next: RequestHandler) => HandlerResult + } + + export interface WorkspaceFolderWorkspaceMiddleware { + workspaceFolders?: (token: CancellationToken, next: RequestHandler0) => HandlerResult + didChangeWorkspaceFolders?: NextSignature + } + + export interface ProvideTypeDefinitionSignature { + ( + this: void, + document: LinesTextDocument, + position: Position, + token: CancellationToken + ): ProviderResult + } + + export interface TypeDefinitionMiddleware { + provideTypeDefinition?: ( + this: void, + document: LinesTextDocument, + position: Position, + token: CancellationToken, + next: ProvideTypeDefinitionSignature + ) => ProviderResult + } + + export interface ProvideImplementationSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface ImplementationMiddleware { + provideImplementation?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: ProvideImplementationSignature) => ProviderResult + } + export type ProvideDocumentColorsSignature = (document: LinesTextDocument, token: CancellationToken) => ProviderResult + + export type ProvideColorPresentationSignature = ( + color: Color, + context: { document: LinesTextDocument; range: Range }, + token: CancellationToken + ) => ProviderResult + + export interface ColorProviderMiddleware { + provideDocumentColors?: ( + this: void, + document: LinesTextDocument, + token: CancellationToken, + next: ProvideDocumentColorsSignature + ) => ProviderResult + provideColorPresentations?: ( + this: void, + color: Color, + context: { document: LinesTextDocument; range: Range }, + token: CancellationToken, + next: ProvideColorPresentationSignature + ) => ProviderResult + } + + export interface ProvideDeclarationSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface DeclarationMiddleware { + provideDeclaration?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: ProvideDeclarationSignature) => ProviderResult + } + + export type ProvideFoldingRangeSignature = ( + this: void, + document: LinesTextDocument, + context: FoldingContext, + token: CancellationToken + ) => ProviderResult + + export interface FoldingRangeProviderMiddleware { + provideFoldingRanges?: ( + this: void, + document: LinesTextDocument, + context: FoldingContext, + token: CancellationToken, + next: ProvideFoldingRangeSignature + ) => ProviderResult + } + + export interface PrepareCallHierarchySignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface CallHierarchyIncomingCallsSignature { + (this: void, item: CallHierarchyItem, token: CancellationToken): ProviderResult + } + + export interface CallHierarchyOutgoingCallsSignature { + (this: void, item: CallHierarchyItem, token: CancellationToken): ProviderResult + } + export interface CallHierarchyMiddleware { + prepareCallHierarchy?: ( + this: void, + document: LinesTextDocument, + positions: Position, + token: CancellationToken, + next: PrepareCallHierarchySignature + ) => ProviderResult + provideCallHierarchyIncomingCalls?: ( + this: void, + item: CallHierarchyItem, + token: CancellationToken, + next: CallHierarchyIncomingCallsSignature + ) => ProviderResult + provideCallHierarchyOutgoingCalls?: ( + this: void, + item: CallHierarchyItem, + token: CancellationToken, + next: CallHierarchyOutgoingCallsSignature + ) => ProviderResult + } + + export interface DocumentSemanticsTokensSignature { + (this: void, document: LinesTextDocument, token: CancellationToken): ProviderResult + } + + export interface DocumentSemanticsTokensEditsSignature { + (this: void, document: LinesTextDocument, previousResultId: string, token: CancellationToken): ProviderResult + } + + export interface DocumentRangeSemanticTokensSignature { + (this: void, document: LinesTextDocument, range: Range, token: CancellationToken): ProviderResult + } + + export interface SemanticTokensMiddleware { + provideDocumentSemanticTokens?: ( + this: void, + document: LinesTextDocument, + token: CancellationToken, + next: DocumentSemanticsTokensSignature + ) => ProviderResult + provideDocumentSemanticTokensEdits?: ( + this: void, + document: LinesTextDocument, + previousResultId: string, + token: CancellationToken, + next: DocumentSemanticsTokensEditsSignature + ) => ProviderResult + provideDocumentRangeSemanticTokens?: ( + this: void, + document: LinesTextDocument, + range: Range, + token: CancellationToken, + next: DocumentRangeSemanticTokensSignature + ) => ProviderResult + } + + + /** + * File operation middleware + * @since 3.16.0 + */ + export interface FileOperationsMiddleware { + didCreateFiles?: NextSignature + willCreateFiles?: NextSignature> + didRenameFiles?: NextSignature + willRenameFiles?: NextSignature> + didDeleteFiles?: NextSignature + willDeleteFiles?: NextSignature> + } + + export interface ProvideLinkedEditingRangeSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface LinkedEditingRangeMiddleware { + provideLinkedEditingRange?: ( + this: void, + document: LinesTextDocument, + position: Position, + token: CancellationToken, + next: ProvideLinkedEditingRangeSignature + ) => ProviderResult + } + + export interface ProvideSelectionRangeSignature { + (this: void, document: LinesTextDocument, positions: Position[], token: CancellationToken): ProviderResult + } + + export interface SelectionRangeProviderMiddleware { + provideSelectionRanges?: (this: void, document: LinesTextDocument, positions: Position[], token: CancellationToken, next: ProvideSelectionRangeSignature) => ProviderResult + } + + export interface HandleWorkDoneProgressSignature { + (this: void, token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd): void + } + + export interface HandleDiagnosticsSignature { + (this: void, uri: string, diagnostics: Diagnostic[]): void + } + + export interface ProvideCompletionItemsSignature { + (this: void, document: LinesTextDocument, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult + } + + export interface ResolveCompletionItemSignature { + (this: void, item: CompletionItem, token: CancellationToken): ProviderResult + } + + export interface ProvideHoverSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface ProvideSignatureHelpSignature { + (this: void, document: LinesTextDocument, position: Position, context: SignatureHelpContext, token: CancellationToken): ProviderResult + } + + export interface ProvideDefinitionSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface ProvideReferencesSignature { + (this: void, document: LinesTextDocument, position: Position, options: { + includeDeclaration: boolean + }, token: CancellationToken): ProviderResult + } + + export interface ProvideDocumentHighlightsSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface ProvideDocumentSymbolsSignature { + (this: void, document: LinesTextDocument, token: CancellationToken): ProviderResult + } + + export interface ProvideWorkspaceSymbolsSignature { + (this: void, query: string, token: CancellationToken): ProviderResult + } + + export interface ProvideCodeActionsSignature { + (this: void, document: LinesTextDocument, range: Range, context: CodeActionContext, token: CancellationToken): ProviderResult<(Command | CodeAction)[]> + } + + export interface ResolveCodeActionSignature { + (this: void, item: CodeAction, token: CancellationToken): ProviderResult + } + + export interface ProvideCodeLensesSignature { + (this: void, document: LinesTextDocument, token: CancellationToken): ProviderResult + } + + export interface ResolveCodeLensSignature { + (this: void, codeLens: CodeLens, token: CancellationToken): ProviderResult + } + + export interface ProvideDocumentFormattingEditsSignature { + (this: void, document: LinesTextDocument, options: FormattingOptions, token: CancellationToken): ProviderResult + } + + export interface ProvideDocumentRangeFormattingEditsSignature { + (this: void, document: LinesTextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult + } + + export interface ProvideOnTypeFormattingEditsSignature { + (this: void, document: LinesTextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult + } + + export interface PrepareRenameSignature { + (this: void, document: LinesTextDocument, position: Position, token: CancellationToken): ProviderResult + } + + export interface ProvideRenameEditsSignature { + (this: void, document: LinesTextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult + } + + export interface ProvideDocumentLinksSignature { + (this: void, document: LinesTextDocument, token: CancellationToken): ProviderResult + } + + export interface ResolveDocumentLinkSignature { + (this: void, link: DocumentLink, token: CancellationToken): ProviderResult + } + + export interface ExecuteCommandSignature { + (this: void, command: string, args: any[]): ProviderResult + } + + export interface NextSignature { + (this: void, data: P, next: (data: P) => R): R + } + + export interface DidChangeConfigurationSignature { + (this: void, sections: string[] | undefined): void + } + + export interface DidChangeWatchedFileSignature { + (this: void, event: FileEvent): void + } + + export interface _WorkspaceMiddleware { + didChangeConfiguration?: (this: void, sections: string[] | undefined, next: DidChangeConfigurationSignature) => void + didChangeWatchedFile?: (this: void, event: FileEvent, next: DidChangeWatchedFileSignature) => void + } + + export type WorkspaceMiddleware = _WorkspaceMiddleware & ConfigurationWorkspaceMiddleware & WorkspaceFolderWorkspaceMiddleware & FileOperationsMiddleware + + /** + * Params to show a document. + * + * @since 3.16.0 + */ + export interface ShowDocumentParams { + /** + * The document uri to show. + */ + uri: string + /** + * Indicates to show the resource in an external program. + * To show for example `https://code.visualstudio.com/` + * in the default WEB browser set `external` to `true`. + */ + external?: boolean + /** + * An optional property to indicate whether the editor + * showing the document should take focus or not. + * Clients might ignore this property if an external + * program in started. + */ + takeFocus?: boolean + /** + * An optional selection range if the document is a text + * document. Clients might ignore the property if an + * external program is started or the file is not a text + * file. + */ + selection?: Range + } + /** + * The result of an show document request. + * + * @since 3.16.0 + */ + export interface ShowDocumentResult { + /** + * A boolean indicating if the show was successful. + */ + success: boolean + } + + export interface _WindowMiddleware { + showDocument?: ( + this: void, + params: ShowDocumentParams, + next: RequestHandler + ) => Promise + } + export type WindowMiddleware = _WindowMiddleware + + /** + * The Middleware lets extensions intercept the request and notifications send and received + * from the server + */ + interface _Middleware { + didOpen?: NextSignature + didChange?: NextSignature + willSave?: NextSignature + willSaveWaitUntil?: NextSignature> + didSave?: NextSignature + didClose?: NextSignature + handleDiagnostics?: (this: void, uri: string, diagnostics: Diagnostic[], next: HandleDiagnosticsSignature) => void + provideCompletionItem?: (this: void, document: LinesTextDocument, position: Position, context: CompletionContext, token: CancellationToken, next: ProvideCompletionItemsSignature) => ProviderResult + resolveCompletionItem?: (this: void, item: CompletionItem, token: CancellationToken, next: ResolveCompletionItemSignature) => ProviderResult + provideHover?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: ProvideHoverSignature) => ProviderResult + provideSignatureHelp?: (this: void, document: LinesTextDocument, position: Position, context: SignatureHelpContext, token: CancellationToken, next: ProvideSignatureHelpSignature) => ProviderResult + provideDefinition?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: ProvideDefinitionSignature) => ProviderResult + provideReferences?: (this: void, document: LinesTextDocument, position: Position, options: { + includeDeclaration: boolean + }, token: CancellationToken, next: ProvideReferencesSignature) => ProviderResult + provideDocumentHighlights?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: ProvideDocumentHighlightsSignature) => ProviderResult + provideDocumentSymbols?: (this: void, document: LinesTextDocument, token: CancellationToken, next: ProvideDocumentSymbolsSignature) => ProviderResult + provideWorkspaceSymbols?: (this: void, query: string, token: CancellationToken, next: ProvideWorkspaceSymbolsSignature) => ProviderResult + provideCodeActions?: (this: void, document: LinesTextDocument, range: Range, context: CodeActionContext, token: CancellationToken, next: ProvideCodeActionsSignature) => ProviderResult<(Command | CodeAction)[]> + handleWorkDoneProgress?: (this: void, token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd, next: HandleWorkDoneProgressSignature) => void + resolveCodeAction?: (this: void, item: CodeAction, token: CancellationToken, next: ResolveCodeActionSignature) => ProviderResult + provideCodeLenses?: (this: void, document: LinesTextDocument, token: CancellationToken, next: ProvideCodeLensesSignature) => ProviderResult + resolveCodeLens?: (this: void, codeLens: CodeLens, token: CancellationToken, next: ResolveCodeLensSignature) => ProviderResult + provideDocumentFormattingEdits?: (this: void, document: LinesTextDocument, options: FormattingOptions, token: CancellationToken, next: ProvideDocumentFormattingEditsSignature) => ProviderResult + provideDocumentRangeFormattingEdits?: (this: void, document: LinesTextDocument, range: Range, options: FormattingOptions, token: CancellationToken, next: ProvideDocumentRangeFormattingEditsSignature) => ProviderResult + provideOnTypeFormattingEdits?: (this: void, document: LinesTextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken, next: ProvideOnTypeFormattingEditsSignature) => ProviderResult + prepareRename?: (this: void, document: LinesTextDocument, position: Position, token: CancellationToken, next: PrepareRenameSignature) => ProviderResult + provideRenameEdits?: (this: void, document: LinesTextDocument, position: Position, newName: string, token: CancellationToken, next: ProvideRenameEditsSignature) => ProviderResult + provideDocumentLinks?: (this: void, document: LinesTextDocument, token: CancellationToken, next: ProvideDocumentLinksSignature) => ProviderResult + resolveDocumentLink?: (this: void, link: DocumentLink, token: CancellationToken, next: ResolveDocumentLinkSignature) => ProviderResult + executeCommand?: (this: void, command: string, args: any[], next: ExecuteCommandSignature) => ProviderResult + workspace?: WorkspaceMiddleware + window?: WindowMiddleware + } + export type Middleware = _Middleware & TypeDefinitionMiddleware & ImplementationMiddleware & ColorProviderMiddleware & DeclarationMiddleware & FoldingRangeProviderMiddleware & CallHierarchyMiddleware & SemanticTokensMiddleware & LinkedEditingRangeMiddleware & SelectionRangeProviderMiddleware + + export interface ConnectionOptions { + // cancellationStrategy: CancellationStrategy + maxRestartCount?: number + } + + export interface LanguageClientOptions { + ignoredRootPaths?: string[] + disableSnippetCompletion?: boolean + disableDynamicRegister?: boolean + disabledFeatures?: string[] + formatterPriority?: number + documentSelector?: DocumentSelector | string[] + synchronize?: SynchronizeOptions + diagnosticCollectionName?: string + outputChannelName?: string + outputChannel?: OutputChannel + revealOutputChannelOn?: RevealOutputChannelOn + /** + * The encoding use to read stdout and stderr. Defaults + * to 'utf8' if omitted. + */ + stdioEncoding?: string + initializationOptions?: any | (() => any) + initializationFailedHandler?: InitializationFailedHandler + progressOnInitialization?: boolean + errorHandler?: ErrorHandler + middleware?: Middleware + workspaceFolder?: WorkspaceFolder + connectionOptions?: ConnectionOptions + markdown?: { + isTrusted: boolean + } + } + export enum State { + Stopped = 1, + Running = 2, + Starting = 3 + } + export interface StateChangeEvent { + oldState: State + newState: State + } + export enum ClientState { + Initial = 0, + Starting = 1, + StartFailed = 2, + Running = 3, + Stopping = 4, + Stopped = 5 + } + export interface RegistrationData { + id: string + registerOptions: T + } + /** + * A static feature. A static feature can't be dynamically activate via the + * server. It is wired during the initialize sequence. + */ + export interface StaticFeature { + /** + * Called to fill the initialize params. + * + * @params the initialize params. + */ + fillInitializeParams?: (params: any) => void + /** + * Called to fill in the client capabilities this feature implements. + * + * @param capabilities The client capabilities to fill. + */ + fillClientCapabilities(capabilities: any): void + /** + * Initialize the feature. This method is called on a feature instance + * when the client has successfully received the initialize request from + * the server and before the client sends the initialized notification + * to the server. + * + * @param capabilities the server capabilities + * @param documentSelector the document selector pass to the client's constructor. + * May be `undefined` if the client was created without a selector. + */ + initialize(capabilities: any, documentSelector: DocumentSelector | undefined): void + /** + * Called when the client is stopped to dispose this feature. Usually a feature + * unregisters listeners registered hooked up with the VS Code extension host. + */ + dispose(): void + } + + class ParameterStructures { + private readonly kind + /** + * The parameter structure is automatically inferred on the number of parameters + * and the parameter type in case of a single param. + */ + static readonly auto: ParameterStructures + /** + * Forces `byPosition` parameter structure. This is useful if you have a single + * parameter which has a literal type. + */ + static readonly byPosition: ParameterStructures + /** + * Forces `byName` parameter structure. This is only useful when having a single + * parameter. The library will report errors if used with a different number of + * parameters. + */ + static readonly byName: ParameterStructures + private constructor() + static is(value: any): value is ParameterStructures + toString(): string + } + /** + * An interface to type messages. + */ + export interface MessageSignature { + readonly method: string + readonly numberOfParams: number + readonly parameterStructures: ParameterStructures + } + + /** + * + * An abstract implementation of a MessageType. + */ + abstract class AbstractMessageSignature implements MessageSignature { + readonly method: string + readonly numberOfParams: number + constructor(method: string, numberOfParams: number) + get parameterStructures(): ParameterStructures + } + + /** + * Classes to type request response pairs + */ + export class RequestType0 extends AbstractMessageSignature { + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly _: [R, E, _EM] | undefined + constructor(method: string) + } + + export class RequestType extends AbstractMessageSignature { + private _parameterStructures + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly _: [P, R, E, _EM] | undefined + constructor(method: string, _parameterStructures?: ParameterStructures) + get parameterStructures(): ParameterStructures + } + + export class NotificationType

    extends AbstractMessageSignature { + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly _: [P, _EM] | undefined + constructor(method: string) + } + + export class NotificationType0 extends AbstractMessageSignature { + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly _: [_EM] | undefined + constructor(method: string) + } + + export interface InitializeParams { + /** + * The process Id of the parent process that started + * the server. + */ + processId: number | null + /** + * Information about the client + * + * @since 3.15.0 + */ + clientInfo?: { + /** + * The name of the client as defined by the client. + */ + name: string + /** + * The client's version as defined by the client. + */ + version?: string + } + /** + * The rootPath of the workspace. Is null + * if no folder is open. + * + * @deprecated in favour of rootUri. + */ + rootPath?: string | null + /** + * The rootUri of the workspace. Is null if no + * folder is open. If both `rootPath` and `rootUri` are set + * `rootUri` wins. + * + * @deprecated in favour of workspaceFolders. + */ + rootUri: string | null + /** + * The capabilities provided by the client (editor or tool) + */ + capabilities: any + /** + * User provided initialization options. + */ + initializationOptions?: any + /** + * The initial trace setting. If omitted trace is disabled ('off'). + */ + trace?: 'off' | 'messages' | 'verbose' + /** + * An optional token that a server can use to report work done progress. + */ + workDoneToken?: ProgressToken + } + class RegistrationType { + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly ____: [RO, _EM] | undefined + readonly method: string + constructor(method: string) + } + /** + * The result returned from an initialize request. + */ + export interface InitializeResult { + /** + * The capabilities the language server provides. + */ + capabilities: any + /** + * Information about the server. + * + * @since 3.15.0 + */ + serverInfo?: { + /** + * The name of the server as defined by the server. + */ + name: string + /** + * The servers's version as defined by the server. + */ + version?: string + } + /** + * Custom initialization results. + */ + [custom: string]: any + } + + export interface DynamicFeature { + /** + * Called to fill the initialize params. + * + * @params the initialize params. + */ + fillInitializeParams?: (params: InitializeParams) => void + /** + * Called to fill in the client capabilities this feature implements. + * + * @param capabilities The client capabilities to fill. + */ + fillClientCapabilities(capabilities: any): void + /** + * Initialize the feature. This method is called on a feature instance + * when the client has successfully received the initialize request from + * the server and before the client sends the initialized notification + * to the server. + * + * @param capabilities the server capabilities. + * @param documentSelector the document selector pass to the client's constructor. + * May be `undefined` if the client was created without a selector. + */ + initialize(capabilities: any, documentSelector: DocumentSelector | undefined): void + /** + * The signature (e.g. method) for which this features support dynamic activation / registration. + */ + registrationType: RegistrationType + /** + * Is called when the server send a register request for the given message. + * + * @param data additional registration data as defined in the protocol. + */ + register(data: RegistrationData): void + /** + * Is called when the server wants to unregister a feature. + * + * @param id the id used when registering the feature. + */ + unregister(id: string): void + /** + * Called when the client is stopped to dispose this feature. Usually a feature + * unregisters listeners registered hooked up with the VS Code extension host. + */ + dispose(): void + } + + export interface NotificationFeature { + /** + * Triggers the corresponding RPC method. + */ + getProvider(document: TextDocument): { + send: T + } + } + + export interface ExecutableOptions { + cwd?: string + env?: any + detached?: boolean + shell?: boolean + } + + export interface Executable { + command: string + args?: string[] + options?: ExecutableOptions + } + + export interface ForkOptions { + cwd?: string + env?: any + execPath?: string + encoding?: string + execArgv?: string[] + } + + export interface StreamInfo { + writer: NodeJS.WritableStream + reader: NodeJS.ReadableStream + detached?: boolean + } + + export enum TransportKind { + stdio = 0, + ipc = 1, + pipe = 2, + socket = 3 + } + + export interface SocketTransport { + kind: TransportKind.socket + port: number + } + + export interface NodeModule { + module: string + transport?: TransportKind | SocketTransport + args?: string[] + runtime?: string + options?: ForkOptions + } + + export interface ChildProcessInfo { + process: cp.ChildProcess + detached: boolean + } + + export interface PartialMessageInfo { + readonly messageToken: number + readonly waitingTime: number + } + + export interface MessageReader { + readonly onError: Event + readonly onClose: Event + readonly onPartialMessage: Event + listen(callback: (data: { jsonrpc: string }) => void): void + dispose(): void + } + + export interface MessageWriter { + readonly onError: Event<[Error, { jsonrpc: string } | undefined, number | undefined]> + readonly onClose: Event + write(msg: { jsonrpc: string }): void + dispose(): void + } + + export class NullLogger { + constructor() + error(message: string): void + warn(message: string): void + info(message: string): void + log(message: string): void + } + + export interface MessageTransports { + reader: MessageReader + writer: MessageWriter + detached?: boolean + } + + export namespace MessageTransports { + /** + * Checks whether the given value conforms to the [MessageTransports](#MessageTransports) interface. + */ + function is(value: any): value is MessageTransports + } + + export type ServerOptions = Executable | NodeModule | { + run: Executable + debug: Executable + } | { + run: NodeModule + debug: NodeModule + } | (() => Promise) + + export interface _EM { + _$endMarker$_: number + } + + export class ProgressType

    { + /** + * Clients must not use this property. It is here to ensure correct typing. + */ + readonly __?: [P, _EM] + constructor() + } + + export enum Trace { + Off = 0, + Messages = 1, + Verbose = 2 + } + + /** + * A language server for manage a language server. + * It's recommended to use `services.registLanguageClient` for regist language client to serviers, + * you can have language client listed in `CocList services` and services could start the language client + * by `documentselector` of `clientOptions`. + */ + export class LanguageClient { + readonly id: string + readonly name: string + constructor(id: string, name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean) + /** + * Create language client by name and options, don't forget regist language client + * to services by `services.registLanguageClient` + */ + constructor(name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean) + /** + * R => result + * E => Error result + */ + sendRequest(type: RequestType0, token?: CancellationToken): Promise + /** + * P => params + * R => result + * E => Error result + */ + sendRequest(type: RequestType, params: P, token?: CancellationToken): Promise + sendRequest(method: string, token?: CancellationToken): Promise + sendRequest(method: string, param: any, token?: CancellationToken): Promise + + onRequest(type: RequestType0, handler: RequestHandler0): Disposable + onRequest(type: RequestType, handler: RequestHandler): Disposable + onRequest(method: string, handler: (...params: any[]) => HandlerResult): Disposable + + sendNotification(type: NotificationType0): void + sendNotification

    (type: NotificationType

    , params?: P): void + sendNotification(method: string): void + sendNotification(method: string, params: any): void + + onNotification(type: NotificationType0, handler: () => void): Disposable + onNotification

    (type: NotificationType

    , handler: (params: P) => void): Disposable + onNotification(method: string, handler: (...params: any[]) => void): Disposable + + onProgress

    (type: ProgressType, token: string | number, handler: (params: P) => void): Disposable + sendProgress

    (type: ProgressType

    , token: string | number, value: P): void + + /** + * Append info to outputChannel + */ + info(message: string, data?: any): void + /** + * Append warning to outputChannel + */ + warn(message: string, data?: any): void + /** + * append error to outputChannel + */ + error(message: string, data?: any): void + getPublicState(): State + get initializeResult(): InitializeResult | undefined + + get clientOptions(): LanguageClientOptions + /** + * Fired on language server state change. + */ + get onDidChangeState(): Event + get outputChannel(): OutputChannel + get diagnostics(): DiagnosticCollection | undefined + + /** + * Current running state. + */ + get serviceState(): ServiceStat + /** + * Check if server could start. + */ + needsStart(): boolean + /** + * Check if server could stop. + */ + needsStop(): boolean + onReady(): Promise + get started(): boolean + set trace(value: Trace) + + /** + * Stop language server. + */ + stop(): Promise + + /** + * Start language server, not needed when registered to services by `services.registLanguageClient` + */ + start(): Disposable + /** + * Restart language client. + */ + restart(): void + + /** + * Register custom feature. + */ + registerFeature(feature: StaticFeature | DynamicFeature): void + + /** + * Log failed request to outputChannel. + */ + handleFailedRequest(type: MessageSignature, token: CancellationToken | undefined, error: any, defaultValue: T) + } + + /** + * Monitor for setting change, restart language server when specified setting changed. + */ + export class SettingMonitor { + constructor(client: LanguageClient, setting: string) + start(): Disposable + } + // }} +} +// vim: set sw=2 ts=2 sts=2 et foldmarker={{,}} foldmethod=marker foldlevel=0 nofen: diff --git a/sources_non_forked/coc.nvim/yarn.lock b/sources_non_forked/coc.nvim/yarn.lock new file mode 100644 index 00000000..54f1590b --- /dev/null +++ b/sources_non_forked/coc.nvim/yarn.lock @@ -0,0 +1,3736 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + +"@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8" + integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.15.0" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.15.0", "@babel/generator@^7.7.2": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15" + integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== + dependencies: + "@babel/types" "^7.15.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-compilation-targets@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818" + integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4" + integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ== + dependencies: + "@babel/helper-get-function-arity" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-get-function-arity@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" + integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-hoist-variables@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" + integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-member-expression-to-functions@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b" + integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg== + dependencies: + "@babel/types" "^7.15.0" + +"@babel/helper-module-imports@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" + integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-module-transforms@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08" + integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-simple-access" "^7.14.8" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-optimise-call-expression@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c" + integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-replace-supers@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4" + integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-simple-access@^7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" + integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== + dependencies: + "@babel/types" "^7.14.8" + +"@babel/helper-split-export-declaration@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" + integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" + integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helpers@^7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.8.tgz#839f88f463025886cff7f85a35297007e2da1b77" + integrity sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw== + dependencies: + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.14.8" + "@babel/types" "^7.14.8" + +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.7.2": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" + integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/template@^7.14.5", "@babel/template@^7.3.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.14.8", "@babel/traverse@^7.15.0", "@babel/traverse@^7.7.2": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" + integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-hoist-variables" "^7.14.5" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@chemzqm/neovim@^5.7.9": + version "5.7.9" + resolved "https://registry.yarnpkg.com/@chemzqm/neovim/-/neovim-5.7.9.tgz#78cb54d07d8e24533177140371e3ac1d694ff5f7" + integrity sha512-ou2lI650Rh+/3tS8HuiVim73RJSkCoVqJsf+Mqyw17+CGxbcCmXQqA2stT81j3QAXsbCF+5Ro/z152TrQLUUBg== + dependencies: + msgpack-lite "^0.1.26" + +"@chemzqm/string-width@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@chemzqm/string-width/-/string-width-5.1.2.tgz#4e1f7e44827e1a68007b9a8674676e57d312da32" + integrity sha512-aQaaww4Grh1xSqis8hL+J7jZNTuyp/QADUel00ucNeUw9Ix16BLvdoc8Q0OiNU2uoLRlKf49nPT3WvfulYZgeQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^6.0.0" + +"@es-joy/jsdoccomment@~0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.29.0.tgz#527c7eefadeaf5c5d0c3b2721b5fa425d2119e98" + integrity sha512-4yKy5t+/joLihG+ei6CCU6sc08sjUdEdXCQ2U+9h9VP13EiqHQ4YMgDC18ys/AsLdJDBX3KRx/AWY6PR7hn52Q== + dependencies: + comment-parser "1.3.1" + esquery "^1.4.0" + jsdoc-type-pratt-parser "~3.0.1" + +"@eslint/eslintrc@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.2.tgz#4989b9e8c0216747ee7cca314ae73791bb281aae" + integrity sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" + integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.4.2.tgz#7a95612d38c007ddb528ee446fe5e5e785e685ce" + integrity sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.4.2" + jest-util "^27.4.2" + slash "^3.0.0" + +"@jest/core@^27.4.5": + version "27.4.5" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.4.5.tgz#cae2dc34259782f4866c6606c3b480cce920ed4c" + integrity sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ== + dependencies: + "@jest/console" "^27.4.2" + "@jest/reporters" "^27.4.5" + "@jest/test-result" "^27.4.2" + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.4.2" + jest-config "^27.4.5" + jest-haste-map "^27.4.5" + jest-message-util "^27.4.2" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.5" + jest-resolve-dependencies "^27.4.5" + jest-runner "^27.4.5" + jest-runtime "^27.4.5" + jest-snapshot "^27.4.5" + jest-util "^27.4.2" + jest-validate "^27.4.2" + jest-watcher "^27.4.2" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/create-cache-key-function@^27.4.2": + version "27.5.0" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.0.tgz#0f713af7f9d533f3f6c31130c87cd668d1e5fd06" + integrity sha512-ibNE/ngRfVJj4y5cf9QnBbVKovO44Hfw13mEVSJcO1+MYh31g1gh9mvWNmOmWZjiPTwaIBSoYfLvebGypzUbVw== + dependencies: + "@jest/types" "^27.5.0" + +"@jest/environment@^27.4.4": + version "27.4.4" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.4.4.tgz#66ebebc79673d84aad29d2bb70a8c51e6c29bb4d" + integrity sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ== + dependencies: + "@jest/fake-timers" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.2" + +"@jest/fake-timers@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.4.2.tgz#d217f86c3ba2027bf29e0b731fd0cb761a72d093" + integrity sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg== + dependencies: + "@jest/types" "^27.4.2" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.4.2" + jest-mock "^27.4.2" + jest-util "^27.4.2" + +"@jest/globals@^27.4.4": + version "27.4.4" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.4.4.tgz#fe501a80c23ea2dab585c42be2a519bb5e38530d" + integrity sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ== + dependencies: + "@jest/environment" "^27.4.4" + "@jest/types" "^27.4.2" + expect "^27.4.2" + +"@jest/reporters@^27.4.5": + version "27.4.5" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.4.5.tgz#e229acca48d18ea39e805540c1c322b075ae63ad" + integrity sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.4.2" + "@jest/test-result" "^27.4.2" + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^27.4.5" + jest-resolve "^27.4.5" + jest-util "^27.4.2" + jest-worker "^27.4.5" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.4.0": + version "27.4.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.4.0.tgz#2f0385d0d884fb3e2554e8f71f8fa957af9a74b6" + integrity sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.4.2.tgz#05fd4a5466ec502f3eae0b39dff2b93ea4d5d9ec" + integrity sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA== + dependencies: + "@jest/console" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.4.5": + version "27.4.5" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz#1d7e026844d343b60d2ca7fd82c579a17b445d7d" + integrity sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ== + dependencies: + "@jest/test-result" "^27.4.2" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.5" + jest-runtime "^27.4.5" + +"@jest/transform@^27.4.5": + version "27.4.5" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.4.5.tgz#3dfe2e3680cd4aa27356172bf25617ab5b94f195" + integrity sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.4.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.5" + jest-regex-util "^27.4.0" + jest-util "^27.4.2" + micromatch "^4.0.4" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.4.2", "@jest/types@^27.5.0": + version "27.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.0.tgz#6ad04a5c5355fd9f46e5cf761850e0edb3c209dd" + integrity sha512-oDHEp7gwSgA82RZ6pzUL3ugM2njP/lVB1MsxRZNOBk+CoNvh9SpH1lQixPFc/kDlV50v59csiW4HLixWmhmgPQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@swc/core-android-arm-eabi@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm-eabi/-/core-android-arm-eabi-1.2.183.tgz#7277b8d2f1e7033aa916331adba78a4b5bfc8d07" + integrity sha512-DzFR8sokjVESnSXWR/4hLDxPUuvFoTpAHbMEQjj6YrwiXeWQneFudATa0ysyGlszGrmlrT+yL5wrK+gp0M8+Kg== + +"@swc/core-android-arm64@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.183.tgz#4cdbcd9963de6d5f3a31f65deace3ffd652ad04c" + integrity sha512-LHDSXrtRLYvSbPU0Canp6kcanGbu5IdApvY/2njyLLlhi9GNg+0VJosc14O5sSid5qdg/mMaq4y6u1X6j8CxUw== + +"@swc/core-darwin-arm64@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.183.tgz#6293f0f62ab816bc75384b89eb9b2a36def88bd8" + integrity sha512-4UZhW/6DzcwFI5MQcGHEsjCDl32Ilfg09TOtr9IO9QK0nADE0Vy6K83ze8iXDIxVnu/jmc2rrX/FwmqRCS7F9w== + +"@swc/core-darwin-x64@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.183.tgz#bcf4fd6de262446c6cb77203a05c1d112b425b48" + integrity sha512-3BYS/4jkZAZbmrxXYeDAljjAbE/TAiEXIDKeGiRZ+nRk0sLNqwO30aWZl34U1CbzuK3gPcGHTEVuChUCoTkWKw== + +"@swc/core-freebsd-x64@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-freebsd-x64/-/core-freebsd-x64-1.2.183.tgz#fad84fca47ae078923c54b7784e9edda723b37b1" + integrity sha512-9nJqmFZzo2sCcRRZzKxYjEHE9dL3xj0vkELIkfDi7p1C+GpiwZTIh6s39KusnhY89s8igdYWnRyg/3d2FHsuFA== + +"@swc/core-linux-arm-gnueabihf@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.183.tgz#9d17505dc2997b7de7940e81f08385992e1c1d94" + integrity sha512-Bd0jwn715oqJTVICZiyWx6OYK7qAXZhJbpJLEekpkMfTyveLCnwyou+bwdldGPdqOHb+3q0Cg2eds1P0pXs9Xw== + +"@swc/core-linux-arm64-gnu@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.183.tgz#bcf2aa31e41ba17195ecfc669e42a38ab86f461c" + integrity sha512-QdQJyfL9nQPYMXdH2pdN6v0M0G8hdEY1g2Cao07CwNVGD0ZHURFY1GFPoyXLkVPVUqyvUPCRZSfC4fTUrKUFeA== + +"@swc/core-linux-arm64-musl@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.183.tgz#cf583e1a41821a438b4e790bb96c99b0e66366bc" + integrity sha512-hkDyhwgsK+MPZ47CSjk3VIrabX8xzuQHRAJoPseR/kTJ782ur19Dsun+7tVD8aSgmWjG7nBHYvsdF96jLLim6g== + +"@swc/core-linux-x64-gnu@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.183.tgz#30f56ddb20880d316733227349c410a4f7312889" + integrity sha512-jR6yjQWBm5q9wY4kXfT+3rKHoE9+ugGycaO/yuSeekxvs+dlEGcup0vu/VjfurnbfpAj7O2dnSKH7TE95wMkQg== + +"@swc/core-linux-x64-musl@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.183.tgz#4a5b9603276db97416739889899042521d58d155" + integrity sha512-4YM3TWishQal3qFsNwWXd47em2zTOShgkxUBm2SOGKtPCMsrfi9MJdesyQH5rCrNWGy1lvo7XpvnN2GSEzYjBQ== + +"@swc/core-win32-arm64-msvc@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.183.tgz#a79bb79edb2a24cbb198550ef58221c684ab33c4" + integrity sha512-mIXR1hPkNL2/v3xEcfbgZJclwMuQxJNVIHUyu6+cb8vUp4rbYoJioEi0qh613c36o9MpHccKZftMMd0buNFWXg== + +"@swc/core-win32-ia32-msvc@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.183.tgz#e6ae402c5e0c4be0f7e053ab53b5a1641535da9d" + integrity sha512-NokriuUcwOBdj6k6fpNrFcprv2FoHfyV6ymBaZuk8UXdoRhDFguoTsFxKxKo1oGyqYreuPmaK7NBU/H9SNRxDA== + +"@swc/core-win32-x64-msvc@1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.183.tgz#470d2daa8655d13c6c403ce52b47f919ac2c4b4b" + integrity sha512-oWiEDrUb4aRRc7y558KonVoFqmGXGKFvOj8ceiz4UVwoQCcwNX3djvjIf3zwkj+DwjKiHPFVwhENaRgMphthrA== + +"@swc/core@^1.2.183": + version "1.2.183" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.183.tgz#10f8471a587640fe86ab43d03771f72f3ef173db" + integrity sha512-RwAq9broU0YqoVJqPpTVxXFAj63+Fx1UWAtBsEqWyJQJc7RunuqNb2vMzp9X+5GeVr6yaa8qE7iKB99gp5enJg== + optionalDependencies: + "@swc/core-android-arm-eabi" "1.2.183" + "@swc/core-android-arm64" "1.2.183" + "@swc/core-darwin-arm64" "1.2.183" + "@swc/core-darwin-x64" "1.2.183" + "@swc/core-freebsd-x64" "1.2.183" + "@swc/core-linux-arm-gnueabihf" "1.2.183" + "@swc/core-linux-arm64-gnu" "1.2.183" + "@swc/core-linux-arm64-musl" "1.2.183" + "@swc/core-linux-x64-gnu" "1.2.183" + "@swc/core-linux-x64-musl" "1.2.183" + "@swc/core-win32-arm64-msvc" "1.2.183" + "@swc/core-win32-ia32-msvc" "1.2.183" + "@swc/core-win32-x64-msvc" "1.2.183" + +"@swc/jest@^0.2.21": + version "0.2.21" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.21.tgz#e8c4e234016a914f4cfbb7d75844860a250c1d1c" + integrity sha512-/+NcExiZbxXANNhNPnIdFuGq62CeumulLS1bngwqIXd8H7d96LFUfrYzdt8tlTwLMel8tFtQ5aRjzVkyOTyPDw== + dependencies: + "@jest/create-cache-key-function" "^27.4.2" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.15" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024" + integrity sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/cli-table@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/cli-table/-/cli-table-0.3.0.tgz#f1857156bf5fd115c6a2db260ba0be1f8fc5671c" + integrity sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ== + +"@types/debounce@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-3.0.0.tgz#ea4290f6e2d7ab99464c93b4a69b843d0993b181" + integrity sha512-SbehVj+zL0QFTufW3HP/Xvwr/kFWw1sFMLCvmyJdp5Xegbo81sqA2tByWlyeryvSwWBrY4drpLOtGPh0fkxjCQ== + +"@types/fb-watchman@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/fb-watchman/-/fb-watchman-2.0.1.tgz#4f44c7b7ac98463488765d41d269272dd34cb815" + integrity sha512-iJ7/e6drSmuCzAp96/dpksm8YjxbhhyXWV6m1HPbRHvZwUOUZ5vZvZIAUJxKDtI0UpdNfDvLPiai0MTJmmS+HA== + +"@types/fs-extra@^9.0.6": + version "9.0.12" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" + integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== + dependencies: + "@types/node" "*" + +"@types/glob@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.0.3": + version "27.0.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a" + integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + +"@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/marked@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.1.tgz#d588a7bbc4d6551c5e75249bc106ffda96ae33c5" + integrity sha512-ZigEmCWdNUU7IjZEuQ/iaimYdDHWHfTe3kg8ORfKjyGYd9RWumPoOJRQXB0bO+XLkNwzCthW3wUIQtANaEZ1ag== + +"@types/minimatch@*", "@types/minimatch@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/minipass@*": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/minipass/-/minipass-2.2.1.tgz#a52138867c493ff14f07616efcbe2af7662b76fb" + integrity sha512-0bI74UwEJ+JjGqzkyoiCxLVGK5C3Vy5MYdDB6VCtUAulcrulHvqhIrQP9lh/gvMgaNzvvJljMW97rRHVvbTe8Q== + dependencies: + "@types/node" "*" + +"@types/mkdirp@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-1.0.2.tgz#8d0bad7aa793abe551860be1f7ae7f3198c16666" + integrity sha512-o0K1tSO0Dx5X6xlU5F1D6625FawhC3dU3iqr25lluNv/+/QIVH8RLNEiVokgIZo+mz+87w/3Mkg/VvQS+J51fQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@12.12.12": + version "12.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.12.tgz#529bc3e73dbb35dd9e90b0a1c83606a9d3264bdb" + integrity sha512-MGuvYJrPU0HUwqF7LqvIj50RZUX23Z+m583KBygKYUZLlZ88n6w28XRNJRJgsHukLEnLz6w6SvxZoLgbr5wLqQ== + +"@types/prettier@^2.1.5": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" + integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== + +"@types/semver@^7.3.4": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.8.tgz#508a27995498d7586dcecd77c25e289bfaf90c59" + integrity sha512-D/2EJvAlCEtYFEYmmlGwbGXuK886HzyCc3nZX/tkFTQdEU8jZDAgiv08P162yB17y4ZXZoq7yFAnW4GDBb9Now== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/tar@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.5.tgz#5f953f183e36a15c6ce3f336568f6051b7b183f3" + integrity sha512-cgwPhNEabHaZcYIy5xeMtux2EmYBitfqEceBUi2t5+ETy4dW6kswt6WX4+HqLeiiKOo42EXbGiDmVJ2x+vi37Q== + dependencies: + "@types/minipass" "*" + "@types/node" "*" + +"@types/uuid@^8.3.0": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" + integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== + +"@types/which@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf" + integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA== + +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz#022531a639640ff3faafaf251d1ce00a2ef000a1" + integrity sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q== + dependencies: + "@typescript-eslint/scope-manager" "5.20.0" + "@typescript-eslint/type-utils" "5.20.0" + "@typescript-eslint/utils" "5.20.0" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.20.0.tgz#4991c4ee0344315c2afc2a62f156565f689c8d0b" + integrity sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w== + dependencies: + "@typescript-eslint/scope-manager" "5.20.0" + "@typescript-eslint/types" "5.20.0" + "@typescript-eslint/typescript-estree" "5.20.0" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz#79c7fb8598d2942e45b3c881ced95319818c7980" + integrity sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg== + dependencies: + "@typescript-eslint/types" "5.20.0" + "@typescript-eslint/visitor-keys" "5.20.0" + +"@typescript-eslint/type-utils@5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.20.0.tgz#151c21cbe9a378a34685735036e5ddfc00223be3" + integrity sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw== + dependencies: + "@typescript-eslint/utils" "5.20.0" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.20.0.tgz#fa39c3c2aa786568302318f1cb51fcf64258c20c" + integrity sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg== + +"@typescript-eslint/typescript-estree@5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz#ab73686ab18c8781bbf249c9459a55dc9417d6b0" + integrity sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w== + dependencies: + "@typescript-eslint/types" "5.20.0" + "@typescript-eslint/visitor-keys" "5.20.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.20.0", "@typescript-eslint/utils@^5.10.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.20.0.tgz#b8e959ed11eca1b2d5414e12417fd94cae3517a5" + integrity sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.20.0" + "@typescript-eslint/types" "5.20.0" + "@typescript-eslint/typescript-estree" "5.20.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.20.0": + version "5.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz#70236b5c6b67fbaf8b2f58bf3414b76c1e826c2a" + integrity sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg== + dependencies: + "@typescript-eslint/types" "5.20.0" + eslint-visitor-keys "^3.0.0" + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +babel-jest@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.4.5.tgz#d38bd0be8ea71d8b97853a5fc9f76deeb095c709" + integrity sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA== + dependencies: + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^27.4.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" + integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" + integrity sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg== + dependencies: + babel-plugin-jest-hoist "^27.4.0" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.16.6: + version "4.16.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" + integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== + dependencies: + caniuse-lite "^1.0.30001219" + colorette "^1.2.2" + electron-to-chromium "^1.3.723" + escalade "^3.1.1" + node-releases "^1.1.71" + +bser@2.1.1, bser@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= + +bytes@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-lite@^1.0.30001219: + version "1.0.30001300" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz#11ab6c57d3eb6f964cba950401fd00a146786468" + integrity sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA== + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= + dependencies: + traverse ">=0.3.0 <0.4" + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cli-table@^0.3.4: + version "0.3.6" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.6.tgz#e9d6aa859c7fe636981fd3787378c2a20bce92fc" + integrity sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ== + dependencies: + colors "1.0.3" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +comment-parser@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" + integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +content-disposition@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +date-format@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.3.tgz#f63de5dc08dc02efd8ef32bf2a6918e486f35873" + integrity sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ== + +debounce@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.3.723: + version "1.3.787" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.787.tgz#0d814dcc374bb8a0ae7a17c0308c39fb18fcc7bb" + integrity sha512-zeM5AFwvTlSYvGpBaFZKVo7GQEWSk6hS3rQ7mdrr3qB7CiqVl84K6nIPznyKSu0b8ABiEeMEIqyBuzqMkxnjjg== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +esbuild-android-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz#d532d38cb5fe0ae45167ce35f4bbc784c636be40" + integrity sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ== + +esbuild-android-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz#9c5bb3366aabfd14a1c726d36978b79441dfcb6e" + integrity sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw== + +esbuild-darwin-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz#05dcdb6d884f427039ffee5e92ff97527e56c26d" + integrity sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA== + +esbuild-darwin-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz#28e080da4ea0cfe9498071e7f8060498caee1a95" + integrity sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw== + +esbuild-freebsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz#200d3664a3b945bc9fdcba73614b49a11ebd1cfa" + integrity sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ== + +esbuild-freebsd-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz#624b08c5da6013bdc312aaa23c4ff409580f5c3c" + integrity sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug== + +esbuild-linux-32@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz#0238e597eb0b60aa06c7e98fccbbfd6bb9a0d6c5" + integrity sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw== + +esbuild-linux-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz#8a8b8cf47dfce127c858e71229d9a385a82c62e8" + integrity sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug== + +esbuild-linux-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz#7ac94371418a2640ba413bc1700aaedeb2794e52" + integrity sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw== + +esbuild-linux-arm@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz#034bd18e9310b9f010c89f90ef7f05706689600b" + integrity sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw== + +esbuild-linux-mips64le@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz#05f98a8cf6b578eab6b4e6b0ab094f37530934f4" + integrity sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ== + +esbuild-linux-ppc64le@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz#46fd0add8d8535678439d7a9c2876ad20042d952" + integrity sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw== + +esbuild-linux-riscv64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz#ea2e986f0f3e5df73c635135dd778051734fc605" + integrity sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w== + +esbuild-linux-s390x@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz#efe89486e9a1b1508925048076e3f3a6698aa6a3" + integrity sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ== + +esbuild-netbsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz#439fe27d8ee3b5887501ee63988e85f920107db6" + integrity sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA== + +esbuild-openbsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz#31ebf616aadf6e60674469f2b92cec92280d9930" + integrity sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A== + +esbuild-sunos-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz#815e4f936d74970292a63ccfd5791fe5e3569f5f" + integrity sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw== + +esbuild-windows-32@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz#189e14df2478f2c193c86968ab1fb54e1ceaafd2" + integrity sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA== + +esbuild-windows-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz#3d5fbfdc3856850bb47439299e3b60dd18be111f" + integrity sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA== + +esbuild-windows-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz#8b243cbbad8a86cf98697da9ccb88c05df2ef458" + integrity sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA== + +esbuild@^0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.25.tgz#ddb9d47b91ca76abb7d850ce3dfed0bc3dc88d16" + integrity sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q== + optionalDependencies: + esbuild-android-64 "0.14.25" + esbuild-android-arm64 "0.14.25" + esbuild-darwin-64 "0.14.25" + esbuild-darwin-arm64 "0.14.25" + esbuild-freebsd-64 "0.14.25" + esbuild-freebsd-arm64 "0.14.25" + esbuild-linux-32 "0.14.25" + esbuild-linux-64 "0.14.25" + esbuild-linux-arm "0.14.25" + esbuild-linux-arm64 "0.14.25" + esbuild-linux-mips64le "0.14.25" + esbuild-linux-ppc64le "0.14.25" + esbuild-linux-riscv64 "0.14.25" + esbuild-linux-s390x "0.14.25" + esbuild-netbsd-64 "0.14.25" + esbuild-openbsd-64 "0.14.25" + esbuild-sunos-64 "0.14.25" + esbuild-windows-32 "0.14.25" + esbuild-windows-64 "0.14.25" + esbuild-windows-arm64 "0.14.25" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-plugin-jest@^26.1.5: + version "26.1.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.1.5.tgz#6cfca264818d6d6aa120b019dab4d62b6aa8e775" + integrity sha512-su89aDuljL9bTjEufTXmKUMSFe2kZUL9bi7+woq+C2ukHZordhtfPm4Vg+tdioHBaKf8v3/FXW9uV0ksqhYGFw== + dependencies: + "@typescript-eslint/utils" "^5.10.0" + +eslint-plugin-jsdoc@^39.2.8: + version "39.2.8" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.2.8.tgz#09afbf581cdb5f1b65689201e693708c474d7a65" + integrity sha512-uZM+VIWRpwoaIMuuHW2XaMhQ6NXonDiXxKZ3ebgH7JmnBLElib4zln5Tqt3IjvZbS7eqQUOnQ1nM7D4JOk3erA== + dependencies: + "@es-joy/jsdoccomment" "~0.29.0" + comment-parser "1.3.1" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.4.0" + semver "^7.3.7" + spdx-expression-parse "^3.0.1" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.14.0.tgz#62741f159d9eb4a79695b28ec4989fcdec623239" + integrity sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw== + dependencies: + "@eslint/eslintrc" "^1.2.2" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +event-lite@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/event-lite/-/event-lite-0.1.2.tgz#838a3e0fdddef8cc90f128006c8e55a4e4e4c11b" + integrity sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.2.tgz#4429b0f7e307771d176de9bdf23229b101db6ef6" + integrity sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg== + dependencies: + "@jest/types" "^27.4.2" + ansi-styles "^5.0.0" + jest-get-type "^27.4.0" + jest-matcher-utils "^27.4.2" + jest-message-util "^27.4.2" + jest-regex-util "^27.4.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.1.1: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.1.tgz#5d8175aae17db61947f8b162cfc7f63264d22807" + integrity sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0, fb-watchman@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0, flatted@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + +follow-redirects@^1.14.8: + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.10.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.10.0.tgz#60ba56c3ac2ca845cfbf4faeca727ad9dd204676" + integrity sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.4: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.8: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +int64-buffer@^0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.10.tgz#277b228a87d95ad777d07c13832022406a473423" + integrity sha1-J3siiofZWtd30HwTgyAiQGpHNCM= + +is-core-module@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" + integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +isuri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/isuri/-/isuri-2.0.3.tgz#3437121db2fe65af0ba080b7e1a8636f632cca91" + integrity sha1-NDcSHbL+Za8LoIC34ahjb2MsypE= + dependencies: + rfc-3986 "1.0.1" + +jest-changed-files@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" + integrity sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A== + dependencies: + "@jest/types" "^27.4.2" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.4.5.tgz#70bfb78e0200cab9b84747bf274debacaa538467" + integrity sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw== + dependencies: + "@jest/environment" "^27.4.4" + "@jest/test-result" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.4.2" + is-generator-fn "^2.0.0" + jest-each "^27.4.2" + jest-matcher-utils "^27.4.2" + jest-message-util "^27.4.2" + jest-runtime "^27.4.5" + jest-snapshot "^27.4.5" + jest-util "^27.4.2" + pretty-format "^27.4.2" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.4.5.tgz#8708f54c28d13681f3255ec9026a2b15b03d41e8" + integrity sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg== + dependencies: + "@jest/core" "^27.4.5" + "@jest/test-result" "^27.4.2" + "@jest/types" "^27.4.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.4.5" + jest-util "^27.4.2" + jest-validate "^27.4.2" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.4.5.tgz#77ed7f2ba7bcfd7d740ade711d0d13512e08a59e" + integrity sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^27.4.5" + "@jest/types" "^27.4.2" + babel-jest "^27.4.5" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-circus "^27.4.5" + jest-environment-jsdom "^27.4.4" + jest-environment-node "^27.4.4" + jest-get-type "^27.4.0" + jest-jasmine2 "^27.4.5" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.5" + jest-runner "^27.4.5" + jest-util "^27.4.2" + jest-validate "^27.4.2" + micromatch "^4.0.4" + pretty-format "^27.4.2" + slash "^3.0.0" + +jest-diff@^27.0.0, jest-diff@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.2.tgz#786b2a5211d854f848e2dcc1e324448e9481f36f" + integrity sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.4.0" + jest-get-type "^27.4.0" + pretty-format "^27.4.2" + +jest-docblock@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" + integrity sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.4.2.tgz#19364c82a692d0d26557642098d1f4619c9ee7d3" + integrity sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + jest-get-type "^27.4.0" + jest-util "^27.4.2" + pretty-format "^27.4.2" + +jest-environment-jsdom@^27.4.4: + version "27.4.4" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz#94f738e99514d7a880e8ed8e03e3a321d43b49db" + integrity sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA== + dependencies: + "@jest/environment" "^27.4.4" + "@jest/fake-timers" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.2" + jest-util "^27.4.2" + jsdom "^16.6.0" + +jest-environment-node@^27.4.4: + version "27.4.4" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.4.4.tgz#42fe5e3b224cb69b99811ebf6f5eaa5a59618514" + integrity sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA== + dependencies: + "@jest/environment" "^27.4.4" + "@jest/fake-timers" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.2" + jest-util "^27.4.2" + +jest-get-type@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== + +jest-haste-map@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.5.tgz#c2921224a59223f91e03ec15703905978ef0cc1a" + integrity sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q== + dependencies: + "@jest/types" "^27.4.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.4.0" + jest-serializer "^27.4.0" + jest-util "^27.4.2" + jest-worker "^27.4.5" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz#ff79d11561679ff6c89715b0cd6b1e8c0dfbc6dc" + integrity sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^27.4.4" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.4.2" + is-generator-fn "^2.0.0" + jest-each "^27.4.2" + jest-matcher-utils "^27.4.2" + jest-message-util "^27.4.2" + jest-runtime "^27.4.5" + jest-snapshot "^27.4.5" + jest-util "^27.4.2" + pretty-format "^27.4.2" + throat "^6.0.1" + +jest-leak-detector@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz#7fc3120893a7a911c553f3f2bdff9faa4454abbb" + integrity sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw== + dependencies: + jest-get-type "^27.4.0" + pretty-format "^27.4.2" + +jest-matcher-utils@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz#d17c5038607978a255e0a9a5c32c24e984b6c60b" + integrity sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ== + dependencies: + chalk "^4.0.0" + jest-diff "^27.4.2" + jest-get-type "^27.4.0" + pretty-format "^27.4.2" + +jest-message-util@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.4.2.tgz#07f3f1bf207d69cf798ce830cc57f1a849f99388" + integrity sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.4.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.4.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.4.2.tgz#184ff197a25491bfe4570c286daa5d62eb760b88" + integrity sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" + integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== + +jest-resolve-dependencies@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz#9398af854bdb12d6a9e5a8a536ee401f889a3ecf" + integrity sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w== + dependencies: + "@jest/types" "^27.4.2" + jest-regex-util "^27.4.0" + jest-snapshot "^27.4.5" + +jest-resolve@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.4.5.tgz#8dc44f5065fb8d58944c20f932cb7b9fe9760cca" + integrity sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.5" + jest-pnp-resolver "^1.2.2" + jest-util "^27.4.2" + jest-validate "^27.4.2" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.4.5.tgz#daba2ba71c8f34137dc7ac45616add35370a681e" + integrity sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg== + dependencies: + "@jest/console" "^27.4.2" + "@jest/environment" "^27.4.4" + "@jest/test-result" "^27.4.2" + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.4.0" + jest-environment-jsdom "^27.4.4" + jest-environment-node "^27.4.4" + jest-haste-map "^27.4.5" + jest-leak-detector "^27.4.2" + jest-message-util "^27.4.2" + jest-resolve "^27.4.5" + jest-runtime "^27.4.5" + jest-util "^27.4.2" + jest-worker "^27.4.5" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.4.5.tgz#97703ad2a1799d4f50ab59049bd21a9ceaed2813" + integrity sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ== + dependencies: + "@jest/console" "^27.4.2" + "@jest/environment" "^27.4.4" + "@jest/globals" "^27.4.4" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.2" + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.5" + jest-message-util "^27.4.2" + jest-mock "^27.4.2" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.5" + jest-snapshot "^27.4.5" + jest-util "^27.4.2" + jest-validate "^27.4.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^16.2.0" + +jest-serializer@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" + integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.4.5.tgz#2ea909b20aac0fe62504bc161331f730b8a7ecc7" + integrity sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/parser" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.4.5" + "@jest/types" "^27.4.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.4.2" + graceful-fs "^4.2.4" + jest-diff "^27.4.2" + jest-get-type "^27.4.0" + jest-haste-map "^27.4.5" + jest-matcher-utils "^27.4.2" + jest-message-util "^27.4.2" + jest-resolve "^27.4.5" + jest-util "^27.4.2" + natural-compare "^1.4.0" + pretty-format "^27.4.2" + semver "^7.3.2" + +jest-util@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" + +jest-validate@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.4.2.tgz#eecfcc1b1c9429aa007da08a2bae4e32a81bbbc3" + integrity sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A== + dependencies: + "@jest/types" "^27.4.2" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.4.0" + leven "^3.1.0" + pretty-format "^27.4.2" + +jest-watcher@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.4.2.tgz#c9037edfd80354c9fe90de4b6f8b6e2b8e736744" + integrity sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg== + dependencies: + "@jest/test-result" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.4.2" + string-length "^4.0.1" + +jest-worker@^27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.5.tgz#d696e3e46ae0f24cff3fa7195ffba22889262242" + integrity sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@27.4.5: + version "27.4.5" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.4.5.tgz#66e45acba44137fac26be9d3cc5bb031e136dc0f" + integrity sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg== + dependencies: + "@jest/core" "^27.4.5" + import-local "^3.0.2" + jest-cli "^27.4.5" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdoc-type-pratt-parser@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.0.1.tgz#ccbc7a4180bc8748af64d2cc431aaa92f88175bb" + integrity sha512-vqMCdAFVIiFhVgBYE/X8naf3L/7qiJsaYWTfUJZZZ124dR3OUz9HrmaMUGpYIYAN4VSuodf6gIZY0e8ktPw9cg== + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonc-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" + integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log4js@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.4.0.tgz#3f63ccfc8033c83cd617a4d2d50e48be5944eae9" + integrity sha512-ysc/XUecZJuN8NoKOssk3V0cQ29xY4fra6fnigZa5VwxFsCsvdqsdnEuAxNN89LlHpbE4KUD3zGcn+kFqonSVQ== + dependencies: + date-format "^4.0.3" + debug "^4.3.3" + flatted "^3.2.4" + rfdc "^1.3.0" + streamroller "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +marked@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d" + integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" + integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== + +mime-types@^2.1.12: + version "2.1.31" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" + integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== + dependencies: + mime-db "1.48.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +minipass@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +msgpack-lite@^0.1.26: + version "0.1.26" + resolved "https://registry.yarnpkg.com/msgpack-lite/-/msgpack-lite-0.1.26.tgz#dd3c50b26f059f25e7edee3644418358e2a9ad89" + integrity sha1-3TxQsm8FnyXn7e42REGDWOKprYk= + dependencies: + event-lite "^0.1.1" + ieee754 "^1.1.8" + int64-buffer "^0.1.9" + isarray "^1.0.0" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^1.1.71: + version "1.1.73" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" + integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.0.4, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +pretty-format@^27.0.0, pretty-format@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.2.tgz#e4ce92ad66c3888423d332b40477c87d1dac1fb8" + integrity sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw== + dependencies: + "@jest/types" "^27.4.2" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +prompts@^2.0.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" + integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfc-3986@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rfc-3986/-/rfc-3986-1.0.1.tgz#eeeb88342fadbe8027c0f36ada921a13e6f96206" + integrity sha1-7uuINC+tvoAnwPNq2pIaE+b5YgY= + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@^0.5.6: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" + integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stack-utils@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" + integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw== + dependencies: + escape-string-regexp "^2.0.0" + +streamroller@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.0.2.tgz#30418d0eee3d6c93ec897f892ed098e3a81e68b7" + integrity sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA== + dependencies: + date-format "^4.0.3" + debug "^4.1.1" + fs-extra "^10.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tar@^6.1.9: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typescript@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== + +unidecode@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/unidecode/-/unidecode-0.1.8.tgz#efbb301538bc45246a9ac8c559d72f015305053e" + integrity sha1-77swFTi8RSRqmsjFWdcvAVMFBT4= + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unzip-stream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/unzip-stream/-/unzip-stream-0.3.1.tgz#2333b5cd035d29db86fb701ca212cf8517400083" + integrity sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw== + dependencies: + binary "^0.3.0" + mkdirp "^0.5.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +uuid@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +vscode-jsonrpc@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" + integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== + +vscode-languageserver-protocol@3.16.0, vscode-languageserver-protocol@^3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" + integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== + dependencies: + vscode-jsonrpc "6.0.0" + vscode-languageserver-types "3.16.0" + +vscode-languageserver-textdocument@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.3.tgz#879f2649bfa5a6e07bc8b392c23ede2dfbf43eff" + integrity sha512-ynEGytvgTb6HVSUwPJIAZgiHQmPCx8bZ8w5um5Lz+q5DjP0Zj8wTFhQpyg8xaMvefDytw2+HH5yzqS+FhsR28A== + +vscode-languageserver-types@3.16.0, vscode-languageserver-types@^3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" + integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== + +vscode-languageserver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" + integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== + dependencies: + vscode-languageserver-protocol "3.16.0" + +vscode-uri@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" + integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" + integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" diff --git a/sources_non_forked/rust.vim/test/run-tests b/sources_non_forked/rust.vim/test/run-tests old mode 100644 new mode 100755