├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── basic.language-configuration.json ├── bliss.language-configuration.json ├── cld.language-configuration.json ├── cobol.language-configuration.json ├── fortran.language-configuration.json ├── gulpfile.js ├── i18n └── ru │ ├── cld │ ├── AnalysisListener.i18n.json │ ├── SourceContext.i18n.json │ ├── Symbol.i18n.json │ └── extension.i18n.json │ ├── config-helper │ ├── config │ │ ├── config-api.i18n.json │ │ └── config-pool.i18n.json │ └── extension.i18n.json │ ├── extension.i18n.json │ ├── msg │ ├── AnalysisListener.i18n.json │ ├── SourceContext.i18n.json │ ├── Symbol.i18n.json │ └── extension.i18n.json │ ├── package.i18n.json │ ├── python │ ├── debugSession.i18n.json │ ├── extension.i18n.json │ ├── provider.i18n.json │ └── runtime.i18n.json │ ├── ssh-helper │ ├── config-resolve │ │ ├── connect-config-resolver-impl.i18n.json │ │ ├── password-console-filler.i18n.json │ │ └── password-vscode-filler.i18n.json │ ├── extension.i18n.json │ ├── ssh-helper.i18n.json │ └── stream │ │ ├── parse-welcome-vms.i18n.json │ │ ├── parse-welcome.i18n.json │ │ ├── pipe.i18n.json │ │ ├── sftp-client.i18n.json │ │ ├── shell-parser.i18n.json │ │ ├── ssh-client.i18n.json │ │ └── ssh-shell.i18n.json │ ├── synchronizer │ ├── build │ │ └── builder.i18n.json │ ├── common │ │ └── find-files.i18n.json │ ├── dep-tree │ │ └── project-descr.i18n.json │ ├── downloadHeaders.i18n.json │ ├── ensure-settings.i18n.json │ ├── extension.i18n.json │ ├── performer.i18n.json │ ├── scopeWatchers.i18n.json │ ├── sync │ │ ├── fs-source.i18n.json │ │ └── synchronizer.i18n.json │ └── upload-zip.i18n.json │ ├── vms_basic │ └── context │ │ └── SourceContext.i18n.json │ ├── vms_cobol │ ├── context │ │ ├── CobolAnalisisHelpers.i18n.json │ │ ├── CobolAnalysisVisitor.i18n.json │ │ └── CobolSourceContext.i18n.json │ ├── extension.i18n.json │ └── stream │ │ └── cobolInputStream.i18n.json │ ├── vms_debug │ ├── debug │ │ ├── vms_runtime.i18n.json │ │ └── vms_runtime_run.i18n.json │ ├── extension.i18n.json │ ├── net │ │ └── shell-session.i18n.json │ └── parsers │ │ └── debug_module_info.i18n.json │ ├── vms_fortran │ └── context │ │ └── SourceContext.i18n.json │ ├── vms_jvm_debug │ ├── extension.i18n.json │ ├── jvm-debug-session.i18n.json │ ├── jvm-proj-helper.i18n.json │ ├── jvm-project.i18n.json │ └── jvm-shell-runtime.i18n.json │ └── vms_pascal │ └── context │ └── SourceContext.i18n.json ├── images ├── mock-debug-icon.png ├── vms_128x128_v2.png └── vms_logo.png ├── make_async.txt ├── media ├── dep.png └── dep.svg ├── mms.language-configuration.json ├── msg.language-configuration.json ├── package.json ├── package.nls.json ├── package.nls.ru.json ├── pascal.language-configuration.json ├── python ├── server.py └── tracer.py ├── readme.txt ├── resources ├── build_1.png ├── build_28x28.png ├── dark │ ├── boolean.svg │ ├── dependency.svg │ ├── document.svg │ ├── folder.svg │ ├── number.svg │ ├── refresh.svg │ └── string.svg ├── default.mms ├── light │ ├── boolean.svg │ ├── dependency.svg │ ├── document.svg │ ├── folder.svg │ ├── number.svg │ ├── refresh.svg │ └── string.svg ├── package-explorer.png ├── ssh_schema.json ├── static.mms └── synch_schema.json ├── src ├── cld │ ├── AnalysisListener.ts │ ├── CompletionProvider.ts │ ├── ContextErrorListener.ts │ ├── ContextSymbolTable.ts │ ├── DefinitionProvider.ts │ ├── DetailsListener.ts │ ├── Facade.ts │ ├── HoverProvider.ts │ ├── ReferenceProvider.ts │ ├── RenameProvider.ts │ ├── SourceContext.ts │ ├── Symbol.ts │ ├── cld.g4 │ ├── cld.interp │ ├── cld.tokens │ ├── cldLexer.interp │ ├── cldLexer.tokens │ ├── cldLexer.ts │ ├── cldListener.ts │ ├── cldParser.ts │ ├── cldVisitor.ts │ └── extension.ts ├── common │ ├── async-task-queue.ts │ ├── barrier.ts │ ├── bsearch.ts │ ├── correspondLines.ts │ ├── cr-lf-trimmed-eq.ts │ ├── debouncer.ts │ ├── delay.ts │ ├── directory.ts │ ├── iterators.ts │ ├── lock.ts │ ├── log-type.ts │ ├── log.ts │ ├── main.ts │ ├── mem-reader.ts │ ├── mem-writer.ts │ ├── parser │ │ ├── CompletionProvider.ts │ │ ├── DefinitionProvider.ts │ │ ├── ErrorListeners.ts │ │ ├── Facade.ts │ │ ├── HoverProvider.ts │ │ ├── ReferenceProvider.ts │ │ ├── RenameProvider.ts │ │ └── helpers.ts │ ├── print-like.ts │ ├── print-syntax-tree.ts │ ├── quotes.ts │ ├── read_all_stream.ts │ ├── resolve.ts │ ├── rgx-from-str.ts │ ├── simply-compare.ts │ ├── subscribe.ts │ ├── task-count.ts │ ├── task-divider.ts │ ├── wait-fire-event-emitter.ts │ └── waitable-operation.ts ├── config-helper │ ├── command-context.ts │ ├── config │ │ ├── config-api.ts │ │ ├── config-hepler-section.ts │ │ ├── config-pool.ts │ │ ├── config.ts │ │ ├── dummy-editor.ts │ │ ├── dummy-storage.ts │ │ ├── fs-config-helper.ts │ │ ├── fs-storage.ts │ │ ├── storage-impl.ts │ │ ├── uri-editor.ts │ │ ├── vfs-config-helper.ts │ │ ├── vfs-storage.ts │ │ ├── vsc-config-helper.ts │ │ ├── vsc-editor.ts │ │ └── vsc-storage.ts │ ├── extension.ts │ └── log.ts ├── ext-api │ └── ext-api.ts ├── extension.ts ├── msg │ ├── AnalysisListener.ts │ ├── CompletionProvider.ts │ ├── ContextErrorListener.ts │ ├── ContextSymbolTable.ts │ ├── DefinitionProvider.ts │ ├── Facade.ts │ ├── HoverProvider.ts │ ├── RenameProvider.ts │ ├── SourceContext.ts │ ├── Symbol.ts │ ├── extension.ts │ ├── msg.g4 │ ├── msg.interp │ ├── msg.tokens │ ├── msgLex.g4 │ ├── msgLex.interp │ ├── msgLex.tokens │ ├── msgLex.ts │ ├── msgListener.ts │ ├── msgParser.ts │ └── msgVisitor.ts ├── python │ ├── debugConfig.ts │ ├── debugSession.ts │ ├── extension.ts │ ├── provider.ts │ └── runtime.ts ├── ssh-helper │ ├── api.ts │ ├── config-api.ts │ ├── config-resolve │ │ ├── agent-filler.ts │ │ ├── connect-config-resolver-impl.ts │ │ ├── context-password-filler.ts │ │ ├── host-filler.ts │ │ ├── key-filler.ts │ │ ├── password-console-filler.ts │ │ ├── password-filler.ts │ │ ├── password-vscode-filler.ts │ │ └── settings-filler.ts │ ├── config │ │ └── sections │ │ │ ├── connection.ts │ │ │ ├── hosts.ts │ │ │ ├── labeled-connection.ts │ │ │ ├── terminal.ts │ │ │ └── timeouts.ts │ ├── extension.ts │ ├── ssh-helper.ts │ ├── stream │ │ ├── parse-welcome-vms.ts │ │ ├── parse-welcome.ts │ │ ├── pipe.ts │ │ ├── prompt-catcher-vms.ts │ │ ├── prompt-catcher.ts │ │ ├── sftp-client.ts │ │ ├── shell-parser.ts │ │ ├── ssh-client.ts │ │ ├── ssh-shell.ts │ │ └── stream-creators.ts │ └── test │ │ ├── config-resolver.test.ts │ │ ├── config │ │ └── config.ts │ │ ├── lock.test.ts │ │ ├── sftp-pipe.test.ts │ │ ├── sftp-shell-transform.test.ts │ │ └── sftp-shell.test.ts ├── synchronizer │ ├── build │ │ └── builder.ts │ ├── change-crlf.ts │ ├── command-context.ts │ ├── common │ │ ├── TestExecResult.ts │ │ ├── create-file.ts │ │ ├── find-files.ts │ │ ├── parse-output.ts │ │ └── progress.ts │ ├── config │ │ └── sections │ │ │ ├── builds.ts │ │ │ ├── project.ts │ │ │ └── synchronize.ts │ ├── context.ts │ ├── dep-tree │ │ ├── dep-tree.ts │ │ ├── proj-dep-tree.ts │ │ ├── proj-state.ts │ │ ├── project-dep.ts │ │ └── project-descr.ts │ ├── downloadHeaders.ts │ ├── ensure-settings.ts │ ├── extension.ts │ ├── on-the-same-vms.ts │ ├── performer.ts │ ├── projectDepend.ts │ ├── scopeWatchers.ts │ ├── sync │ │ ├── fs-source.ts │ │ ├── sftp-source.ts │ │ ├── source.ts │ │ ├── sync-api.ts │ │ ├── synchronizer.ts │ │ ├── vms-sftp-client.ts │ │ └── vms-shell-source.ts │ ├── test │ │ ├── config │ │ │ └── vms.ts │ │ ├── find-files.test.ts │ │ ├── problem.test.ts │ │ ├── sftp-readdir.test.ts │ │ └── source.test.ts │ ├── upload-zip.ts │ └── vms │ │ ├── vms-absolute-date-string.ts │ │ └── vms-path-converter.ts ├── task2cmd │ ├── extension.ts │ └── task2cmd-prov.ts ├── test │ ├── .gitignore │ ├── a.a.test.ts │ ├── a.diff.test.ts │ ├── cobol-unit.test.ts │ ├── cobol.test.ts │ ├── lock.test.ts │ ├── long.test.ts │ └── quotes.test.ts ├── vms_basic │ ├── context │ │ ├── AnalysisListener.ts │ │ ├── ContextErrorListener.ts │ │ ├── ContextSymbolTable.ts │ │ ├── DetailsListener.ts │ │ ├── Facade.ts │ │ ├── SourceContext.ts │ │ └── Symbol.ts │ ├── ext_api │ │ └── config_manager.ts │ ├── extension.ts │ ├── parser │ │ ├── BasicLexer.g4 │ │ ├── BasicLexer.interp │ │ ├── BasicLexer.tokens │ │ ├── BasicLexer.ts │ │ ├── BasicParser.g4 │ │ ├── BasicParser.interp │ │ ├── BasicParser.tokens │ │ ├── BasicParser.ts │ │ ├── BasicParserListener.ts │ │ └── BasicParserVisitor.ts │ └── providers │ │ ├── CompletionProvider.ts │ │ ├── DefinitionProvider.ts │ │ ├── HoverProvider.ts │ │ ├── ReferenceProvider.ts │ │ └── RenameProvider.ts ├── vms_cobol │ ├── context │ │ ├── CobolAnalisisHelpers.ts │ │ ├── CobolAnalysisVisitor.ts │ │ ├── CobolBackground.ts │ │ ├── CobolDetailsListener.ts │ │ ├── CobolGlobals.ts │ │ ├── CobolSourceContext.ts │ │ ├── CobolSymbol.ts │ │ └── CobolSymbolTable.ts │ ├── extension.ts │ ├── parser │ │ ├── cobol.g4 │ │ ├── cobol.interp │ │ ├── cobol.tokens │ │ ├── cobolCopy.g4 │ │ ├── cobolCopy.interp │ │ ├── cobolCopy.tokens │ │ ├── cobolCopyLexer.interp │ │ ├── cobolCopyLexer.tokens │ │ ├── cobolCopyLexer.ts │ │ ├── cobolCopyListener.ts │ │ ├── cobolCopyParser.ts │ │ ├── cobolCopyVisitor.ts │ │ ├── cobolLexer.g4 │ │ ├── cobolLexer.interp │ │ ├── cobolLexer.tokens │ │ ├── cobolLexer.ts │ │ ├── cobolListener.ts │ │ ├── cobolParser.ts │ │ ├── cobolParserImpl.ts │ │ └── cobolVisitor.ts │ ├── stream │ │ ├── CopyManagerImpl.ts │ │ ├── CopyManagers.ts │ │ └── cobolInputStream.ts │ └── test │ │ └── test.cob ├── vms_debug │ ├── command │ │ ├── debug_commands.ts │ │ └── os_commands.ts │ ├── debug │ │ ├── vms_debug.ts │ │ ├── vms_debug_run.ts │ │ ├── vms_runtime.ts │ │ └── vms_runtime_run.ts │ ├── ext-api │ │ └── config_manager.ts │ ├── extension.ts │ ├── net │ │ ├── shell-parser.ts │ │ └── shell-session.ts │ ├── parsers │ │ ├── debug_file_info.ts │ │ ├── debug_module_info.ts │ │ ├── debug_parser.ts │ │ └── debug_variable_info.ts │ ├── queue │ │ └── queues.ts │ └── ui │ │ ├── status_bar.ts │ │ └── terminal.ts ├── vms_fortran │ ├── context │ │ ├── AnalysisListener.ts │ │ ├── ContextErrorListener.ts │ │ ├── ContextSymbolTable.ts │ │ ├── DetailsListener.ts │ │ ├── Facade.ts │ │ ├── SourceContext.ts │ │ └── Symbol.ts │ ├── ext_api │ │ └── config_manager.ts │ ├── extension.ts │ ├── parser │ │ ├── FortranLexer.g4 │ │ ├── FortranLexer.interp │ │ ├── FortranLexer.tokens │ │ ├── FortranLexer.ts │ │ ├── FortranParser.g4 │ │ ├── FortranParser.interp │ │ ├── FortranParser.tokens │ │ ├── FortranParser.ts │ │ ├── FortranParserListener.ts │ │ └── FortranParserVisitor.ts │ └── providers │ │ ├── CompletionProvider.ts │ │ ├── DefinitionProvider.ts │ │ ├── HoverProvider.ts │ │ ├── ReferenceProvider.ts │ │ └── RenameProvider.ts ├── vms_jvm_debug │ ├── cmd-queue.ts │ ├── communication.ts │ ├── drop.ts │ ├── extension.ts │ ├── jvm-config.ts │ ├── jvm-debug-session.ts │ ├── jvm-proj-helper.ts │ ├── jvm-project.ts │ ├── jvm-shell-runtime.ts │ ├── jvm-state-machine.ts │ ├── shell-splitter.ts │ ├── simple-cmd-client.ts │ └── ssh-shell-server.ts ├── vms_pascal │ ├── context │ │ ├── AnalysisListener.ts │ │ ├── ContextErrorListener.ts │ │ ├── ContextSymbolTable.ts │ │ ├── DetailsListener.ts │ │ ├── Facade.ts │ │ ├── SourceContext.ts │ │ └── Symbol.ts │ ├── ext_api │ │ └── config_manager.ts │ ├── extension.ts │ ├── parser │ │ ├── pascal.g4 │ │ ├── pascal.interp │ │ ├── pascal.tokens │ │ ├── pascalLexer.interp │ │ ├── pascalLexer.tokens │ │ ├── pascalLexer.ts │ │ ├── pascalListener.ts │ │ ├── pascalParser.ts │ │ └── pascalVisitor.ts │ └── providers │ │ ├── CompletionProvider.ts │ │ ├── DefinitionProvider.ts │ │ ├── HoverProvider.ts │ │ ├── ReferenceProvider.ts │ │ └── RenameProvider.ts └── zip │ ├── extension.ts │ └── zip-api.ts ├── syntaxes ├── basic.tmLanguage.json ├── bliss.tmLanguage.json ├── cld.tmLanguage.json ├── fortran.tmLanguage.json ├── mms.tmLanguage.json ├── msg.tmLanguage.json ├── pascal.tmLanguage.json └── vms-cobol.tmLanguage.json ├── tsconfig.json ├── tslint.json └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | .ropeproject/ 5 | *.vsix 6 | *.zip 7 | package-lock.json 8 | # autogenerated files 9 | **/.antlr/* 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vmssoftware.project-dep.buildName": "DEBUG", 3 | "search.exclude": { 4 | "**/node_modules": false 5 | }, 6 | "search.useGlobalIgnoreFiles": true, 7 | "search.useIgnoreFiles": false 8 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | out/**/*.js 6 | out/**/*.ts 7 | src/** 8 | .gitignore 9 | tsconfig.json 10 | vsc-extension-quickstart.md 11 | tslint.json 12 | gulpfile.js 13 | webpack.config.js 14 | i18n 15 | !out/index.js 16 | node_modules 17 | *.zip 18 | package-lock.json -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 VMS Software, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /basic.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "!", 4 | "blockComment": [ "!", "!" ] 5 | }, 6 | "wordPattern": "[a-zA-Z][a-zA-Z$_0-9\\.]*[$%]?", 7 | "brackets": [ 8 | ["(", ")"], 9 | ["[", "]"], 10 | ], 11 | "autoClosingPairs": [ 12 | ["(", ")"], 13 | ["[", "]"], 14 | ["\"", "\""], 15 | ["'", "'"] 16 | ], 17 | "surroundingPairs": [ 18 | ["(", ")"], 19 | ["[", "]"], 20 | ["\"", "\""], 21 | ["'", "'"] 22 | ] 23 | } -------------------------------------------------------------------------------- /bliss.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "!", 4 | "blockComment": [ "%(", ")%" ] 5 | }, 6 | "wordPattern": "[a-zA-Z$_][a-zA-Z$_0-9]*", 7 | "brackets": [ 8 | ["(", ")"], 9 | ["[", "]"], 10 | ["<", ">"], 11 | ["begin", "end"] 12 | ], 13 | "autoClosingPairs": [ 14 | ["(", ")"], 15 | ["\"", "\""], 16 | ["'", "'"] 17 | ], 18 | "surroundingPairs": [ 19 | ["(", ")"], 20 | ["\"", "\""], 21 | ["'", "'"] 22 | ] 23 | } -------------------------------------------------------------------------------- /cld.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "!" 4 | }, 5 | "brackets": [ 6 | ["(", ")"] 7 | ], 8 | "autoClosingPairs": [ 9 | ["(", ")"], 10 | ["\"", "\""], 11 | ["'", "'"] 12 | ], 13 | "surroundingPairs": [ 14 | ["(", ")"], 15 | ["\"", "\""], 16 | ["'", "'"] 17 | ] 18 | } -------------------------------------------------------------------------------- /cobol.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "*>" 4 | }, 5 | "brackets": [ 6 | [ 7 | "[", 8 | "]" 9 | ], 10 | [ 11 | "(", 12 | ")" 13 | ], 14 | [ 15 | "\"", 16 | "\"" 17 | ], 18 | [ 19 | "'", 20 | "'" 21 | ] 22 | ], 23 | "autoClosingPairs": [ 24 | { 25 | "open": "[", 26 | "close": "]" 27 | }, 28 | { 29 | "open": "(", 30 | "close": ")" 31 | }, 32 | { 33 | "open": "'", 34 | "close": "'", 35 | "notIn": [ 36 | "string", 37 | "comment" 38 | ] 39 | }, 40 | { 41 | "open": "\"", 42 | "close": "\"", 43 | "notIn": [ 44 | "string", 45 | "comment" 46 | ] 47 | } 48 | ], 49 | "surroundingPairs": [ 50 | [ 51 | "{", 52 | "}" 53 | ], 54 | [ 55 | "[", 56 | "]" 57 | ], 58 | [ 59 | "(", 60 | ")" 61 | ], 62 | [ 63 | "\"", 64 | "\"" 65 | ], 66 | [ 67 | "'", 68 | "'" 69 | ] 70 | ], 71 | "folding": { 72 | "markers": { 73 | "start": "^\\s*\\$region\\b", 74 | "end": "^\\s*\\$end-region\\b" 75 | } 76 | }, 77 | "wordPattern": "[$a-zA-Z0-9_]([-$a-zA-Z0-9_]*[$a-zA-Z0-9_])?" 78 | } 79 | -------------------------------------------------------------------------------- /fortran.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "wordPattern": "[a-zA-Z][a-zA-Z0-9_$]*", 3 | "comments": { 4 | "lineComment": "!" 5 | }, 6 | "brackets": [ 7 | [ 8 | "[", 9 | "]" 10 | ], 11 | [ 12 | "(", 13 | ")" 14 | ], 15 | [ 16 | "(/", 17 | "/)" 18 | ] 19 | ], 20 | "autoClosingPairs": [ 21 | { 22 | "open": "[", 23 | "close": "]" 24 | }, 25 | { 26 | "open": "(", 27 | "close": ")" 28 | }, 29 | { 30 | "open": "(/", 31 | "close": "/)" 32 | } 33 | ], 34 | "surroundingPairs": [ 35 | [ 36 | "[", 37 | "]" 38 | ], 39 | [ 40 | "(", 41 | ")" 42 | ], 43 | [ 44 | "'", 45 | "'" 46 | ], 47 | [ 48 | "\"", 49 | "\"" 50 | ] 51 | ], 52 | "indentationRules": { 53 | "unIndentedLinePattern": "^\\s*!.*", 54 | "increaseIndentPattern": { 55 | "pattern": "then(\\s*|\\s*!.*)$|^\\s*(program|subroutine|function|module|do|block|associate|case|select\\s*case)\\b.*$|\\s*(else|else\\s*if|elsewhere)\\b.*$", 56 | "flags": "i" 57 | }, 58 | "decreaseIndentPattern": { 59 | "pattern": "^\\s*end\\s*(select|if|do|function|subroutine|module|program)\\b.*$|^\\s*else|case\\b.*$", 60 | "flags": "i" 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /i18n/ru/cld/AnalysisListener.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "cannotFindDefine": "Невозможно найти DEFINE для данного элемента.", 3 | "cannotFindEntity": "Невозможно найти данный элемент или он двусмысленый.", 4 | "circularTypeRef": "Циклическая ссылка на тип.", 5 | "emptyParameterName": "Имя параметра не может быть пустым.", 6 | "entityHasNoChildren": "Элемент не имеет потомков.", 7 | "entityNotUnique": "Имя должно быть уникальным.", 8 | "entityOutside": "Элемент за пределами DEFINE.", 9 | "entityStartNameNotUnique": "Первые четыре символа имени должны быть уникальными.", 10 | "identStringTooLong": "Строка идентификации максимум 31 символ.", 11 | "imageStringTooLong": "Строка образа максимум 63 символа.", 12 | "invalidParameterName": "Имя параметра должно быть в виде Pn, где n - позиция параметра.", 13 | "invalidParameterNumber": "Имя параметра должно быть пронумеровано последовательно от P1 до P8.", 14 | "mutualDefaultOrRequired": "Выражения DEFAULT и REQUIRED взаимоисключающие.", 15 | "mutualImageOrRoutine": "Возможно только одно - или ROUTINE, или IMAGE.", 16 | "mutualQual": "Выражения NOQUALIFIERS и QUALIFIER взаимоисключающие.", 17 | "mutualDisallow": "Выражения NODISALLOWS и DISALLOW взаимоисключающие.", 18 | "mutualParameter": "Выражения NOPARAMETERS и PARAMETER взаимоисключающие.", 19 | "nameTooLong": "Имя максимум 31 символ.", 20 | "parameterPromptTooLong": "Параметр prompt максимум 31 символ.", 21 | "parameterValueDefaultStringTooLong": "Параметр default value максимум 94 символа.", 22 | "syntaxNotExists": "Не найдено SYNTAX для данного имени.", 23 | "tooManyKeywords": "Вы можете указать до 255 ключевых слов в выражении DEFINE TYPE.", 24 | "tooManyLabels": "Слишком много меток.", 25 | "tooManyQualifiers": "Вы можете использовать QUALIFIER до 255 раз в одном DEFINE.", 26 | "tooManyTypes": "Слишком много типов.", 27 | "typeNotExists": "Не найден TYPE для данного имени." 28 | } -------------------------------------------------------------------------------- /i18n/ru/cld/SourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/cld/Symbol.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/cld/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config.notfound": "Не найден плагин vmssoftware.config-helper" 3 | } -------------------------------------------------------------------------------- /i18n/ru/config-helper/config/config-api.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "message.created": "{0} создано" 3 | } -------------------------------------------------------------------------------- /i18n/ru/config-helper/config/config-pool.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config.filldata.failed": "чтение данных ('{0}') неудачно", 3 | "config.storedata.failed": "сохранение данных ('{0}') неудачно" 4 | } -------------------------------------------------------------------------------- /i18n/ru/config-helper/extension.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/extension.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/msg/AnalysisListener.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "emptyBaseValue": "Базовый номер не может быть пустым.", 3 | "emptySeverity": "Попытка определить сообщение без указания степени тяжести", 4 | "emptyFacilityName": "Имя службы не может быть пустым.", 5 | "emptyTitleName": "Титульное имя не может быть пустым.", 6 | "emptyFaoCount": "Счётчик FAO не может быть пустым.", 7 | "emptyLiteralName": "Буквенное определение не может быть пустым.", 8 | "emptyMessageIdentification": "Идентификатор сообщения не может быть пустым.", 9 | "emptyMessageName": "Сообщение не может быть пустым.", 10 | "emptyPrefixValue": "Префикс службы не может быть пустым.", 11 | "emptyPrefixToken": "У сообщения должен быть префикс.", 12 | "emptyUserValue": "Пользовательское значение не может быть пустым.", 13 | "messageAlreadyExists": "Сообщение уже существует.", 14 | "messageSymbolAlreadyExists": "Символ сообщения уже существует.", 15 | "oneLine": "Нельзя продолжить текст на следующую строку.", 16 | "tooBigFaoCount": "Число должно быть десятичным от 0 до 255.", 17 | "tooBigMessageNumber": "Количество сообщений не может быть более 4095 и должно быть больше нуля.", 18 | "tooBigUserValue": "Число должно быть десятичным от 0 до 255.", 19 | "tooLongFacilityName": "Имя службы не более 9 символов.", 20 | "tooLongFacilityPrefix": "Маскимальная длина альтернативного префикса, созданного с помощью /PREFIX, составляет 9 символов.", 21 | "tooLongIdentValue": "Максимальная длина идентификатора 31 символ.", 22 | "tooLongIdentification": "Имя может включать до девяти символов.", 23 | "tooLongMessageName": "Общая длина префикса и имени сообщения не должно превышать 31 символ.", 24 | "tooLongMessageText": "Тескт может быть длиной до 255 байт.", 25 | "tooLongTitleDescription": "Титул листинга имеет максимальную длину 28 символов.", 26 | "tooLongTitleName": "Титульное имя имеет максимальную длину 31 символ.", 27 | "undefinedVariable": "Неопределённая переменная.", 28 | "messageFaoCountDiff": "Вероятно, счётчик FAO не верный." 29 | } -------------------------------------------------------------------------------- /i18n/ru/msg/SourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "hexnum": "Шестнадцатиричное число", 3 | "octnum": "Восьмиричное число", 4 | "decnum": "Десятичное число" 5 | } -------------------------------------------------------------------------------- /i18n/ru/msg/Symbol.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "keyword": "Ключевое слово", 3 | "operator": "Оператор", 4 | "literal": "Литера", 5 | "message": "Сообщение", 6 | "variable": "Переменная", 7 | "facility": "Имя службы", 8 | "prefix": "Префикс службы" 9 | } -------------------------------------------------------------------------------- /i18n/ru/msg/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config.notfound": "Не найден плагин vmssoftware.config-helper" 3 | } -------------------------------------------------------------------------------- /i18n/ru/python/debugSession.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "port.busy": "Порт {0} занят." 3 | } -------------------------------------------------------------------------------- /i18n/ru/python/extension.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/python/provider.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "msg.config.invalid": "Не верная конфигурация" 3 | } -------------------------------------------------------------------------------- /i18n/ru/python/runtime.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/config-resolve/connect-config-resolver-impl.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.clearcache": "clearCache: delete {0}", 3 | "debug.killcache": "killCache: delete {0}", 4 | "debug.feedback": "feedBack: элемент {0} принят={1}", 5 | "debug.feedback.lock": "feedback: свободен {0}", 6 | "debug.feedback.already": "feedback: уже принят={0} {1}", 7 | "debug.feedback.no": "feedBack: нет узла {0}", 8 | "debug.resolve.start": "resolveConnectConfig: попытка для {0}", 9 | "debug.resolve.create_node": "resolveConnectConfig: создание узла {0}", 10 | "debug.resolve.lock": "resolveConnectConfig: блокирован {0}", 11 | "debug.resolve.first": "resolveConnectConfig: первый запрос {0}", 12 | "debug.resolve.filled": "resolveConnectConfig: заполнен {0}", 13 | "debug.resolve.didnt": "resolveConnectConfig: не заполнен {0}", 14 | "debug.resolve.unlock.nofeedback": "resolveConnectConfig: lock released (no feedback needed) {0}", 15 | "debug.resolve.timeout": "resolveConnectConfig: разблокирован по таймауту {0}", 16 | "debug.resolve.second": "resolveConnectConfig: второй и следующие запросы {0}", 17 | "debug.resolve.state": "resolveConnectConfig: принят={0} {1}", 18 | "debug.resolve.unlock.already": "resolveConnectConfig: lock released {0}", 19 | "debug.resolve.ret": "resolveConnectConfig: завершён {0}", 20 | "debug.resolve.start.test": "resolveConnectConfig: try {0}" 21 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/config-resolve/password-console-filler.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "query.password": "Пароль для {0}@{1}:{2} " 3 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/config-resolve/password-vscode-filler.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "query.password": "Пароль для {0}@{1}:{2} " 3 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/ssh-helper.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "ssh_helper.case_host": "Cannot find a host in list: {0}, did you mean {1}?", 3 | "ssh_helper.no_host": "Cannot find a host in list: {0}", 4 | "config.logResult.fail": "Settings: load operation failed", 5 | "config.logResult.prepare_failed": "Settings: cannot load data from storage", 6 | "config.logResult.some_data_failed": "Settings: failed to fill some data while loading" 7 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/parse-welcome-vms.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.tt": "vms парсер: найдена команда TTY {0}", 3 | "debug.terminal": "vms parse: setup terminal and wait next prompt", 4 | "debug.prompt": "vms парсер: найден промпт '{0}'" 5 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/parse-welcome.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.prompt": "парсер: найден промпт '{0}'" 3 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/pipe.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.source_fail": "не удалось создать источник {0}", 3 | "debug.source_error": "ошибка источника {0}", 4 | "debug.dest_fail": "не удалось создать приёмник {0}", 5 | "debug.dest_error": "ошибка приёмника {0}", 6 | "debug.dest_finished": "приёмник завершён", 7 | "debug.dest_closed": "приёмник закрыт", 8 | "debug.done": "завершено {0}", 9 | "debug.source_lost": "источник исчез" 10 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/sftp-client.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.read.err": "чтение stream{0} ошибка: {1}", 3 | "debug.write.err": "запись stream{0} ошибка: {1}", 4 | "operation.getstat": "get stat {0} через sftp{1}", 5 | "debug.operation.error": "{0} ошибка: {1}", 6 | "operation.delete": "delete {0} via sftp{1}", 7 | "operation.setstat": "set stat {0} через sftp{1}", 8 | "operation.readdir": "read directory {0} через sftp{1}", 9 | "operation.createdir": "create directory {0} через sftp{1}", 10 | "operation.sftp": "create sftp{0}", 11 | "debug.sftp.ready": "sftp{0} готов", 12 | "debug.sftp.end": "sftp{0} конец", 13 | "debug.sftp.error": "sftp{0} ошибка: {1}", 14 | "debug.sftp.close": "sftp{0} закрыт" 15 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/shell-parser.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.closed": "ShellParser{0}: закрыт", 3 | "debug.error": "ShellParser{1}: ошибка {0}", 4 | "debug.chunk": "ShellParser{0}: получены данные", 5 | "debug.nobuf": "ShellParser{0}: данные не Buffer", 6 | "debug.ready": "ShellParser{0}: готов", 7 | "debug.timeout": "ShellParser{0}: таймаут" 8 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/ssh-client.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.ready": "client{0} готов", 3 | "debug.end": "client{0} завершён", 4 | "debug.error": "client{1} ошибка: {0}", 5 | "connect.exception": "Exception: {0}", 6 | "debug.resolver": "не определена конфигурация {0}" 7 | } -------------------------------------------------------------------------------- /i18n/ru/ssh-helper/stream/ssh-shell.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.cmd.error": "shell{1} ошибка команды: {0}", 3 | "debug.cmd.raw": "shell{1} сырые дынные команды: {0}", 4 | "debug.cmd.out": "shell{0} вывод команды найден", 5 | "debug.garbage": "shell{0} мусор", 6 | "debug.closed": "shell{0} канал закрыт", 7 | "debug.channel.exit": "shell{0} канал ушёл", 8 | "debug.written": "shell{1} команда записана: {0}", 9 | "debug.unpiped": "shell{0} парсер конца команды отсоединён", 10 | "debug.undef": "shell{0} канал неопределён при попытке отсоединения парсера конца команды", 11 | "debug.welcome": "shell{0} создание парсера приветствия по-умолчанию", 12 | "debug.prompt": "shell{0} создание парсера конца команды по-умолчанию", 13 | "debug.prompt.set": "shell{1} установка промпта '{0}' в парсер конца команды", 14 | "operation.connect": "создание shell{0}", 15 | "debug.operation.error": "{0} ошибка: {1}", 16 | "debug.ready": "shell{0} готов", 17 | "debug.close": "shell{0} закрыт", 18 | "debug.exit": "shell{1} вышел {0}", 19 | "debug.cleaned": "Shell{0} очищен" 20 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/build/builder.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.disposing": "Освобождение источников", 3 | "collect.no_class_for_file": "No class for this file match: {0}", 4 | "collect.no_method_for_line": "No method for this line match: {0}", 5 | "collect.no_class_for_main": "No class for this main function match: {0}", 6 | "collect.no_class_for_method": "No class for method: {0}", 7 | "collect.no_info": "No info for classes: {0}", 8 | "build.cfg": "There is no build configuration named {0}.", 9 | "check.inc.mask": "Please check listing file masks for correct curly brackets", 10 | "create.mms.first": "Сперва (пере)создайте MMS.", 11 | "output.cannot_exec": "Не удалось запустить {0}", 12 | "mms_exist": "Предыдущий MMS файл переименован в {0}", 13 | "opt_exist": "Предыдущий OPT файл переименован в {0}", 14 | "com_exist": "Предыдущий COM файл переименован в {0}", 15 | "cannot.clean": "Have no idea how to clean configuration: {0}", 16 | "cannot.build": "Have no idea how to build configuration: {0}", 17 | "too_many_files": "There are more than one file named {0}", 18 | "no_file": "Cannot find the file named {0}", 19 | "debug.cannot_get_ssh_helper": "Не удалось загрузить ssh-helper API", 20 | "output.install_ssh": "Установите плагин 'vmssoftware.ssh-helper'", 21 | "debug.create_shell": "Создание shell для компиляции" 22 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/common/find-files.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "check.inc.mask": "Проверьте маску include на правильность скобок", 3 | "check.exc.mask": "Проверьте маску include на правильность скобок" 4 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/dep-tree/project-descr.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "SSH": "SSH", 3 | "Project": "Проект", 4 | "Local": "Локально", 5 | "unknown": "Неизвестно", 6 | "modified": "Модифицирован", 7 | "synchronized": "Синхронизирован", 8 | "built": "Посторен", 9 | "not.built": "Не построен", 10 | "select.buildName": "Выберите конфигурацию для построения" 11 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/downloadHeaders.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "cd.failed": "Не удалось установить директорию", 3 | "ssh-helper.failed": "Расширение vmssoftware.ssh-helper не найдено.", 4 | "shell.failed": "Невозможно создать удалённый SHELL.", 5 | "no-result": "Не удалось выполнить команду для получения списка TLB файлов", 6 | "no-tlb": "Не найдены *.TLB файлы в папке SYS$LIBRARY", 7 | "create.failed": "Не удалось создать директорию", 8 | "file.extract.failed": "{0} was failed to unpack", 9 | "file.extracted": "Распакован: {0}", 10 | "del.failed": "Не удалось удалить временные файлы: {0}", 11 | "done": "Успешное завершение." 12 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/ensure-settings.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config.logResult.fail": "Settings: load operation failed", 3 | "config.logResult.prepare_failed": "Settings: cannot load data from storage", 4 | "config.logResult.some_data_failed": "Settings: failed to fill some data while loading" 5 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.activated": "Расширение 'VMS синхронизация' активировано", 3 | "scope.undefined": "Нет выделенного проекта в проводнике проектов", 4 | "debug.deactivated": "Расширение 'VMS синхронизация' выгружено" 5 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/scopeWatchers.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "check.inc.mask": "Проверьте маску include на корректность скобок", 3 | "check.exc.mask": "Проверьте маску exclude на корректность скобок" 4 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/sync/fs-source.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.no_date": "Нет даты файла {0}" 3 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/sync/synchronizer.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.disposing": "Освобождение ресурсов", 3 | "output.download_manually": "Удалённый файл {0} новее, проверьте и загрузите его самостоятельно", 4 | "output.edit_count": "Отредактируйте и сохраните {0} файл(ов) самостоятельно", 5 | "cannot.find.remote": "Cannot find files on remote source", 6 | "cannot.find.local": "Cannot find files on local source", 7 | "debug.retcode": "Синхронизация вернула: {0}", 8 | "debug.quick.delete": "Delete remote file failed: {0}", 9 | "debug.quick.delete.ok": "Remote file deleted: {0}", 10 | "quick.failed": "Quick uploading failed. Please execute full synchronization or uploading.", 11 | "debug.quick.retcode": "Quick uploading: {0}", 12 | "debug.upload.error": "Ошибка при выгрузке {0}", 13 | "debug.upload.retcode": "Выгрузка исходников retCode: {0}", 14 | "build.cfg": "There is no build configuration named {0}.", 15 | "debug.download_listing.error": "Ошибка при загрузке листинга {0}", 16 | "debug.download.error": "Ошибка при загрузке {0}", 17 | "file-like-bin": "Файл скорее всего бинарный: {0}", 18 | "title.rem_loc": "Удалённый {0} <-> Локальный", 19 | "debug.no_remote": "Нет удалённого файла {0} => выгрузить", 20 | "debug.local_is_newer": "Локальный файл {0} новее => выгрузить", 21 | "debug.remote_is_newer": "Удалённый файл {0} новее на {1} => загрузить", 22 | "debug.the_same": "Файлы {0} одинаковы", 23 | "debug.no_local": "Нет локального файла {0} => загрузить", 24 | "debug.cannot_get_ssh_helper": "Не удалось загрузить ssh-helper API", 25 | "output.install_ssh": "Установите плагин 'vmssoftware.ssh-helper'", 26 | "message.action_success": "{0} удачно: {1}", 27 | "message.action_failed": "{0} ошибка: {1}", 28 | "debug.create_remote": "Создание удалённого источника", 29 | "debug.create_local": "Создание локального источника" 30 | } -------------------------------------------------------------------------------- /i18n/ru/synchronizer/upload-zip.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "zip.cannot_clean": "Не удалось удалить локальный zip файл.", 3 | "ssh-helper.failed": "Не нашлось расширение vmssoftware.ssh-helper", 4 | "zip.missed": "Расширение vmssoftware.zip-helper не найдено.", 5 | "zip.cannot_start": "Не удалось запустить Zip.", 6 | "zip.nothing": "Нечего паковать.", 7 | "zip.ssh.stopped": "Останов.", 8 | "zip.prepare_to_uploading": "ZIP файл создан. Подготовка к выгрузке.", 9 | "zip.ssh.failed": "Расширение vmssoftware.ssh-helper не найдено.", 10 | "zip.shell.failed": "Не удалось создать shell на удалённой машине.", 11 | "zip.cleaning_folder": "Очистка папки.", 12 | "zip.start_uploading": "Начало выгрузки ZIP файла.", 13 | "zip.prepare_to_unzippping": "ZIP файл выгружен. Подготовка к распаковке.", 14 | "zip.cd.failed": "Не удалось установить текущую директорию.", 15 | "zip.start_unzipping": "Начало распаковки.", 16 | "zip.unzip.failed": "Команда Unzip неуспешна.", 17 | "zip.unzip.not.installed": "Похоже, что 'unzip' не установлен", 18 | "zip.unzip.error_output": "Вывод команды Unzip:\n {0}", 19 | "zip.deleting_zip": "Удаление ZIP файла на стороне VMS.", 20 | "zip.cannot_finish": "Не удалось завершить Zip." 21 | } -------------------------------------------------------------------------------- /i18n/ru/vms_basic/context/SourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/vms_cobol/context/CobolAnalisisHelpers.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "text_length_range": "Должно содержать от {0} до {1} символ(-ов,а)", 3 | "number_in_range": "Должно быть от {0} до {1}", 4 | "not_an_integer": "Должно быть целым", 5 | "undefined_name": "Неопределённое имя", 6 | "ambigous_name": "Двузначное имя", 7 | "illegal_type": "Неверный тип", 8 | "duplicated.clause": "Двойное выражение" 9 | } -------------------------------------------------------------------------------- /i18n/ru/vms_cobol/context/CobolSourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/vms_cobol/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config.notfound": "Не найден плагин vmssoftware.config-helper" 3 | } -------------------------------------------------------------------------------- /i18n/ru/vms_cobol/stream/cobolInputStream.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "string.continuation.improperly": "Продолжение должно начинаться с зоны B", 3 | "string.continuation.error": "Ошибка продолжения - строка должна начинаться с {0}", 4 | "string.continuation.error.unpredictable": "Непредсказуемая ошибка продолжения" 5 | } -------------------------------------------------------------------------------- /i18n/ru/vms_debug/debug/vms_runtime.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "config_error": "Ошибка конфигурации", 3 | "program.end": ": У вас нет прав: log_io, oper, share.", 4 | "runtime.watch_error": "Watch: Ошибка параметра. Пример: (when (x > 3)) или ().", 5 | "runtime.command_ignore": "Команда запрещена!" 6 | } -------------------------------------------------------------------------------- /i18n/ru/vms_debug/debug/vms_runtime_run.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime.program_end": "Программа завершена!" 3 | } -------------------------------------------------------------------------------- /i18n/ru/vms_debug/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "setup.connection": "Пожалуйста, определите соединение", 3 | "extention.conecting": "Соединение с сервером ...", 4 | "extention.bar.conecting": "Соединение ...", 5 | "extention.connected": "Соединение с сервером установлено", 6 | "extention.bar.connected": "Подключен", 7 | "extention.closed": "Соединение закрыто", 8 | "extention.bar.disconnected": "Отключен", 9 | "extention.сustomize_configuration": "Настройте конфигурацию", 10 | "extention.not_connected": "Нет соединения с сервером" 11 | } -------------------------------------------------------------------------------- /i18n/ru/vms_debug/net/shell-session.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "os.not.supported": ": OS is not supported.", 3 | "proram.completed": ": The program is completed.", 4 | "conn.closed": "Connection is closed.", 5 | "ssh.hlp.api.fail": "Could not get ssh-helper API.", 6 | "output.cannot_attach": "Невозможно присоединиться", 7 | "session.interrupted": "(Internal error: the session was interrupted.)" 8 | } -------------------------------------------------------------------------------- /i18n/ru/vms_debug/parsers/debug_module_info.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/vms_fortran/context/SourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/vms_jvm_debug/extension.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "msg.class_name": "Введите класс для запуска", 3 | "msg.config.invalid": "Неверная конфигурация" 4 | } -------------------------------------------------------------------------------- /i18n/ru/vms_jvm_debug/jvm-debug-session.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "jvm.port.busy": "Порт {0} занят." 3 | } -------------------------------------------------------------------------------- /i18n/ru/vms_jvm_debug/jvm-proj-helper.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "breakpoint.no.line": "Невозможно установить точку останова {0}:{1} -> отключена", 3 | "breakpoint.no.line.disable": "Unable to set breakpoint at {0}:{1}. Breakpoint disabled." 4 | } -------------------------------------------------------------------------------- /i18n/ru/vms_jvm_debug/jvm-project.i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "javainfo.lost": "Информация по классам Java утеряна" 3 | } -------------------------------------------------------------------------------- /i18n/ru/vms_jvm_debug/jvm-shell-runtime.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /i18n/ru/vms_pascal/context/SourceContext.i18n.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /images/mock-debug-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/images/mock-debug-icon.png -------------------------------------------------------------------------------- /images/vms_128x128_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/images/vms_128x128_v2.png -------------------------------------------------------------------------------- /images/vms_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/images/vms_logo.png -------------------------------------------------------------------------------- /make_async.txt: -------------------------------------------------------------------------------- 1 | //Make the next replacings, using regexp, and comment some errorneous functions: 2 | 3 | (// @RuleVersion.*\n\tpublic) 4 | $1 async 5 | 6 | (public\s*async.*?\(.*?\)):.* 7 | $1 { 8 | 9 | (this\.[^.]*\(\d*\)) 10 | await $1 11 | 12 | -------------------------------------------------------------------------------- /media/dep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/media/dep.png -------------------------------------------------------------------------------- /mms.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "!", 5 | }, 6 | // symbols used as brackets 7 | "brackets": [ 8 | ["{", "}"], 9 | ["[", "]"], 10 | ["(", ")"] 11 | ], 12 | // symbols that are auto closed when typing 13 | "autoClosingPairs": [ 14 | ["{", "}"], 15 | ["[", "]"], 16 | ["(", ")"], 17 | ["\"", "\""], 18 | ["'", "'"] 19 | ], 20 | // symbols that that can be used to surround a selection 21 | "surroundingPairs": [ 22 | ["{", "}"], 23 | ["[", "]"], 24 | ["(", ")"], 25 | ["\"", "\""], 26 | ["'", "'"] 27 | ] 28 | } -------------------------------------------------------------------------------- /msg.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "!" 4 | }, 5 | "brackets": [ 6 | ["<", ">"] 7 | ], 8 | "autoClosingPairs": [ 9 | ["<", ">"], 10 | ["\"", "\""], 11 | ["'", "'"] 12 | ], 13 | "surroundingPairs": [ 14 | ["<", ">"], 15 | ["\"", "\""], 16 | ["'", "'"] 17 | ] 18 | } -------------------------------------------------------------------------------- /pascal.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "!", 4 | "blockComment": [ "{", "}" ] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | ["{", "}"], 13 | ["[", "]"], 14 | ["(", ")"], 15 | ["'", "'"] 16 | ], 17 | "surroundingPairs": [ 18 | ["{", "}"], 19 | ["[", "]"], 20 | ["(", ")"], 21 | ["'", "'"] 22 | ], 23 | "wordPattern": "[a-zA-Z$_][a-zA-Z$_0-9]*" 24 | } 25 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Repository containing code for new OpenVMS IDE based on Visual Studio Code. -------------------------------------------------------------------------------- /resources/build_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/resources/build_1.png -------------------------------------------------------------------------------- /resources/build_28x28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/resources/build_28x28.png -------------------------------------------------------------------------------- /resources/dark/boolean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/dependency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/document.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/default.mms: -------------------------------------------------------------------------------- 1 | 2 | ! MMS - run with /EXTENDED_SYNTAX qualifier 3 | .SILENT 4 | 5 | ! Debug or Release 6 | .IF DEBUG 7 | OUT_DIR = .$(OUTDIR).debug 8 | CXXFLAGS = /DEBUG/NOOP/LIST=$(MMS$TARGET_NAME)/OBJECT=$(MMS$TARGET) 9 | CCFLAGS = /DEBUG/NOOP/LIST=$(MMS$TARGET_NAME)/OBJECT=$(MMS$TARGET) 10 | LINKFLAGS = /DEBUG/MAP=$(MMS$TARGET_NAME)/EXECUTABLE=$(MMS$TARGET) 11 | .ELSE 12 | OUT_DIR = .$(OUTDIR).release 13 | CXXFLAGS = /OBJECT=$(MMS$TARGET) 14 | CCFLAGS = /OBJECT=$(MMS$TARGET) 15 | LINKFLAGS = /EXECUTABLE=$(MMS$TARGET) 16 | .ENDIF 17 | 18 | ! Object directory 19 | OBJ_DIR = $(OUT_DIR).obj 20 | 21 | OBJECTS = $(JOIN $(PATSUBST *,[*],$(PATSUBST *[*],**,$(SUBST [],,$(ADDPREFIX $(OBJ_DIR),$(DIR $(SOURCES)))))),$(ADDSUFFIX .OBJ, $(NOTDIR $(BASENAME $(SOURCES))))) 22 | 23 | .SUFFIXES 24 | .SUFFIXES .EXE .OBJ .CPP .C 25 | 26 | .CPP.OBJ 27 | @- pipe create/dir $(DIR $(MMS$TARGET)) | copy SYS$INPUT nl: 28 | $(CXX) $(CXXFLAGS) $(MMS$SOURCE) 29 | 30 | .C.OBJ 31 | @- pipe create/dir $(DIR $(MMS$TARGET)) | copy SYS$INPUT nl: 32 | $(CC) $(CCFLAGS) $(MMS$SOURCE) 33 | 34 | [$(OUT_DIR)]$(NAME).exe DEPENDS_ON $(OBJECTS) 35 | $(LINK) $(LINKFLAGS) $(MMS$SOURCE_LIST) 36 | 37 | -------------------------------------------------------------------------------- /resources/light/boolean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/dependency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/document.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/package-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmssoftware/vms-ide/fb86e12999b0f05b9edfc2e53a8e4b5af58b2e27/resources/package-explorer.png -------------------------------------------------------------------------------- /resources/static.mms: -------------------------------------------------------------------------------- 1 | OUTDIR=out 2 | NAME=static 3 | INCLUDES=inc.h, add.h 4 | SOURCES=inc.cpp, add.cpp 5 | 6 | ! MMS - run with /EXTENDED_SYNTAX qualifier 7 | ! .SILENT 8 | 9 | ! Debug or Release 10 | .IF DEBUG 11 | OUT_DIR = .$(OUTDIR).debug 12 | CXXFLAGS = /DEBUG/NOOP/LIST=$(MMS$TARGET_NAME)/OBJECT=$(MMS$TARGET) 13 | CCFLAGS = /DEBUG/NOOP/LIST=$(MMS$TARGET_NAME)/OBJECT=$(MMS$TARGET) 14 | .ELSE 15 | OUT_DIR = .$(OUTDIR).release 16 | CXXFLAGS = /OBJECT=$(MMS$TARGET) 17 | CCFLAGS = /OBJECT=$(MMS$TARGET) 18 | .ENDIF 19 | 20 | ! Object directory 21 | OBJ_DIR = $(OUT_DIR).obj 22 | 23 | .SUFFIXES 24 | .SUFFIXES .OLB .OBJ .CPP .C 25 | 26 | .CPP.OBJ 27 | pipe create/dir $(DIR $(MMS$TARGET)) | copy SYS$INPUT nl: 28 | $(CXX) $(CXXFLAGS) $(MMS$SOURCE) 29 | 30 | .C.OBJ 31 | pipe create/dir $(DIR $(MMS$TARGET)) | copy SYS$INPUT nl: 32 | $(CC) $(CCFLAGS) $(MMS$SOURCE) 33 | 34 | [$(OUT_DIR)]$(NAME).OLB :: [$(OBJ_DIR)]inc.obj 35 | IF "''F$SEARCH("[$(OUT_DIR)]$(NAME).OLB")'" .EQS. "" THEN - 36 | LIBR/CREATE/OBJ [$(OUT_DIR)]$(NAME).OLB 37 | LIBR [$(OUT_DIR)]$(NAME).OLB [$(OBJ_DIR)]inc.obj 38 | 39 | [$(OUT_DIR)]$(NAME).OLB :: [$(OBJ_DIR)]add.obj 40 | IF "''F$SEARCH("[$(OUT_DIR)]$(NAME).OLB")'" .EQS. "" THEN - 41 | LIBR/CREATE/OBJ [$(OUT_DIR)]$(NAME).OLB 42 | LIBR [$(OUT_DIR)]$(NAME).OLB [$(OBJ_DIR)]add.obj 43 | 44 | [$(OBJ_DIR)]inc.obj : inc.cpp $(INCLUDES) 45 | 46 | [$(OBJ_DIR)]add.obj : add.cpp $(INCLUDES) -------------------------------------------------------------------------------- /src/cld/CompletionProvider.ts: -------------------------------------------------------------------------------- 1 | 2 | import { TextDocument, Position, CancellationToken, Location, CompletionItem, CompletionItemKind, ProviderResult, CompletionList } from 'vscode'; 3 | import { CldFacade, SymbolKind } from './Facade'; 4 | import { translateCompletionKind } from './Symbol'; 5 | 6 | // Determines the sort order in the completion list. One value for each SymbolKind. 7 | const sortKeys = [ 8 | "99", // Other 9 | ]; 10 | 11 | // Descriptions for each symbol kind. 12 | const details = [ 13 | "Other", 14 | ]; 15 | 16 | export class CldCompletionItemProvider { 17 | constructor(private backend: CldFacade) { } 18 | 19 | public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 20 | 21 | let candidates = this.backend.getCodeCompletionCandidates(document.fileName, position.character, position.line + 1); 22 | let completionList: CompletionItem[] = []; 23 | 24 | candidates.forEach(info => { 25 | let item = new CompletionItem(info.name, translateCompletionKind(info.kind)); 26 | item.sortText = sortKeys[info.kind] + info.name; 27 | item.detail = (info.description !== undefined) ? info.description : details[info.kind]; 28 | completionList.push(item); 29 | }); 30 | 31 | return new CompletionList(completionList, false); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/cld/ContextErrorListener.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is released under the MIT license. 3 | * Copyright (c) 2016, 2017 Mike Lischke 4 | * 5 | * See LICENSE file for more info. 6 | */ 7 | 8 | "use strict"; 9 | 10 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 11 | 12 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 13 | 14 | export class ContextLexerErrorListener implements ANTLRErrorListener { 15 | constructor(private errorList: DiagnosticEntry[]) { 16 | } 17 | 18 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 19 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void { 20 | let error: DiagnosticEntry = { 21 | type: DiagnosticType.Error, 22 | message: msg, 23 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 24 | }; 25 | 26 | this.errorList.push(error); 27 | } 28 | } 29 | 30 | export class ContextErrorListener implements ANTLRErrorListener { 31 | constructor(private errorList: DiagnosticEntry[]) { 32 | } 33 | 34 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 35 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void { 36 | let error: DiagnosticEntry = { 37 | type: DiagnosticType.Error, 38 | message: msg, 39 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 40 | }; 41 | 42 | if (offendingSymbol) { 43 | error.range.end.column = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 44 | } 45 | this.errorList.push(error); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/cld/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { CldFacade } from './Facade'; 3 | 4 | export class CldDefinitionProvider implements DefinitionProvider { 5 | constructor(private backend: CldFacade) { } 6 | 7 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 8 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 9 | 10 | if (!info) { 11 | return undefined; 12 | } 13 | 14 | if (info.masterDefinition) { 15 | let range = new Range( 16 | info.masterDefinition.range.start.row - 1, info.masterDefinition.range.start.column, 17 | info.masterDefinition.range.end.row - 1, info.masterDefinition.range.end.column 18 | ); 19 | return new Location(Uri.file(info.source), range); 20 | } else { 21 | // Empty for built-in entities or self-define attempts. 22 | // let position = new Position(0, 0); 23 | return new Location(document.uri, position); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cld/HoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { HoverProvider, TextDocument, Position, CancellationToken, ProviderResult, Hover } from "vscode"; 3 | import { CldFacade } from "./Facade"; 4 | import { symbolDescriptionFromEnum } from './Symbol'; 5 | 6 | export class CldHoverProvider implements HoverProvider { 7 | constructor(private backend: CldFacade) { } 8 | 9 | public provideHover(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 10 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 11 | if (!info) { 12 | return undefined; 13 | } 14 | 15 | return new Hover([ 16 | info.description? info.description : symbolDescriptionFromEnum(info.kind) 17 | ]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cld/ReferenceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | Location, 4 | Position, 5 | ProviderResult, 6 | Range, 7 | ReferenceContext, 8 | ReferenceProvider, 9 | TextDocument, 10 | } from 'vscode'; 11 | import { CldFacade } from './Facade'; 12 | 13 | export class CldReferenceProvider implements ReferenceProvider { 14 | constructor(private backend: CldFacade) { } 15 | 16 | provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult { 17 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 18 | const result: Location[] = []; 19 | if (occurences.length > 0 ) { 20 | // const master = occurences[0]; 21 | // if (master.definition && 22 | // master.definition.range.start.row === position.line + 1 && 23 | // master.definition.range.start.column <= position.character && 24 | // master.definition.range.end.column > position.character) { 25 | // // we point to the master 26 | for (let symbol of occurences) { 27 | if (symbol.definition) { 28 | let range = new Range( 29 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 30 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 31 | ); 32 | const loc: Location = { 33 | range, 34 | uri: document.uri, 35 | }; 36 | result.push(loc); 37 | } 38 | } 39 | // } 40 | } 41 | return result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/cld/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { CldFacade } from './Facade'; 3 | 4 | export class CldRenameProvider implements RenameProvider { 5 | constructor(private backend: CldFacade) { } 6 | 7 | // public prepareRename(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 8 | // let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 9 | 10 | // if (info && info.definition) { 11 | // return new Range( 12 | // info.definition.range.start.row - 1, 13 | // info.definition.range.start.column, 14 | // info.definition.range.end.row - 1, 15 | // info.definition.range.end.column); 16 | // } 17 | 18 | // return undefined; 19 | // } 20 | 21 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, 22 | token: CancellationToken): ProviderResult { 23 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 24 | if (occurences.length) { 25 | const result = new WorkspaceEdit(); 26 | for (let symbol of occurences) { 27 | if (symbol.definition) { 28 | let range = new Range( 29 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 30 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 31 | ); 32 | result.replace(Uri.file(symbol.source), range, newName); 33 | } 34 | } 35 | return result; 36 | } 37 | return undefined; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/cld/cld.tokens: -------------------------------------------------------------------------------- 1 | DEFINE=1 2 | IDENT=2 3 | MODULE=3 4 | SYNTAX=4 5 | TYPE=5 6 | VERB=6 7 | NODISALLOWS=7 8 | DISALLOW=8 9 | IMAGE=9 10 | NOPARAMETERS=10 11 | PARAMETER=11 12 | DEFAULT=12 13 | LABEL=13 14 | PROMPT=14 15 | VALUE=15 16 | NOCONCATENATE=16 17 | CONCATENATE=17 18 | LIST=18 19 | REQUIRED=19 20 | NOQUALIFIERS=20 21 | QUALIFIER=21 22 | BATCH=22 23 | NONNEGATABLE=23 24 | NEGATABLE=24 25 | PLACEMENT=25 26 | GLOBAL=26 27 | LOCAL=27 28 | POSITIONAL=28 29 | ROUTINE=29 30 | KEYWORD=30 31 | SYNONYM=31 32 | ANY2=32 33 | NEG=33 34 | NOT=34 35 | AND=35 36 | OR=36 37 | NAME=37 38 | COMMA=38 39 | EQUAL=39 40 | P_OPEN=40 41 | P_CLOSE=41 42 | A_OPEN=42 43 | A_CLOSE=43 44 | DOT=44 45 | STRING=45 46 | WHITESPACE=46 47 | NEWLINE=47 48 | COMMENT=48 49 | ','=38 50 | '='=39 51 | '('=40 52 | ')'=41 53 | '<'=42 54 | '>'=43 55 | '.'=44 56 | -------------------------------------------------------------------------------- /src/cld/cldLexer.tokens: -------------------------------------------------------------------------------- 1 | DEFINE=1 2 | IDENT=2 3 | MODULE=3 4 | SYNTAX=4 5 | TYPE=5 6 | VERB=6 7 | NODISALLOWS=7 8 | DISALLOW=8 9 | IMAGE=9 10 | NOPARAMETERS=10 11 | PARAMETER=11 12 | DEFAULT=12 13 | LABEL=13 14 | PROMPT=14 15 | VALUE=15 16 | NOCONCATENATE=16 17 | CONCATENATE=17 18 | LIST=18 19 | REQUIRED=19 20 | NOQUALIFIERS=20 21 | QUALIFIER=21 22 | BATCH=22 23 | NONNEGATABLE=23 24 | NEGATABLE=24 25 | PLACEMENT=25 26 | GLOBAL=26 27 | LOCAL=27 28 | POSITIONAL=28 29 | ROUTINE=29 30 | KEYWORD=30 31 | SYNONYM=31 32 | ANY2=32 33 | NEG=33 34 | NOT=34 35 | AND=35 36 | OR=36 37 | NAME=37 38 | COMMA=38 39 | EQUAL=39 40 | P_OPEN=40 41 | P_CLOSE=41 42 | A_OPEN=42 43 | A_CLOSE=43 44 | DOT=44 45 | STRING=45 46 | WHITESPACE=46 47 | NEWLINE=47 48 | COMMENT=48 49 | ','=38 50 | '='=39 51 | '('=40 52 | ')'=41 53 | '<'=42 54 | '>'=43 55 | '.'=44 56 | -------------------------------------------------------------------------------- /src/common/async-task-queue.ts: -------------------------------------------------------------------------------- 1 | type SimplyFn = () => void; 2 | 3 | export class AsyncTaskQueue { 4 | 5 | protected tasks: SimplyFn[] = []; 6 | protected isRunning: boolean = false; 7 | protected isStopped: boolean = false; 8 | 9 | public get numTasks(): number { 10 | return this.tasks.length; 11 | } 12 | 13 | /** 14 | * Enqueue task to execute 15 | * @param task 16 | * @param asap to set task in first position 17 | */ 18 | public enqueue(task: SimplyFn, asap: boolean = false): void { 19 | if (asap) { 20 | this.tasks.unshift(task); 21 | } else { 22 | this.tasks.push(task); 23 | } 24 | this.start(); 25 | } 26 | 27 | public start(): void { 28 | this.isStopped = false; 29 | if (!this.isRunning) { 30 | this.execute(); 31 | } 32 | } 33 | 34 | public stop(): void { 35 | this.isStopped = true; 36 | } 37 | 38 | private execute(): void { 39 | 40 | // If there is more than one task in the queue and this is not stopped. 41 | if (!this.isStopped && this.tasks.length > 0) { 42 | 43 | // Set status to running 44 | this.isRunning = true; 45 | 46 | // Get the first task 47 | const task: SimplyFn = this.tasks.shift()!; 48 | 49 | // Run the task decoupled and start the next 50 | Promise.resolve().then(async () => { 51 | await task(); 52 | this.execute(); 53 | }); 54 | 55 | } else { 56 | // If there is no more tasks or if this is no longer running 57 | // Set status to not running 58 | this.isRunning = false; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/common/bsearch.ts: -------------------------------------------------------------------------------- 1 | export function binarySearch(array: T[], predicate: (el: T) => number) { 2 | var m = 0; 3 | var n = array.length - 1; 4 | while (m <= n) { 5 | var k = (n + m) >> 1; 6 | var cmp = predicate(array[k]); 7 | if (cmp > 0) { 8 | m = k + 1; 9 | } else if(cmp < 0) { 10 | n = k - 1; 11 | } else { 12 | return k; 13 | } 14 | } 15 | return -m - 1; 16 | } -------------------------------------------------------------------------------- /src/common/cr-lf-trimmed-eq.ts: -------------------------------------------------------------------------------- 1 | const regexpt = /[\x13\x10]/g; 2 | 3 | export function CrLfTrimmedEqIgnoreCase(one: string, two: string): boolean { 4 | if (one === two) { 5 | return true; 6 | } 7 | return one.replace(regexpt, "").trim().toUpperCase() === two.replace(regexpt, "").trim().toUpperCase(); 8 | } 9 | -------------------------------------------------------------------------------- /src/common/debouncer.ts: -------------------------------------------------------------------------------- 1 | import { LogFunction, LogType } from "./log-type"; 2 | 3 | /** 4 | * Collects all calls and fire only one if during _msec were no more calls 5 | * Only the last then() or await will continue to work!!! 6 | */ 7 | 8 | export class Debouncer { 9 | 10 | protected timer: NodeJS.Timeout | undefined = undefined; 11 | 12 | constructor(protected msec: number, public debugLog?: LogFunction) { 13 | 14 | } 15 | 16 | public async debounce() { 17 | if (this.debugLog) { 18 | this.debugLog(LogType.debug, () => "debounce: start"); 19 | } 20 | if (this.timer) { 21 | if (this.debugLog) { 22 | this.debugLog(LogType.debug, () => "debounce: timer exists - clear timer"); 23 | } 24 | clearTimeout(this.timer); 25 | } 26 | if (this.debugLog) { 27 | this.debugLog(LogType.debug, () => "debounce: creating promise"); 28 | } 29 | return new Promise((resolve) => { 30 | if (this.debugLog) { 31 | this.debugLog(LogType.debug, () => "debounce: creating timer"); 32 | } 33 | this.timer = setTimeout(() => { 34 | if (this.debugLog) { 35 | this.debugLog(LogType.debug, () => "debounce: timer fired"); 36 | } 37 | this.timer = undefined; 38 | resolve(); 39 | }, this.msec); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/common/delay.ts: -------------------------------------------------------------------------------- 1 | 2 | export async function Delay(msec: number) { 3 | return new Promise((resolve) => { 4 | setTimeout(() => { 5 | resolve(); 6 | }, msec); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /src/common/directory.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface IFileEntry { 3 | filename: string; 4 | isFile: boolean; 5 | isDirectory: boolean; 6 | date: Date; // modification date 7 | vers: number; // version 8 | } 9 | 10 | export const ftpPathSeparator = "/"; 11 | 12 | export interface IReadDirectory { 13 | readDirectory(directory: string): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /src/common/iterators.ts: -------------------------------------------------------------------------------- 1 | 2 | export function minOf(iter: IterableIterator) { 3 | let min = Number.MAX_SAFE_INTEGER; 4 | for (const i of iter) { 5 | if (min > i) { 6 | min = i; 7 | } 8 | } 9 | return min; 10 | } -------------------------------------------------------------------------------- /src/common/log-type.ts: -------------------------------------------------------------------------------- 1 | 2 | export enum LogType { 3 | error, 4 | warning, 5 | information, 6 | debug, 7 | } 8 | 9 | export type LogResult= () => string; 10 | 11 | export type LogFunction = (type: LogType, message: LogResult, show?: boolean, addStackLevel?: number) => void; 12 | -------------------------------------------------------------------------------- /src/common/log.ts: -------------------------------------------------------------------------------- 1 | import { LogResult, LogType } from "./log-type"; 2 | 3 | export function logConsoleFn(type: LogType, message: LogResult) { 4 | switch (type) { 5 | case LogType.error: 6 | // tslint:disable-next-line:no-console 7 | console.error(message()); 8 | break; 9 | case LogType.warning: 10 | // tslint:disable-next-line:no-console 11 | console.warn(message()); 12 | break; 13 | case LogType.information: 14 | // tslint:disable-next-line:no-console 15 | console.info(message()); 16 | break; 17 | case LogType.debug: 18 | // tslint:disable-next-line:no-console 19 | console.log(message()); 20 | break; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/common/main.ts: -------------------------------------------------------------------------------- 1 | export * from "./async-task-queue"; 2 | export * from "./barrier"; 3 | export * from "./cr-lf-trimmed-eq"; 4 | export * from "./debouncer"; 5 | export * from "./delay"; 6 | export * from "./directory"; 7 | export * from "./lock"; 8 | export * from "./log"; 9 | export * from "./log-type"; 10 | export * from "./mem-reader"; 11 | export * from "./mem-writer"; 12 | export * from "./print-like"; 13 | export * from "./resolve"; 14 | export * from "./simply-compare"; 15 | export * from "./subscribe"; 16 | export * from "./wait-fire-event-emitter"; 17 | export * from "./waitable-operation"; 18 | -------------------------------------------------------------------------------- /src/common/mem-reader.ts: -------------------------------------------------------------------------------- 1 | import { Readable } from "stream"; 2 | import { LogFunction, LogType } from "./log-type"; 3 | 4 | export class MemoryReadStream extends Readable { 5 | 6 | public pos = 0; 7 | 8 | constructor(public chunks?: Array, public debugLog?: LogFunction) { 9 | super(); 10 | this.on("error", (err) => { 11 | if (this.debugLog) { 12 | this.debugLog(LogType.error, () => `memstream error: ${err}`); 13 | } 14 | }); 15 | } 16 | 17 | public _read(size: number) { 18 | if (this.chunks) { 19 | if (this.pos < this.chunks.length) { 20 | if (this.chunks[this.pos] === null) { 21 | process.nextTick(() => this.emit("error", new Error("Null Chunk"))); 22 | } else { 23 | this.push(this.chunks[this.pos++]); 24 | } 25 | } else { 26 | this.push(null); 27 | } 28 | } else { 29 | this.push(null); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/common/mem-writer.ts: -------------------------------------------------------------------------------- 1 | import { Writable } from "stream"; 2 | import { LogFunction, LogType } from "./log-type"; 3 | 4 | export class MemoryWriteStream extends Writable { 5 | 6 | public static badChunk: Buffer = Buffer.from([0, 0, 0, 0, 0]); 7 | 8 | public chunks: Buffer[] = []; 9 | 10 | constructor(public debugLog?: LogFunction, public emulateError?: boolean) { 11 | super(); 12 | this.on("error", (err) => { 13 | if (this.debugLog) { 14 | this.debugLog(LogType.error, () => `memstream error: ${err}`); 15 | } 16 | }); 17 | } 18 | 19 | public _write(chunk: any, encoding: string, callback: (err?: Error) => any) { 20 | if (this.emulateError) { 21 | callback(new Error("Writing prohibited")); 22 | } 23 | if (Buffer.isBuffer(chunk)) { 24 | if (chunk.equals(MemoryWriteStream.badChunk)) { 25 | callback(new Error("Bad chunk encountered")); 26 | } else { 27 | this.chunks.push(chunk); 28 | callback(); 29 | } 30 | } else { 31 | callback(new Error("Chunk isn't Buffer")); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/common/parser/CompletionProvider.ts: -------------------------------------------------------------------------------- 1 | import { FacadeImpl } from "./Facade"; 2 | import { TextDocument, Position, CancellationToken, ProviderResult, CompletionList, CompletionItem } from "vscode"; 3 | 4 | export class CompletionItemProviderImpl 5 | { 6 | constructor(private backend: FacadeImpl) { } 7 | 8 | public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 9 | { 10 | let candidates = this.backend.getCodeCompletionCandidates(document.fileName, position.character, position.line); 11 | let completionList: CompletionItem[] = []; 12 | 13 | candidates.forEach(candidate => { 14 | let item = new CompletionItem(candidate.candidate); 15 | item.detail = candidate.description; 16 | completionList.push(item); 17 | }); 18 | 19 | return new CompletionList(completionList, false); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/common/parser/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { FacadeImpl } from './Facade'; 3 | 4 | export class DefinitionProviderImpl implements DefinitionProvider { 5 | constructor(private backend: FacadeImpl) { 6 | } 7 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 8 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line); 9 | if (info && info.definition) { 10 | let range = new Range(0,0,0,0); 11 | if (info.definition.range) { 12 | range = new Range( 13 | info.definition.range.start.row, info.definition.range.start.col, 14 | info.definition.range.end.row, info.definition.range.end.col 15 | ); 16 | } 17 | return new Location(Uri.file(info.definition.source), range); 18 | } 19 | return undefined; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/common/parser/ErrorListeners.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 4 | import { IDiagnosticEntry, EDiagnosticType } from './Facade'; 5 | 6 | 7 | export class LexerErrorListener implements ANTLRErrorListener 8 | { 9 | constructor(private errorList: IDiagnosticEntry[]) 10 | { } 11 | 12 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 13 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 14 | { 15 | let error: IDiagnosticEntry = { 16 | type: EDiagnosticType.Error, 17 | message: msg, 18 | range: { start: { col: charPositionInLine, row: line }, end: { col: charPositionInLine + 1, row: line }} 19 | }; 20 | 21 | this.errorList.push(error); 22 | } 23 | } 24 | 25 | export class ParserErrorListener implements ANTLRErrorListener 26 | { 27 | constructor(private errorList: IDiagnosticEntry[]) { 28 | } 29 | 30 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 31 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 32 | { 33 | let error: IDiagnosticEntry = { 34 | type: EDiagnosticType.Error, 35 | message: msg, 36 | range: { start: { col: charPositionInLine, row: line }, end: { col: charPositionInLine + 1, row: line }} 37 | }; 38 | 39 | if (offendingSymbol) { 40 | error.range.end.col = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 41 | } 42 | 43 | this.errorList.push(error); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/common/parser/HoverProvider.ts: -------------------------------------------------------------------------------- 1 | import { HoverProvider, TextDocument, Position, CancellationToken, Hover, workspace } from "vscode"; 2 | import { FacadeImpl } from "./Facade"; 3 | import * as path from 'path'; 4 | 5 | export class HoverProviderImpl implements HoverProvider { 6 | constructor(private backend: FacadeImpl) { 7 | } 8 | public async provideHover(document: TextDocument, position: Position, token: CancellationToken) { 9 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line); 10 | if (info) { 11 | let defStr = ""; 12 | if (info.definition) { 13 | if (info.definition.source) { 14 | defStr = workspace.asRelativePath(info.definition.source, true); 15 | } 16 | if (info.definition.text) { 17 | defStr = `defined in ${defStr}`; 18 | if (info.definition.range) { 19 | defStr += ` at ${info.definition.range.start.row + 1}:${info.definition.range.start.col + 1}`; 20 | } 21 | } else { 22 | defStr = `from ${defStr}`; 23 | } 24 | } 25 | return new Hover([ 26 | `**${info.kindString}** ${defStr}`, 27 | info.description 28 | ]); 29 | } 30 | return undefined; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/common/parser/ReferenceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | Location, 4 | Position, 5 | ProviderResult, 6 | Range, 7 | ReferenceContext, 8 | ReferenceProvider, 9 | TextDocument, 10 | Uri, 11 | } from 'vscode'; 12 | import { FacadeImpl } from './Facade'; 13 | 14 | export class ReferenceProviderImpl implements ReferenceProvider { 15 | 16 | constructor(private backend: FacadeImpl) { 17 | } 18 | 19 | public provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult { 20 | const occurences = this.backend.getOccurencesUnderCursor(document.fileName, position.character, position.line); 21 | const result: Location[] = []; 22 | 23 | if (occurences.length > 0 ) { 24 | for (let ocuurance of occurences) { 25 | if (ocuurance.range) { 26 | let range = new Range( 27 | ocuurance.range.start.row, ocuurance.range.start.col, 28 | ocuurance.range.end.row, ocuurance.range.end.col 29 | ); 30 | const loc: Location = { 31 | range, 32 | uri: Uri.file(ocuurance.source), 33 | }; 34 | result.push(loc); 35 | } 36 | } 37 | } 38 | 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/common/parser/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { FacadeImpl } from './Facade'; 3 | 4 | export class RenameProviderImpl implements RenameProvider { 5 | constructor(private backend: FacadeImpl) { 6 | } 7 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult { 8 | const occurences = this.backend.getOccurencesUnderCursor(document.fileName, position.character, position.line); 9 | if (occurences.length) { 10 | const result = new WorkspaceEdit(); 11 | for (let occurance of occurences) { 12 | if (occurance.text && occurance.range) { 13 | let range = new Range( 14 | occurance.range.start.row, occurance.range.start.col, 15 | occurance.range.end.row, occurance.range.end.col 16 | ); 17 | let replaceName = newName; 18 | if (occurance.quotas) { 19 | replaceName = occurance.quotas + newName + occurance.quotas[occurance.quotas.length - 1]; 20 | } 21 | result.replace(Uri.file(occurance.source), range, replaceName); 22 | } 23 | } 24 | return result; 25 | } 26 | return undefined; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/common/print-like.ts: -------------------------------------------------------------------------------- 1 | 2 | export function printLike(strings: TemplateStringsArray, ...values: T) { 3 | return (...p: T) => { 4 | let str = ""; 5 | for (let i = 0; i < p.length; i++) { 6 | str += strings[i]; 7 | str += p[i]; 8 | } 9 | str += strings[strings.length - 1]; 10 | return str; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/common/print-syntax-tree.ts: -------------------------------------------------------------------------------- 1 | import { Parser, ParserRuleContext } from "antlr4ts"; 2 | import { ParseTree, Trees } from "antlr4ts/tree"; 3 | 4 | export function getSyntaxTreeStrings(parser: Parser, root: ParseTree) : string[] { 5 | return recursive(root, 0, parser); 6 | } 7 | 8 | function recursive(root: ParseTree, offset: number, parser: Parser): string[] { 9 | let buf = [" ".repeat(offset) + Trees.getNodeText(root, parser.ruleNames)]; 10 | if (root instanceof ParserRuleContext) { 11 | if (root.children != null) { 12 | for (let child of root.children) { 13 | buf.push(...recursive(child, offset + 1, parser)); 14 | } 15 | } 16 | } 17 | // else if (root instanceof TerminalNode) { 18 | // let symbName = parser.vocabulary.getSymbolicName(root.symbol.type); 19 | // if (symbName) { 20 | // buf[buf.length-1] += ' <' + symbName + '>'; 21 | // } 22 | // } 23 | return buf; 24 | } -------------------------------------------------------------------------------- /src/common/quotes.ts: -------------------------------------------------------------------------------- 1 | export function test_enclosing_quotes(str: string) { 2 | let first_char = str[0]; 3 | if (first_char === '"' || first_char === "'") { 4 | for(let i = 1; i < str.length; ++i) { 5 | if (str[i] == '\\') { 6 | ++i; 7 | } else if (str[i] == first_char) { 8 | return { enclosed: true, quote_pos: i } ; 9 | } 10 | } 11 | } 12 | return { enclosed: false, quote_pos: -1 } ; 13 | } -------------------------------------------------------------------------------- /src/common/read_all_stream.ts: -------------------------------------------------------------------------------- 1 | import { Readable, Writable } from "stream"; 2 | 3 | export async function readWholeStream(stream: Readable | undefined) { 4 | return new Promise((resolve) => { 5 | if (stream) { 6 | const chunks: Buffer[] = []; 7 | stream.on('data', chunk => Buffer.isBuffer(chunk) ? chunks.push(chunk) : undefined); 8 | stream.on('error', () => resolve("")); 9 | stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); 10 | } else { 11 | resolve(""); 12 | } 13 | }); 14 | } 15 | 16 | export async function writeWholeStream(stream: Writable | undefined, data: Buffer | string) { 17 | if (typeof data === "string") { 18 | data = Buffer.from(data, "utf-8"); 19 | } 20 | return new Promise(async (resolve) => { 21 | if (stream) { 22 | stream.write(data); 23 | stream.end(); 24 | } else { 25 | resolve(false); 26 | } 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /src/common/resolve.ts: -------------------------------------------------------------------------------- 1 | export type Resolve = ((value?: T | PromiseLike | undefined) => void); 2 | export type Reject = ((reason?: any) => void); -------------------------------------------------------------------------------- /src/common/rgx-from-str.ts: -------------------------------------------------------------------------------- 1 | 2 | export function RgxFromStr(str: string, mode = "g") { 3 | return new RegExp(RgxStrFromStr(str), mode); 4 | } 5 | 6 | export function RgxStrFromStr(str: string) { 7 | return str.replace(/[.*+?^${}()|[\]\\\/]/g, "\\$&"); 8 | } 9 | 10 | export function maskSpacesInTemplate(str: string, mask?: string) { 11 | mask = mask || "*"; 12 | let depth = 0; 13 | let result = ""; 14 | for(let i = 0; i < str.length; ++i) { 15 | switch (str[i] ) { 16 | case '<': 17 | ++depth; 18 | result += str[i]; 19 | break; 20 | case '>': 21 | if (depth) { 22 | --depth; 23 | } 24 | result += str[i]; 25 | break; 26 | default: 27 | if (depth && str[i] === ' ') { 28 | result += mask; 29 | } else { 30 | result += str[i]; 31 | } 32 | } 33 | } 34 | return result; 35 | } 36 | 37 | export function removeTemplate(str: string) { 38 | let depth = 0; 39 | let result = ""; 40 | for(let i = 0; i < str.length; ++i) { 41 | switch (str[i] ) { 42 | case '<': 43 | ++depth; 44 | break; 45 | case '>': 46 | if (depth) { 47 | --depth; 48 | } 49 | break; 50 | default: 51 | if (!depth) { 52 | result += str[i]; 53 | } 54 | } 55 | } 56 | return result; 57 | } 58 | -------------------------------------------------------------------------------- /src/common/simply-compare.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * True if equal 4 | * @param a 5 | * @param b 6 | */ 7 | export function isSimplyEq(a: any, b: any): boolean { 8 | if (a === b) { 9 | return true; 10 | } 11 | if (a === undefined || b === undefined) { 12 | return false; 13 | } 14 | let count = 0; 15 | for (const key in a) { 16 | if (a.hasOwnProperty(key)) { 17 | if ( b.hasOwnProperty(key) && a[key] === b[key] ) { 18 | ++ count; 19 | continue; 20 | } 21 | return false; 22 | } 23 | } 24 | for (const key in b) { 25 | if (b.hasOwnProperty(key)) { 26 | -- count; 27 | } 28 | } 29 | return count === 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/common/subscribe.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | 3 | export interface IUnSubscribe { 4 | unsubscribe: () => void; 5 | } 6 | 7 | export function Subscribe(emitter: EventEmitter, event: string | symbol, listener: (...args: any[]) => void) 8 | : IUnSubscribe { 9 | emitter.on(event, listener); 10 | return { unsubscribe: () => { 11 | emitter.removeListener(event, listener); 12 | }}; 13 | } 14 | -------------------------------------------------------------------------------- /src/common/task-count.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | 3 | export class TaskCount { 4 | 5 | private emitter = new EventEmitter(); 6 | private counter = 0; 7 | 8 | public getCount() { 9 | return this.counter; 10 | } 11 | 12 | public taskStarted() { 13 | ++this.counter; 14 | } 15 | 16 | public waitAllTask(): Promise { 17 | return new Promise((resolve) => { 18 | if (this.counter === 0) { 19 | resolve(true); 20 | } else { 21 | // Otherwise, wait until somebody releases the lock and try again 22 | const testTask = () => { 23 | if (this.counter === 0) { 24 | this.emitter.removeListener("taskEnded", testTask); 25 | this.emitter.setMaxListeners(Math.max(0, this.emitter.getMaxListeners() - 1)); 26 | return resolve(true); 27 | } 28 | }; 29 | this.emitter.setMaxListeners(this.emitter.getMaxListeners() + 1); 30 | this.emitter.on("taskEnded", testTask); 31 | } 32 | }); 33 | } 34 | 35 | public taskEnded() { 36 | --this.counter; 37 | setImmediate(() => this.emitter.emit("taskEnded")); 38 | } 39 | } -------------------------------------------------------------------------------- /src/common/task-divider.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Allow task to break its execution and other task can change asyncValue. 4 | * For example - to cancel current async task 5 | */ 6 | export class TaskDivider { 7 | constructor(public asyncValue: T) { 8 | } 9 | 10 | public async testValue() { 11 | return new Promise(resolve => { 12 | setImmediate(() => { 13 | resolve(this.asyncValue); 14 | }); 15 | }); 16 | } 17 | } -------------------------------------------------------------------------------- /src/common/wait-fire-event-emitter.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | import { LogFunction } from "./log-type"; 3 | import { Subscribe } from "./subscribe"; 4 | 5 | /** 6 | * Waiting _wait_msec before firing the event. If a new fire() was called while waiting, the timeout starts again. 7 | * Only last event will be fired, all previous data will be discarded. 8 | */ 9 | export class WaitFireEventEmitter { 10 | 11 | private fireSoonHandle?: NodeJS.Timeout; 12 | private emitter = new EventEmitter(); 13 | private event = Symbol(); 14 | 15 | constructor(private waitMsec: number, public debugLog?: LogFunction) { 16 | } 17 | 18 | public fire(data?: T) { 19 | this.fireSoon(data); 20 | } 21 | 22 | public dispose(): void { 23 | if (this.fireSoonHandle) { 24 | clearTimeout(this.fireSoonHandle); 25 | this.fireSoonHandle = undefined; 26 | } 27 | } 28 | 29 | public Subscribe(listener: (...args: any[]) => void) { 30 | return Subscribe(this.emitter, this.event, listener); 31 | } 32 | 33 | private fireSoon(data?: T ): void { 34 | if (this.fireSoonHandle) { 35 | clearTimeout(this.fireSoonHandle); 36 | } 37 | this.fireSoonHandle = setTimeout(() => { 38 | this.emitter.emit(this.event, data); 39 | }, this.waitMsec); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/config-helper/command-context.ts: -------------------------------------------------------------------------------- 1 | import { commands } from "vscode"; 2 | 3 | export enum CommandContext { 4 | isSingleRoot = "vmssoftware.isSingleRoot", 5 | isTestEnabled = "vmssoftware.config-helper.test:enabled", 6 | } 7 | 8 | export function setContext(context: CommandContext, state: boolean) { 9 | commands.executeCommand("setContext", context, state); 10 | } 11 | -------------------------------------------------------------------------------- /src/config-helper/config/config-hepler-section.ts: -------------------------------------------------------------------------------- 1 | import { IConfigData, IConfigSection } from "./config"; 2 | 3 | export class ConfigHelperSection implements IConfigSection { 4 | 5 | public static readonly section = "settings"; 6 | 7 | public static is(candidate: any): candidate is ConfigHelperSection { 8 | return !!candidate && 9 | typeof candidate.addCalleeInfo === "boolean" && 10 | typeof candidate.debug === "string" && 11 | typeof candidate.test === "string" && 12 | typeof candidate.using === "string"; 13 | } 14 | 15 | public addCalleeInfo: boolean = false; 16 | public debug: string = ""; 17 | public test: string = "test"; 18 | public using: "FS" | "VSC" | "VFS" = "FS"; 19 | 20 | public name(): string { 21 | return ConfigHelperSection.section; 22 | } 23 | 24 | public store(): IConfigData { 25 | return { 26 | addCalleeInfo: this.addCalleeInfo, 27 | debug: this.debug, 28 | test: this.test, 29 | using: this.using, 30 | }; 31 | } 32 | 33 | public templateToFillFrom(): IConfigData { 34 | return this.store(); 35 | } 36 | 37 | public fillFrom(data: IConfigData): boolean { 38 | if (ConfigHelperSection.is(data)) { 39 | this.addCalleeInfo = data.addCalleeInfo; 40 | this.debug = data.debug; 41 | this.test = data.test; 42 | switch (data.using) { 43 | case "FS": 44 | case "VSC": 45 | case "VFS": 46 | this.using = data.using; 47 | break; 48 | default: 49 | this.using = "FS"; 50 | break; 51 | } 52 | return true; 53 | } 54 | return false; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/config-helper/config/dummy-editor.ts: -------------------------------------------------------------------------------- 1 | import { IConfigEditor } from "./config"; 2 | 3 | /** 4 | * Dummy Editor implementation 5 | */ 6 | export class DummyEditor implements IConfigEditor { 7 | public invoke(): Promise { 8 | return Promise.resolve(false); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/config-helper/config/dummy-storage.ts: -------------------------------------------------------------------------------- 1 | import { CSAResult, IConfigStorage } from "./config"; 2 | 3 | /** 4 | * Dummy Storage implementations 5 | */ 6 | 7 | export class DummyStorage implements IConfigStorage { 8 | 9 | public fillStart(): Promise { 10 | return Promise.resolve(CSAResult.prepare_failed); 11 | } 12 | 13 | public fillData(): Promise { 14 | return Promise.resolve(CSAResult.some_data_failed); 15 | } 16 | 17 | public fillEnd(): Promise { 18 | return Promise.resolve(CSAResult.end_failed); 19 | } 20 | 21 | public storeStart(): Promise { 22 | return Promise.resolve(CSAResult.prepare_failed); 23 | } 24 | 25 | public storeData(): Promise { 26 | return Promise.resolve(CSAResult.some_data_failed); 27 | } 28 | 29 | public storeEnd(): Promise { 30 | return Promise.resolve(CSAResult.end_failed); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config-helper/config/fs-storage.ts: -------------------------------------------------------------------------------- 1 | import fs, { exists } from "fs"; 2 | import path from "path"; 3 | import util from "util"; 4 | 5 | import { LogFunction, LogType } from "../../common/main"; 6 | import { CSAResult, IConfigData, IConfigStorage } from "./config"; 7 | import { ConfigStorageImpl } from "./storage-impl"; 8 | 9 | const fsExist = util.promisify(fs.exists); 10 | const fsReadFile = util.promisify(fs.readFile); 11 | const fsWriteFile = util.promisify(fs.writeFile); 12 | const fsMkDir = util.promisify(fs.mkdir); 13 | 14 | /** 15 | * FSConfigStorage 16 | */ 17 | export class FSConfigStorage extends ConfigStorageImpl { 18 | 19 | constructor(protected fileName: string, logFn?: LogFunction) { 20 | super(logFn); 21 | } 22 | 23 | public fillStart(): Promise { 24 | return fsReadFile(this.fileName) 25 | .then((data) => { 26 | this.content = data.toString("utf8"); 27 | return super.fillStart(); 28 | }).catch((err) => { 29 | this.logFn(LogType.debug, () => `${err}`); 30 | return CSAResult.prepare_failed; 31 | }); 32 | } 33 | 34 | public storeEnd(): Promise { 35 | return super.storeEnd() 36 | .then((result) => { 37 | if (result === CSAResult.ok) { 38 | const dir = path.dirname(this.fileName); 39 | return fsExist(dir).then((ok) => { 40 | if (!ok) { 41 | return fsMkDir(dir); 42 | } 43 | }).then(() => { 44 | return fsWriteFile(this.fileName, this.content ? this.content : "") 45 | .then(() => { 46 | this.logFn(LogType.debug, () => "fsWriteFile => ok"); 47 | return CSAResult.ok; 48 | }); 49 | }).catch((err) => { 50 | this.logFn(LogType.debug, () => `fsWriteFile => fail ${err}`); 51 | return CSAResult.end_failed; 52 | }); 53 | } 54 | return result; 55 | }); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/config-helper/config/uri-editor.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Uri, window, workspace, Range, WorkspaceEdit, Position } from "vscode"; 3 | 4 | import { LogFunction, LogType } from "../../common/main"; 5 | import { IConfig, IConfigEditor, CSAResult } from "./config"; 6 | import { ConfigStorageImpl } from "./storage-impl"; 7 | 8 | // import * as nls from "vscode-nls"; 9 | // nls.config({messageFormat: nls.MessageFormat.both}); 10 | // const localize = nls.loadMessageBundle(); 11 | 12 | export class UriEditor implements IConfigEditor { 13 | 14 | constructor(protected uri: Uri, protected cfg: IConfig, public logFn?: LogFunction) { 15 | 16 | } 17 | 18 | public invoke(): Promise { 19 | return new Promise((resolve) => { 20 | const buffer = new ConfigStorageImpl(); 21 | this.cfg.save(buffer).then(async (result) => { 22 | if (result === CSAResult.ok && buffer.GetContent()) { 23 | try { 24 | let range: Range | undefined; 25 | try { 26 | const textDoc = await workspace.openTextDocument(this.uri); 27 | range = textDoc.validateRange(new Range(0, 0, 32767, 32767)); 28 | } catch (err) { 29 | range = undefined; 30 | } 31 | const we = new WorkspaceEdit(); 32 | const str = buffer.GetContent(); 33 | let uri = this.uri; 34 | if (!range) { 35 | uri = this.uri.with({ scheme: "untitled"}); 36 | we.insert(uri, new Position(0, 0), str!); 37 | } else { 38 | we.replace(uri, range, str!); 39 | } 40 | const doc = await workspace.openTextDocument(uri); 41 | const applied = await workspace.applyEdit(we); 42 | await window.showTextDocument(doc, { preview: false }); 43 | resolve(true); 44 | } catch (err) { 45 | resolve(false); 46 | } 47 | } else { 48 | resolve(false); 49 | } 50 | }); 51 | }); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/config-helper/config/vfs-config-helper.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from "vscode"; 2 | 3 | import { LogFunction, LogType } from "../../common/main"; 4 | import { FSConfigHelper } from "./fs-config-helper"; 5 | import { VFSConfigStorage } from "./vfs-storage"; 6 | 7 | // import * as nls from "vscode-nls"; 8 | // nls.config({messageFormat: nls.MessageFormat.both}); 9 | // const localize = nls.loadMessageBundle(); 10 | 11 | /** 12 | * ConfigHelper implementation 13 | */ 14 | export class VFSConfigHelper extends FSConfigHelper { 15 | 16 | protected createConcreteFS_Storage(uri: Uri, logFn?: LogFunction) { 17 | // TODO: test URI and return appropriate FS 18 | return new VFSConfigStorage(uri, logFn); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/config-helper/config/vsc-config-helper.ts: -------------------------------------------------------------------------------- 1 | import { Disposable, Uri, workspace, WorkspaceFolder } from "vscode"; 2 | 3 | import { Debouncer, LogFunction, LogType } from "../../common/main"; 4 | 5 | import { CSAResult, IConfig, IConfigEditor, IConfigHelper, IConfigStorage } from "./config"; 6 | import { ConfigPool } from "./config-pool"; 7 | import { VSCWorkspaceConfigEditor } from "./vsc-editor"; 8 | import { VSCConfigStorage } from "./vsc-storage"; 9 | 10 | // import * as nls from "vscode-nls"; 11 | // nls.config({messageFormat: nls.MessageFormat.both}); 12 | // const localize = nls.loadMessageBundle(); 13 | 14 | /** 15 | * ConfigHelper implementation 16 | */ 17 | export class VSCConfigHelper implements IConfigHelper { 18 | 19 | protected logFn: LogFunction; 20 | 21 | protected config: ConfigPool; 22 | protected storage: IConfigStorage; 23 | protected editor: IConfigEditor; 24 | protected debouncer = new Debouncer(3000); 25 | protected disposables: Disposable[] = []; 26 | 27 | constructor(public workspaceFolder: WorkspaceFolder | undefined, protected extension: string, logFn?: LogFunction) { 28 | // tslint:disable-next-line:no-empty 29 | this.logFn = logFn || (() => {}); 30 | this.storage = new VSCConfigStorage(this.workspaceFolder, this.extension, logFn); 31 | this.config = new ConfigPool(this.storage, logFn); 32 | this.editor = new VSCWorkspaceConfigEditor(this.config, logFn); 33 | this.disposables.push( workspace.onDidChangeConfiguration((e) => { 34 | if (e.affectsConfiguration(this.extension)) { 35 | this.config.freeze(); 36 | this.logFn(LogType.debug, () => "onDidChangeConfiguration"); 37 | this.debouncer.debounce().then(async () => { 38 | await this.config.load().then(result => this.config.lastResult |= result); 39 | this.config.unfreeze(); 40 | }); 41 | } 42 | })); 43 | } 44 | 45 | public dispose() { 46 | for (const disp of this.disposables) { 47 | disp.dispose(); 48 | } 49 | this.disposables = []; 50 | } 51 | 52 | public getConfig(): IConfig { 53 | return this.config; 54 | } 55 | 56 | public getEditor(): IConfigEditor { 57 | return this.editor; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/config-helper/config/vsc-editor.ts: -------------------------------------------------------------------------------- 1 | import { commands } from "vscode"; 2 | 3 | import { LogFunction, LogType } from "../../common/main"; 4 | import { IConfig, IConfigEditor } from "./config"; 5 | 6 | // import * as nls from "vscode-nls"; 7 | // nls.config({messageFormat: nls.MessageFormat.both}); 8 | // const localize = nls.loadMessageBundle(); 9 | 10 | export class VSCWorkspaceConfigEditor implements IConfigEditor { 11 | 12 | protected readonly command = "workbench.action.openWorkspaceSettings"; 13 | 14 | constructor(protected cfg: IConfig, protected logFn?: LogFunction) { 15 | 16 | } 17 | 18 | public invoke(): Promise { 19 | return new Promise((resolve) => { 20 | this.cfg.save().then(() => { 21 | // execute edit command in any case 22 | commands.executeCommand(this.command).then(() => { 23 | resolve(true); 24 | }, () => { 25 | resolve(false); 26 | }); 27 | }); 28 | }); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/config-helper/extension.ts: -------------------------------------------------------------------------------- 1 | import { commands, env, ExtensionContext, workspace } from "vscode"; 2 | import { CommandContext, setContext } from "./command-context"; 3 | 4 | import { ConfigApi } from "./config/config-api"; 5 | import { ConfigHelperSection } from "./config/config-hepler-section"; 6 | import { createLogFunction } from "./log"; 7 | 8 | const locale = env.language ; 9 | import * as nls from "vscode-nls"; 10 | const localize = nls.config({ locale, messageFormat: nls.MessageFormat.both })(); 11 | 12 | const logFn = createLogFunction("VMS-IDE"); 13 | 14 | export function activate(context: ExtensionContext) { 15 | 16 | const configApi = new ConfigApi(logFn); 17 | 18 | // setContext(CommandContext.isTestEnabled, true); // to test command, also required "*" in "activationEvents" in package.json 19 | 20 | setContext(CommandContext.isSingleRoot, (workspace.workspaceFolders !== undefined && workspace.workspaceFolders.length === 1)); 21 | context.subscriptions.push( workspace.onDidChangeWorkspaceFolders(() => { 22 | setContext(CommandContext.isSingleRoot, (workspace.workspaceFolders !== undefined && workspace.workspaceFolders.length === 1)); 23 | })); 24 | 25 | // context.subscriptions.push( commands.registerCommand("vmssoftware.config-helper.test", async () => { 26 | // // 27 | // const configHelper = configApi.getConfigHelper("vmssoftware.config-helper"); 28 | // if (configHelper) { 29 | // let test = await configHelper.getConfig().get(ConfigHelperSection.section); 30 | // if (!ConfigHelperSection.is(test)) { 31 | // configHelper.getConfig().add(new ConfigHelperSection()); 32 | // test = await configHelper.getConfig().get(ConfigHelperSection.section); 33 | // } 34 | // if (ConfigHelperSection.is(test)) { 35 | // test.test = "passed"; 36 | // configHelper.getConfig().save(); 37 | // } 38 | // } 39 | // })); 40 | 41 | return configApi; 42 | } 43 | 44 | export function deactivate() { 45 | // 46 | } 47 | -------------------------------------------------------------------------------- /src/ext-api/ext-api.ts: -------------------------------------------------------------------------------- 1 | 2 | import { IConfigApi } from "../config-helper/config/config"; 3 | import { SshHelper } from "../ssh-helper/ssh-helper"; 4 | import { SyncApi } from "../synchronizer/sync/sync-api"; 5 | import { ZipApi } from "../zip/zip-api"; 6 | 7 | let configApi: IConfigApi | undefined; 8 | let sshHelperType: typeof SshHelper | undefined; 9 | let syncApi: SyncApi | undefined; 10 | let zipApi: typeof ZipApi | undefined; 11 | 12 | export function SetConfigHelperApi(newConfigApi: IConfigApi| undefined) { 13 | configApi = newConfigApi; 14 | } 15 | 16 | export function GetConfigHelperFromApi() { 17 | return configApi; 18 | } 19 | 20 | export function SetSshHelper(newSshHelper: typeof SshHelper | undefined) { 21 | sshHelperType = newSshHelper; 22 | } 23 | 24 | export function GetSshHelperType() { 25 | return sshHelperType; 26 | } 27 | 28 | export function GetSyncApi() { 29 | return syncApi; 30 | } 31 | 32 | export function SetSyncApi(newSyncApi: SyncApi | undefined) { 33 | syncApi = newSyncApi; 34 | } 35 | 36 | export function GetZipApi() { 37 | return zipApi; 38 | } 39 | 40 | export function SetZipApi(newZipApi: typeof ZipApi | undefined) { 41 | zipApi = newZipApi; 42 | } 43 | -------------------------------------------------------------------------------- /src/msg/ContextErrorListener.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is released under the MIT license. 3 | * Copyright (c) 2016, 2017 Mike Lischke 4 | * 5 | * See LICENSE file for more info. 6 | */ 7 | 8 | "use strict"; 9 | 10 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 11 | 12 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 13 | 14 | export class ContextLexerErrorListener implements ANTLRErrorListener { 15 | constructor(private errorList: DiagnosticEntry[]) { 16 | } 17 | 18 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 19 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void { 20 | let error: DiagnosticEntry = { 21 | type: DiagnosticType.Error, 22 | message: msg, 23 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 24 | }; 25 | 26 | this.errorList.push(error); 27 | } 28 | } 29 | 30 | export class ContextErrorListener implements ANTLRErrorListener { 31 | constructor(private errorList: DiagnosticEntry[]) { 32 | } 33 | 34 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 35 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void { 36 | let error: DiagnosticEntry = { 37 | type: DiagnosticType.Error, 38 | message: msg, 39 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 40 | }; 41 | 42 | if (offendingSymbol) { 43 | error.range.end.column = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 44 | } 45 | this.errorList.push(error); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/msg/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { MsgFacade } from './Facade'; 3 | 4 | export class MsgDefinitionProvider implements DefinitionProvider { 5 | constructor(private backend: MsgFacade) { } 6 | 7 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 8 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 9 | 10 | if (!info) { 11 | return undefined; 12 | } 13 | 14 | if (info.definition) { 15 | let range = new Range( 16 | info.definition.range.start.row - 1, info.definition.range.start.column, 17 | info.definition.range.end.row - 1, info.definition.range.end.column 18 | ); 19 | return new Location(Uri.file(info.source), range); 20 | } else { 21 | // Empty for built-in entities. 22 | let position = new Position(0, 0); 23 | return new Location(Uri.parse(""), position); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/msg/HoverProvider.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { HoverProvider, TextDocument, Position, CancellationToken, ProviderResult, Hover } from "vscode"; 3 | import { MsgFacade } from "./Facade"; 4 | import { symbolDescriptionFromEnum } from './Symbol'; 5 | 6 | export class MsgHoverProvider implements HoverProvider { 7 | constructor(private backend: MsgFacade) { } 8 | 9 | public provideHover(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 10 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 11 | if (!info) { 12 | return undefined; 13 | } 14 | 15 | return new Hover([ 16 | info.description? info.description : symbolDescriptionFromEnum(info.kind) 17 | ]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/msg/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { MsgFacade, SymbolKind, SymbolInfo } from './Facade'; 3 | 4 | export class MsgRenameProvider implements RenameProvider { 5 | constructor(private backend: MsgFacade) { } 6 | 7 | public prepareRename(document: TextDocument, position: Position, token: CancellationToken): ProviderResult { 8 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character, position.line + 1); 9 | 10 | if (info && info.definition) { 11 | return new Range( 12 | info.definition.range.start.row - 1, 13 | info.definition.range.start.column, 14 | info.definition.range.end.row - 1, 15 | info.definition.range.end.column); 16 | } 17 | 18 | return undefined; 19 | } 20 | 21 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, 22 | token: CancellationToken): ProviderResult { 23 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 24 | if (occurences.length) { 25 | const result = new WorkspaceEdit(); 26 | for (let symbol of occurences) { 27 | if (symbol.definition) { 28 | let range = new Range( 29 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 30 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 31 | ); 32 | result.replace(Uri.file(symbol.source), range, newName); 33 | } 34 | } 35 | return result; 36 | } 37 | return undefined; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/msg/Symbol.ts: -------------------------------------------------------------------------------- 1 | import * as nls from "vscode-nls"; 2 | import * as vscode from 'vscode'; 3 | import { SymbolKind } from './Facade'; 4 | 5 | nls.config({messageFormat: nls.MessageFormat.both}); 6 | const localize = nls.loadMessageBundle(); 7 | 8 | /** 9 | * Provides a textual expression for a native symbol kind. 10 | */ 11 | export function symbolDescriptionFromEnum(kind: SymbolKind): string { 12 | // Could be localized. 13 | switch (kind) { 14 | case SymbolKind.Keyword: 15 | return localize("keyword", "Keyword"); 16 | case SymbolKind.Operator: 17 | return localize("operator", "Operator"); 18 | case SymbolKind.Literal: 19 | return localize("literal", "Literal"); 20 | case SymbolKind.Message: 21 | return localize("message", "Message"); 22 | case SymbolKind.Variable: 23 | return localize("variable", "Variable"); 24 | case SymbolKind.FacilityName: 25 | return localize("facility", "Facility name"); 26 | case SymbolKind.FacilityPrefix: 27 | return localize("prefix", "Facility prefix"); 28 | default: 29 | return "Unknown type"; 30 | } 31 | } 32 | 33 | /** 34 | * Converts the native symbol kind to a vscode symbol kind. 35 | */ 36 | export function translateSymbolKind(kind: SymbolKind): vscode.SymbolKind { 37 | switch (kind) { 38 | 39 | default: 40 | return vscode.SymbolKind.Null; 41 | } 42 | } 43 | 44 | /** 45 | * Converts the native symbol kind to a vscode symbol kind. 46 | */ 47 | export function translateCompletionKind(kind: SymbolKind): vscode.CompletionItemKind { 48 | switch (kind) { 49 | case SymbolKind.Keyword: 50 | return vscode.CompletionItemKind.Keyword; 51 | 52 | default: 53 | return vscode.CompletionItemKind.Text; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/msg/msg.tokens: -------------------------------------------------------------------------------- 1 | TITLE=1 2 | IDENT=2 3 | PAGE=3 4 | LITERAL=4 5 | FACILITY=5 6 | SEVERITY=6 7 | BASE=7 8 | END=8 9 | PREFIX=9 10 | SHARED=10 11 | SYSTEM=11 12 | FAOCOUNT=12 13 | IDENTIFICATION=13 14 | USERVALUE=14 15 | SUCCESS=15 16 | INFORMATIONAL=16 17 | WARNING=17 18 | ERROR=18 19 | SEVERE=19 20 | FATAL=20 21 | WHITESPACE=21 22 | NEWLINE=22 23 | NAME=23 24 | NUMBER=24 25 | ASSIGN=25 26 | ADD=26 27 | SUB=27 28 | MUL=28 29 | DIV=29 30 | SHIFT=30 31 | SHARP=31 32 | PERC=32 33 | POW=33 34 | UNDER=34 35 | P_OPEN=35 36 | P_CLOS=36 37 | HEXNUM=37 38 | OCTNUM=38 39 | DECNUM=39 40 | DOT=40 41 | COMMA=41 42 | EXCL=42 43 | ASTRING_OPEN=43 44 | QSTRING_OPEN=44 45 | BSTRING_OPEN=45 46 | ANY=46 47 | IDENTSEP=47 48 | IDENTNAME=48 49 | IDENTSTRING=49 50 | IDENTCOMMENT=50 51 | IDENT_CLOSE=51 52 | BSTRING_CLOSE=52 53 | BFAO=53 54 | BTEXT=54 55 | QSTRING_CLOSE=55 56 | QFAO=56 57 | QTEXT=57 58 | ASTRING_CLOSE=58 59 | AFAO=59 60 | ATEXT=60 61 | '='=25 62 | '+'=26 63 | '-'=27 64 | '*'=28 65 | '/'=29 66 | '@'=30 67 | '#'=31 68 | '%'=32 69 | '^'=33 70 | '_'=34 71 | '('=35 72 | ')'=36 73 | '.'=40 74 | ','=41 75 | '!'=42 76 | '<'=45 77 | '>'=52 78 | -------------------------------------------------------------------------------- /src/msg/msgLex.tokens: -------------------------------------------------------------------------------- 1 | TITLE=1 2 | IDENT=2 3 | PAGE=3 4 | LITERAL=4 5 | FACILITY=5 6 | SEVERITY=6 7 | BASE=7 8 | END=8 9 | PREFIX=9 10 | SHARED=10 11 | SYSTEM=11 12 | FAOCOUNT=12 13 | IDENTIFICATION=13 14 | USERVALUE=14 15 | SUCCESS=15 16 | INFORMATIONAL=16 17 | WARNING=17 18 | ERROR=18 19 | SEVERE=19 20 | FATAL=20 21 | WHITESPACE=21 22 | NEWLINE=22 23 | NAME=23 24 | NUMBER=24 25 | ASSIGN=25 26 | ADD=26 27 | SUB=27 28 | MUL=28 29 | DIV=29 30 | SHIFT=30 31 | SHARP=31 32 | PERC=32 33 | POW=33 34 | UNDER=34 35 | P_OPEN=35 36 | P_CLOS=36 37 | HEXNUM=37 38 | OCTNUM=38 39 | DECNUM=39 40 | DOT=40 41 | COMMA=41 42 | EXCL=42 43 | ASTRING_OPEN=43 44 | QSTRING_OPEN=44 45 | BSTRING_OPEN=45 46 | ANY=46 47 | IDENTSEP=47 48 | IDENTNAME=48 49 | IDENTSTRING=49 50 | IDENTCOMMENT=50 51 | IDENT_CLOSE=51 52 | BSTRING_CLOSE=52 53 | BFAO=53 54 | BTEXT=54 55 | QSTRING_CLOSE=55 56 | QFAO=56 57 | QTEXT=57 58 | ASTRING_CLOSE=58 59 | AFAO=59 60 | ATEXT=60 61 | '='=25 62 | '+'=26 63 | '-'=27 64 | '*'=28 65 | '/'=29 66 | '@'=30 67 | '#'=31 68 | '%'=32 69 | '^'=33 70 | '_'=34 71 | '('=35 72 | ')'=36 73 | '.'=40 74 | ','=41 75 | '!'=42 76 | '<'=45 77 | '>'=52 78 | -------------------------------------------------------------------------------- /src/python/debugConfig.ts: -------------------------------------------------------------------------------- 1 | 2 | import { DebugProtocol } from "@vscode/debugprotocol"; 3 | import { DebugConfiguration, WorkspaceFolder } from "vscode"; 4 | 5 | /** 6 | * This interface describes the vms_jvm_debugger specific launch attributes 7 | * (which are not part of the Debug Adapter Protocol). 8 | * The schema for these attributes lives in the package.json of the mock-debug extension. 9 | * The interface should always match this schema. 10 | */ 11 | export interface IPythonLaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { 12 | /** a script to execute. */ 13 | script: string; 14 | /** a VMS command to execute before. */ 15 | pre_launch?: string; 16 | /** a port to debug. */ 17 | port?: string; 18 | /** command line arguments */ 19 | arguments?: string; 20 | /** python arguments */ 21 | python_args?: string; 22 | /** current workspace folder */ 23 | workspace: WorkspaceFolder; 24 | } 25 | 26 | export interface IPythonDebugConfiguration extends DebugConfiguration { 27 | /** a script to execute. */ 28 | script: string; 29 | /** a VMS command to execute before. */ 30 | pre_launch?: string; 31 | /** a port to debug. */ 32 | port?: string; 33 | /** command line arguments */ 34 | arguments?: string; 35 | /** python arguments */ 36 | python_args?: string; 37 | /** current workspace folder */ 38 | workspace: WorkspaceFolder; 39 | } 40 | 41 | export function isPythonDebugConfiguration(candidate: any): candidate is IPythonDebugConfiguration { 42 | return !!candidate && 43 | typeof candidate.type === "string" && 44 | typeof candidate.name === "string" && 45 | typeof candidate.request === "string" && 46 | (typeof candidate.python_args === undefined || typeof candidate.python_args === "string") && 47 | (typeof candidate.arguments === undefined || typeof candidate.arguments === "string") && 48 | (typeof candidate.pre_launch === undefined || typeof candidate.pre_launch === "string") && 49 | (typeof candidate.port === undefined || typeof candidate.port === "number") && 50 | typeof candidate.script === "string"; 51 | } -------------------------------------------------------------------------------- /src/python/extension.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) VMS Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { LogFunction, LogType } from "../common/main"; 6 | import * as vscode from "vscode"; 7 | import * as nls from "vscode-nls"; 8 | import { createLogFunction } from "../config-helper/log"; 9 | import { PythonConfigurationProvider, PythonDebugAdapterDescriptorFactory } from "./provider"; 10 | 11 | nls.config({messageFormat: nls.MessageFormat.both}); 12 | const localize = nls.loadMessageBundle(); 13 | 14 | let logFn: LogFunction; 15 | 16 | export function activate(context: vscode.ExtensionContext) 17 | { 18 | logFn = createLogFunction("VMS-IDE"); 19 | 20 | // register a configuration provider for 'vms jvm debugger' debug type 21 | const provider = new PythonConfigurationProvider(); 22 | context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider(PythonConfigurationProvider.debuggerType, provider)); 23 | 24 | const factory = new PythonDebugAdapterDescriptorFactory(logFn); 25 | context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory(PythonConfigurationProvider.debuggerType, factory)); 26 | context.subscriptions.push(factory); 27 | } 28 | 29 | export function deactivate() 30 | { 31 | // nothing to do 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/ssh-helper/config-api.ts: -------------------------------------------------------------------------------- 1 | import { IConfigApi } from "../config-helper/config/config"; 2 | import { GetConfigHelperFromApi } from "../ext-api/ext-api"; 3 | 4 | export let configApi: IConfigApi | undefined; 5 | 6 | export async function ensureConfigHelperApi(): Promise { 7 | if (!configApi) { 8 | configApi = GetConfigHelperFromApi(); 9 | } 10 | return configApi !== undefined; 11 | } 12 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/agent-filler.ts: -------------------------------------------------------------------------------- 1 | 2 | import { LogFunction, LogType } from "../../common/main"; 3 | import { IConnectConfig } from "../api"; 4 | import { ISettingsFiller } from "./settings-filler"; 5 | 6 | export class AgentFiller implements ISettingsFiller { 7 | 8 | public logFn: LogFunction; 9 | 10 | constructor(logFunc?: LogFunction) { 11 | // tslint:disable-next-line:no-empty 12 | this.logFn = logFunc || (() => {}); 13 | } 14 | 15 | /** 16 | * True it settings has unempty host and username 17 | * @param settings 18 | */ 19 | public testSettings(settings: IConnectConfig): boolean { 20 | const ret = typeof settings.host === "string" && !!settings.host && 21 | typeof settings.username === "string" && !!settings.username && 22 | ((typeof settings.addConnectConfig?.agent === "string" && !!settings.addConnectConfig?.agent)); 23 | return ret; 24 | } 25 | 26 | public async fillSetting(settings: IConnectConfig): Promise { 27 | 28 | if (typeof settings.addConnectConfig?.agent === "string" && !!settings.addConnectConfig?.agent) { 29 | // ok, already has 30 | return true; 31 | } 32 | return false; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/context-password-filler.ts: -------------------------------------------------------------------------------- 1 | import { Lock } from "../../common/main"; 2 | 3 | import { IConnectConfig } from "../api"; 4 | import { ISettingsFiller } from "./settings-filler"; 5 | 6 | export interface IContextPassword { 7 | host?: string; 8 | password?: string; 9 | } 10 | 11 | export class ContextPasswordFiller implements ISettingsFiller { 12 | 13 | private lock = new Lock(); 14 | 15 | constructor(public contexts: IContextPassword[] = [], public emulateUserDelay = 0) { 16 | } 17 | 18 | public testSettings(settings: IConnectConfig): boolean { 19 | const ret = typeof settings.host === "string" && 20 | !!settings.host && 21 | typeof settings.username === "string" && 22 | !!settings.username; 23 | return ret; 24 | } 25 | 26 | public async fillSetting(settings: IConnectConfig): Promise { 27 | 28 | if (typeof settings.password === "string" && 29 | settings.password) { 30 | // ok, already has 31 | return true; 32 | } 33 | 34 | for (const context of this.contexts) { 35 | if (context.host === settings.host) { 36 | if (this.emulateUserDelay !== 0) { 37 | await this.lock.acquire(); // to prevent concurrent use of console 38 | const waitUser = new Lock(true); // simulate user 39 | setTimeout(() => { 40 | settings.password = context.password; 41 | waitUser.release(); 42 | }, this.emulateUserDelay); 43 | await waitUser.acquire(); // do not pass until password entered 44 | this.lock.release(); 45 | } else { 46 | settings.password = context.password; 47 | } 48 | } 49 | } 50 | 51 | return !!settings.password; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/host-filler.ts: -------------------------------------------------------------------------------- 1 | 2 | import { LogFunction } from "../../common/main"; 3 | import { IConnectConfig, IHostsSection } from "../api"; 4 | import { ISettingsFiller } from "./settings-filler"; 5 | 6 | export class HostFiller implements ISettingsFiller { 7 | 8 | public static rg = /^<(.*)>$/; 9 | 10 | public logFn: LogFunction; 11 | 12 | constructor(public hostSection: IHostsSection, logFunc?: LogFunction) { 13 | // tslint:disable-next-line:no-empty 14 | this.logFn = logFunc || (() => {}); 15 | } 16 | 17 | /** 18 | * If settings has then resolve it from hosts and pass to the next fillers 19 | * @param settings 20 | */ 21 | public testSettings(settings: IConnectConfig): boolean { 22 | if (typeof settings.host === "string" && !!settings.host) { 23 | const matched = settings.host.match(HostFiller.rg); 24 | if (matched) { 25 | for (const host of this.hostSection.hosts) { 26 | if (host.label === matched[1]) { 27 | settings.host = host.host; 28 | settings.port = host.port; 29 | settings.username = host.username; 30 | settings.keyFile = host.keyFile; 31 | settings.password = host.password; 32 | settings.debug = host.debug; 33 | settings.skipSignatureVerification = host.skipSignatureVerification?true:false; 34 | settings.algorithms = Object.assign({}, host.algorithms); 35 | settings.supportSetFileTime = host.supportSetFileTime; 36 | settings.unzipCmd = host.unzipCmd; 37 | settings.zipCmd = host.zipCmd; 38 | settings.addConnectConfig = host.addConnectConfig; 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | public async fillSetting(settings: IConnectConfig): Promise { 48 | return false; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/key-filler.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs-extra"; 2 | 3 | import { LogFunction, LogType } from "../../common/main"; 4 | import { IConnectConfig } from "../api"; 5 | import { ISettingsFiller } from "./settings-filler"; 6 | 7 | export class KeyFiller implements ISettingsFiller { 8 | 9 | public logFn: LogFunction; 10 | 11 | constructor(logFunc?: LogFunction) { 12 | // tslint:disable-next-line:no-empty 13 | this.logFn = logFunc || (() => {}); 14 | } 15 | 16 | /** 17 | * True it settings has unempty host and username 18 | * @param settings 19 | */ 20 | public testSettings(settings: IConnectConfig): boolean { 21 | const ret = typeof settings.host === "string" && !!settings.host && 22 | typeof settings.username === "string" && !!settings.username && 23 | ( (typeof settings.privateKey === "string" && !!settings.privateKey) || 24 | Buffer.isBuffer(settings.privateKey) || 25 | (typeof settings.keyFile === "string" && !!settings.keyFile) 26 | ); 27 | return ret; 28 | } 29 | 30 | public async fillSetting(settings: IConnectConfig): Promise { 31 | 32 | if (typeof settings.privateKey === "string" || 33 | Buffer.isBuffer(settings.privateKey)) { 34 | // ok, already has 35 | return true; 36 | } 37 | if (!settings.keyFile) { 38 | return false; 39 | } 40 | try { 41 | settings.privateKey = await fs.readFile(settings.keyFile); 42 | // if (settings.keyFile !== undefined) { 43 | // delete settings.keyFile; 44 | // } 45 | if (settings.password !== undefined) { 46 | delete settings.password; 47 | } 48 | return true; 49 | } catch (err) { 50 | this.logFn(LogType.error, () => String(err)); 51 | return false; 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/password-console-filler.ts: -------------------------------------------------------------------------------- 1 | import * as readline from "readline"; 2 | 3 | import { Lock } from "../../common/main"; 4 | 5 | import { IConnectConfig } from "../api"; 6 | import { ISettingsFiller } from "./settings-filler"; 7 | 8 | import * as nls from "vscode-nls"; 9 | nls.config({messageFormat: nls.MessageFormat.both}); 10 | const localize = nls.loadMessageBundle(); 11 | 12 | const lock = new Lock(); 13 | 14 | export class PasswordConsoleFiller implements ISettingsFiller { 15 | 16 | /** 17 | * True it settings has unempty host and username 18 | * @param settings 19 | */ 20 | public testSettings(settings: IConnectConfig): boolean { 21 | const ret = typeof settings.host === "string" && 22 | !!settings.host && 23 | typeof settings.username === "string" && 24 | !!settings.username; 25 | return ret; 26 | } 27 | 28 | public async fillSetting(settings: IConnectConfig): Promise { 29 | 30 | if (typeof settings.password === "string" && 31 | settings.password) { 32 | // ok, already has 33 | return true; 34 | } 35 | 36 | await lock.acquire(); // to prevent concurrent use of console 37 | 38 | let retCode = false; 39 | const waitUser = new Lock(true); // to wait user input 40 | 41 | settings.port = settings.port || 22; 42 | const readLineInterface = readline.createInterface(process.stdin, process.stdout); 43 | const prompt = localize("query.password", "Password for {0}@{1}:{2} ", settings.username, settings.host, settings.port); 44 | // TODO: how to use * instead of symbols? 45 | readLineInterface.question(prompt, (answer) => { 46 | readLineInterface.close(); 47 | if (answer) { 48 | settings.password = answer; 49 | retCode = true; 50 | } 51 | waitUser.release(); // ok, may proceed 52 | }); 53 | 54 | await waitUser.acquire(); // do not pass until password entered 55 | 56 | lock.release(); 57 | return retCode; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/password-filler.ts: -------------------------------------------------------------------------------- 1 | import { Lock } from "../../common/main"; 2 | 3 | import { IConnectConfig } from "../api"; 4 | import { ISettingsFiller } from "./settings-filler"; 5 | 6 | export class ConstPasswordFiller implements ISettingsFiller { 7 | 8 | private lock = new Lock(); 9 | 10 | constructor(public password: string, public timeout?: number) { 11 | 12 | } 13 | 14 | /** 15 | * True it settings has unempty host and username 16 | * @param settings 17 | */ 18 | public testSettings(settings: IConnectConfig): boolean { 19 | const ret = typeof settings.host === "string" && 20 | !!settings.host && 21 | typeof settings.username === "string" && 22 | !!settings.username; 23 | return ret; 24 | } 25 | 26 | public async fillSetting(settings: IConnectConfig): Promise { 27 | 28 | if (typeof settings.password === "string" && 29 | settings.password) { 30 | // ok, already has 31 | return true; 32 | } 33 | 34 | await this.lock.acquire(); // to prevent concurrent use of console 35 | 36 | if (this.timeout) { 37 | const waitUser = new Lock(true); // simulate user 38 | setTimeout(() => { 39 | settings.password = this.password; 40 | if (settings.keyFile !== undefined) { 41 | delete settings.keyFile; 42 | } 43 | waitUser.release(); 44 | }, this.timeout); 45 | await waitUser.acquire(); // do not pass until password entered 46 | } else { 47 | settings.password = this.password; 48 | } 49 | 50 | this.lock.release(); 51 | 52 | return !!settings.password; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/password-vscode-filler.ts: -------------------------------------------------------------------------------- 1 | 2 | import { window } from "vscode"; 3 | 4 | import { Lock } from "../../common/main"; 5 | 6 | import { IConnectConfig } from "../api"; 7 | import { ISettingsFiller } from "./settings-filler"; 8 | 9 | import * as nls from "vscode-nls"; 10 | nls.config({messageFormat: nls.MessageFormat.both}); 11 | const localize = nls.loadMessageBundle(); 12 | 13 | const lock = new Lock(); 14 | 15 | export class PasswordVscodeFiller implements ISettingsFiller { 16 | 17 | /** 18 | * True it settings has unempty host and username 19 | * @param settings 20 | */ 21 | public testSettings(settings: IConnectConfig): boolean { 22 | const ret = typeof settings.host === "string" && 23 | !!settings.host && 24 | typeof settings.username === "string" && 25 | !!settings.username; 26 | return ret; 27 | } 28 | 29 | public async fillSetting(settings: IConnectConfig): Promise { 30 | if (typeof settings.password === "string" && 31 | settings.password) { 32 | // ok, already has 33 | return true; 34 | } 35 | await lock.acquire(); // to prevent concurrent using 36 | settings.port = settings.port || 22; 37 | const prompt = localize("query.password", "Password for {0}@{1}:{2} ", settings.username, settings.host, settings.port); 38 | settings.password = await window.showInputBox( { password: true, prompt, ignoreFocusOut: true }); 39 | if (settings.keyFile !== undefined) { 40 | delete settings.keyFile; 41 | } 42 | lock.release(); 43 | return settings.password !== undefined; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/ssh-helper/config-resolve/settings-filler.ts: -------------------------------------------------------------------------------- 1 | 2 | import { IConnectConfig } from "../api"; 3 | 4 | export interface ISettingsFiller { 5 | /** 6 | * Test if that kind of settings can be filled by this implementation, may change settings object 7 | * @param settings settings to test 8 | * @returns true if can be filled (or already filled) 9 | */ 10 | testSettings(settings: IConnectConfig): boolean; 11 | 12 | /** 13 | * Fill settings, should change settings object 14 | * @param settings settings to fill out 15 | * @returns true if settings filled and can be used 16 | */ 17 | fillSetting(settings: IConnectConfig): Promise; 18 | } 19 | -------------------------------------------------------------------------------- /src/ssh-helper/config/sections/hosts.ts: -------------------------------------------------------------------------------- 1 | import { IConfigData, IConfigSection, ValueData } from "../../../config-helper/config/config"; 2 | import { IHostsSection } from "../../api"; 3 | import { LabeledConnection } from "./labeled-connection"; 4 | 5 | export class HostsSection implements IConfigSection { 6 | 7 | public static readonly section = "host-collection"; 8 | 9 | public static is(candidate: any): candidate is IHostsSection { 10 | return !!candidate && 11 | candidate.hosts instanceof Array; 12 | } 13 | public hosts: LabeledConnection[] = []; 14 | 15 | public name(): string { 16 | return HostsSection.section; 17 | } 18 | 19 | public store(): IConfigData { 20 | const ret: IConfigData = {}; 21 | ret.hosts = [] as IConfigData[]; 22 | for (const tmp of this.hosts) { 23 | ret.hosts.push(tmp.store()); 24 | } 25 | return ret; 26 | } 27 | 28 | public templateToFillFrom(): IConfigData { 29 | const ret: IConfigData = { 30 | hosts: [ new LabeledConnection().templateToFillFrom() ], 31 | }; 32 | return ret; 33 | } 34 | 35 | public fillFrom(data: IConfigData): boolean { 36 | let retcode = true; 37 | this.hosts = []; 38 | if (data.hosts instanceof Array) { 39 | for (const host of data.hosts) { 40 | const tmp = new LabeledConnection(); 41 | if (tmp.fillFrom(host as IConfigData)) { 42 | this.hosts.push(tmp); 43 | } else { 44 | retcode = false; 45 | } 46 | } 47 | } 48 | return retcode; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/ssh-helper/config/sections/labeled-connection.ts: -------------------------------------------------------------------------------- 1 | import { ConnectionSection } from "./connection"; 2 | 3 | import { IConfigData } from "../../../config-helper/config/config"; 4 | 5 | export class LabeledConnection extends ConnectionSection { 6 | 7 | public static is(candidate: any): candidate is LabeledConnection { 8 | return typeof candidate.label === "string" && ConnectionSection.is(candidate); 9 | } 10 | 11 | public label: string = ""; 12 | 13 | public name(): string { 14 | return this.label; 15 | } 16 | 17 | public store(): IConfigData { 18 | const ret = super.store(); 19 | ret.label = this.label; 20 | return ret; 21 | } 22 | 23 | public templateToFillFrom(): IConfigData { 24 | const ret = super.templateToFillFrom(); 25 | ret.label = ""; 26 | return ret; 27 | } 28 | 29 | public fillFrom(data: IConfigData): boolean { 30 | if (typeof data.label === "string") { 31 | this.label = data.label; 32 | } 33 | return super.fillFrom(data); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ssh-helper/config/sections/terminal.ts: -------------------------------------------------------------------------------- 1 | import { IConfigData, IConfigSection } from "../../../config-helper/config/config"; 2 | import { ITerminalSection } from "../../api"; 3 | 4 | export class TerminalSection implements ITerminalSection, IConfigSection { 5 | 6 | public static readonly section = "terminal"; 7 | 8 | public static is(candidate: any): candidate is ITerminalSection { 9 | return !!candidate && 10 | typeof candidate.command === "string"; 11 | } 12 | 13 | public command = ""; 14 | 15 | public name(): string { 16 | return TerminalSection.section; 17 | } 18 | 19 | public store(): IConfigData { 20 | return this.templateToFillFrom(); 21 | } 22 | 23 | public templateToFillFrom(): IConfigData { 24 | return { 25 | command: this.command, 26 | }; 27 | } 28 | 29 | public fillFrom(data: IConfigData): boolean { 30 | if (TerminalSection.is(data)) { 31 | this.command = data.command; 32 | return true; 33 | } 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ssh-helper/config/sections/timeouts.ts: -------------------------------------------------------------------------------- 1 | import { IConfigData, IConfigSection } from "../../../config-helper/config/config"; 2 | import { ITimeoutsSection } from "../../api"; 3 | 4 | export class TimeoutSection implements ITimeoutsSection, IConfigSection { 5 | 6 | public static readonly section = "timeouts"; 7 | 8 | public static is(candidate: any): candidate is ITimeoutsSection { 9 | return !!candidate && 10 | typeof candidate.cmdTimeout === "number" && 11 | typeof candidate.feedbackTimeout === "number" && 12 | typeof candidate.welcomeTimeout === "number"; 13 | } 14 | 15 | public cmdTimeout: number = 0; // in msec 16 | public feedbackTimeout: number = 0; // in msec 17 | public welcomeTimeout: number = 0; // in msec 18 | 19 | public name(): string { 20 | return TimeoutSection.section; 21 | } 22 | 23 | public store(): IConfigData { 24 | return this.templateToFillFrom(); 25 | } 26 | 27 | public templateToFillFrom(): IConfigData { 28 | return { 29 | cmdTimeout: this.cmdTimeout, 30 | feedbackTimeout: this.feedbackTimeout, 31 | welcomeTimeout: this.welcomeTimeout, 32 | }; 33 | } 34 | 35 | public fillFrom(data: IConfigData): boolean { 36 | if (TimeoutSection.is(data)) { 37 | this.cmdTimeout = data.cmdTimeout; 38 | this.feedbackTimeout = data.feedbackTimeout; 39 | this.welcomeTimeout = data.welcomeTimeout; 40 | return true; 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ssh-helper/extension.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as vscode from "vscode"; 3 | 4 | import { configApi, ensureConfigHelperApi } from "./config-api"; 5 | import { SshHelper } from "./ssh-helper"; 6 | 7 | const locale = vscode.env.language ; 8 | import * as nls from "vscode-nls"; 9 | const localize = nls.config({ locale, messageFormat: nls.MessageFormat.both })(); 10 | 11 | export async function activate(context: vscode.ExtensionContext) { 12 | 13 | if (!await ensureConfigHelperApi() || !configApi) { 14 | return undefined; 15 | } 16 | 17 | const sshHelper = new SshHelper(configApi.createLogFunction("VMS-IDE")); 18 | 19 | setupWatchers(sshHelper); 20 | 21 | vscode.workspace.onDidChangeWorkspaceFolders(() => { 22 | setupWatchers(sshHelper); 23 | }); 24 | 25 | context.subscriptions.push(sshHelper); 26 | 27 | return SshHelper; // class, not object 28 | } 29 | 30 | let watchers: vscode.Disposable[] = []; 31 | 32 | function setupWatchers(sshHelper: SshHelper) { 33 | watchers.forEach((watcher) => watcher.dispose()); 34 | watchers = []; 35 | if (vscode.workspace.workspaceFolders) { 36 | for (const wf of vscode.workspace.workspaceFolders) { 37 | watchers.push(sshHelper.setConfigWatcher(wf.name, () => { 38 | sshHelper.killPasswordCache(); 39 | sshHelper.testSettings(wf.name); 40 | })); 41 | } 42 | } 43 | } 44 | 45 | export function deactivate() { 46 | // do nothing 47 | } 48 | -------------------------------------------------------------------------------- /src/ssh-helper/stream/parse-welcome.ts: -------------------------------------------------------------------------------- 1 | import { LogFunction, LogType } from "../../common/main"; 2 | import { IParseWelcome } from "../api"; 3 | import { ShellParser } from "./shell-parser"; 4 | import { SshShell } from "./ssh-shell"; 5 | 6 | import * as nls from "vscode-nls"; 7 | nls.config({messageFormat: nls.MessageFormat.both}); 8 | const localize = nls.loadMessageBundle(); 9 | 10 | export class ParseWelcome extends ShellParser implements IParseWelcome { 11 | 12 | public prompt?: string; 13 | 14 | /** 15 | * Parses stream until the last line isn't the same as previous line. Writes EOL on each data received. 16 | * Caveat: may be the reason of garbage in output already after prompt is caught, so wait your command 17 | * before utilizing output. 18 | * @param timeout timeout prompt catching 19 | * @param logFn like console.log 20 | */ 21 | constructor(timeout?: number, logFn?: LogFunction, tag?: string) { 22 | super(timeout, logFn, tag); 23 | } 24 | 25 | /** 26 | * Just write some if esc-code found, else welcome! 27 | */ 28 | public _transform(chunk: any, encoding: string, callback: () => any) { 29 | super._transform(chunk, encoding, callback); 30 | if (Buffer.isBuffer(chunk)) { 31 | if (chunk.includes(27)) { 32 | this.push(SshShell.eol); 33 | } else { 34 | if (this.lines.length > 1) { 35 | if (this.lines[this.lines.length - 1].trim() === this.lastLine.trim()) { 36 | this.prompt = this.lastLine.trim(); 37 | this.logFn(LogType.debug, () => localize("debug.prompt", "parse: found prompt '{0}'", this.prompt)); 38 | this.setReady(); 39 | } 40 | } 41 | if (this.prompt === undefined) { 42 | this.push(SshShell.eol); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ssh-helper/stream/prompt-catcher-vms.ts: -------------------------------------------------------------------------------- 1 | import { LogFunction, LogType } from "../../common/main"; 2 | 3 | import { IPromptCatcher } from "../api"; 4 | import { ShellParser } from "./shell-parser"; 5 | 6 | export class PromptCatcherVms extends ShellParser implements IPromptCatcher { 7 | 8 | /** 9 | * Note: only the last prompt will be caught properly. 10 | * If do write several commands without catching each prompt some of these prompts may not be caught. 11 | */ 12 | constructor(public prompt: string, timeout?: number, logFn?: LogFunction, tag?: string) { 13 | super(timeout, logFn, tag); 14 | } 15 | 16 | public _transform(chunk: any, encoding: string, callback: () => any) { 17 | super._transform(chunk, encoding, callback); 18 | if (Buffer.isBuffer(chunk)) { 19 | if (chunk.includes(0)) { 20 | const promptIdx = this.lastLine.lastIndexOf(String.fromCharCode(0)); 21 | if (promptIdx >= 0) { 22 | this.lastLine = this.lastLine.slice(0, promptIdx); 23 | } 24 | this.setReady(); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ssh-helper/stream/prompt-catcher.ts: -------------------------------------------------------------------------------- 1 | import { LogFunction, LogType } from "../../common/main"; 2 | 3 | import { IPromptCatcher } from "../api"; 4 | import { ShellParser } from "./shell-parser"; 5 | 6 | export class PromptCatcher extends ShellParser implements IPromptCatcher { 7 | 8 | /** 9 | * Note: only the last prompt will be caught properly. 10 | * If do write several commands without catching each prompt some of these prompts may not be caught. 11 | */ 12 | constructor(public prompt: string, timeout?: number, logFn?: LogFunction, tag?: string) { 13 | super(timeout, logFn, tag); 14 | } 15 | 16 | public _transform(chunk: any, encoding: string, callback: () => any) { 17 | super._transform(chunk, encoding, callback); 18 | if (this.lastLine.endsWith(this.prompt)) { 19 | // remove prompt 20 | this.lastLine = this.lastLine.slice(0, this.lastLine.length - this.prompt.length); 21 | // emit event and clear lastString 22 | this.setReady(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ssh-helper/stream/stream-creators.ts: -------------------------------------------------------------------------------- 1 | import { Readable, Writable } from "stream"; 2 | 3 | import { ICanCreateReadStream, ICanCreateWriteStream, IMemoryStreamCreator } from "./../api"; 4 | 5 | import { LogFunction, LogType, MemoryReadStream, MemoryWriteStream } from "../../common/main"; 6 | 7 | export class MemoryStreamCreator implements IMemoryStreamCreator, ICanCreateReadStream, ICanCreateWriteStream { 8 | 9 | public readStream?: MemoryReadStream; 10 | public writeStream?: MemoryWriteStream; 11 | 12 | constructor(public chunks?: Array, public emulateError?: boolean, public logFn?: LogFunction) { 13 | } 14 | 15 | public async createReadStream(file: string): Promise { 16 | return this.readStream = new MemoryReadStream(this.chunks, this.logFn); 17 | } 18 | 19 | public async createWriteStream(file: string): Promise { 20 | return this.writeStream = new MemoryWriteStream(this.logFn, this.emulateError); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/ssh-helper/test/config/config.ts: -------------------------------------------------------------------------------- 1 | export async function TestConfiguration(local: boolean) { 2 | if (local) { 3 | return { 4 | host: "localhost", 5 | port: 22, 6 | username: "user", 7 | password: "pass", 8 | }; 9 | } else { 10 | return { 11 | host: "104.207.199.181", 12 | port: 22, 13 | username: "vorfolomeev", 14 | keyFile: "H:/.ssh/sv01", 15 | }; 16 | } 17 | } -------------------------------------------------------------------------------- /src/synchronizer/command-context.ts: -------------------------------------------------------------------------------- 1 | import { commands } from "vscode"; 2 | 3 | export enum CommandContext { 4 | isInAction = "vmssoftware.synchronizer.isInAction", 5 | // isSyncronizing = "vmssoftware.synchronizer.isSync", 6 | // isBuilding = "vmssoftware.synchronizer.isBuild", 7 | // isSaving = "vmssoftware.synchronizer.isSaving", 8 | // isCrLf = "vmssoftware.synchronizer.isCrLf", 9 | // isEdit = "vmssoftware.synchronizer.isEdit", 10 | // isHeaders = "vmssoftware.synchronizer.isHeaders", 11 | } 12 | 13 | const contextMap = new Map(); 14 | 15 | export function setContext(context: CommandContext, state: boolean) { 16 | contextMap.set(context, state); 17 | commands.executeCommand("setContext", context, state); 18 | } 19 | 20 | export function getContext(context: CommandContext): boolean { 21 | return !!contextMap.get(context); 22 | } 23 | -------------------------------------------------------------------------------- /src/synchronizer/common/TestExecResult.ts: -------------------------------------------------------------------------------- 1 | 2 | const rgx = /(?:%|-)(?:\w+)-(?:W|E|F)-(?:\w+), (.*)/; 3 | /** 4 | * 5 | * @param result 6 | * @returns error string or indefined 7 | */ 8 | export function ParseExecResult(result: string[] | undefined): string[] { 9 | if (!result) { 10 | return ["No result"]; 11 | } 12 | let errors: string[] = []; 13 | for (let line of result) { 14 | let match = line.match(rgx); 15 | if (match && match[1]) { 16 | errors.push(match[1]); 17 | } 18 | } 19 | return errors; 20 | } -------------------------------------------------------------------------------- /src/synchronizer/common/create-file.ts: -------------------------------------------------------------------------------- 1 | import vscode from "vscode"; 2 | 3 | export async function createFile(fileUri: vscode.Uri, content: string) { 4 | try { 5 | let range: vscode.Range | undefined; 6 | try { 7 | const textDoc = await vscode.workspace.openTextDocument(fileUri); 8 | range = textDoc.validateRange(new vscode.Range(0, 0, 32767, 32767)); 9 | } catch (err) { 10 | range = undefined; 11 | } 12 | const we = new vscode.WorkspaceEdit(); 13 | if (!range) { 14 | we.createFile(fileUri); 15 | we.insert(fileUri, new vscode.Position(0, 0), content); 16 | } else { 17 | we.replace(fileUri, range, content); 18 | } 19 | const status = await vscode.workspace.applyEdit(we); 20 | if (status) { 21 | const textDoc = await vscode.workspace.openTextDocument(fileUri); 22 | const saved = await textDoc.save(); 23 | return saved; 24 | } else { 25 | return false; 26 | } 27 | } catch (err) { 28 | return false; 29 | } 30 | } 31 | 32 | export async function loadFile(fileUri: vscode.Uri) { 33 | try { 34 | const textDoc = await vscode.workspace.openTextDocument(fileUri); 35 | return textDoc.getText(); 36 | } catch (err) { 37 | return ""; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/synchronizer/common/progress.ts: -------------------------------------------------------------------------------- 1 | import { Disposable, window } from "vscode"; 2 | import { IProgress } from "../sync/source"; 3 | 4 | export interface IValueOfMax { 5 | value: number; 6 | maxValue?: number; 7 | } 8 | 9 | export class Progress implements IProgress, Disposable { 10 | 11 | private map: Map = new Map(); 12 | 13 | private prevMessage: Disposable | undefined; 14 | 15 | public getToken(token: string) { 16 | return this.map.get(token); 17 | } 18 | 19 | public dispose() { 20 | if (this.prevMessage) { 21 | this.prevMessage.dispose(); 22 | } 23 | this.prevMessage = undefined; 24 | } 25 | 26 | public addProgress(token: string, addValue: number): boolean { 27 | let prev = this.map.get(token); 28 | if (!prev) { 29 | prev = { value: 0, maxValue: 0}; 30 | } 31 | prev.value += addValue; 32 | this.map.set(token, prev); 33 | this.update(); 34 | return false; // no canceling at all 35 | } 36 | 37 | public setProgress(token: string, value: number, maxValue?: number): boolean { 38 | maxValue = maxValue || 0; 39 | this.map.set(token, {value, maxValue}); 40 | this.update(); 41 | return false; // no canceling at all 42 | } 43 | 44 | private update() { 45 | // setImmediate(() => { 46 | const strArr: string[] = []; 47 | for ( const [key, valueOf] of this.map) { 48 | if (strArr.length > 0) { 49 | strArr.push(", "); 50 | } 51 | strArr.push(key); 52 | strArr.push(": "); 53 | strArr.push(String(valueOf.value)); 54 | if (valueOf.maxValue) { 55 | strArr.push(" of "); 56 | strArr.push(String(valueOf.maxValue)); 57 | } 58 | } 59 | if (this.prevMessage) { 60 | this.prevMessage.dispose(); 61 | } 62 | this.prevMessage = window.setStatusBarMessage(strArr.join("")); 63 | // }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/synchronizer/context.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext } from "vscode"; 2 | 3 | export let contextSaved: ExtensionContext | undefined; 4 | 5 | export function setExtensionContext(context: ExtensionContext) { 6 | contextSaved = context; 7 | } 8 | -------------------------------------------------------------------------------- /src/synchronizer/on-the-same-vms.ts: -------------------------------------------------------------------------------- 1 | import { LogFunction } from "../common/main"; 2 | 3 | import { GetSshHelperType } from "../ext-api/ext-api"; 4 | import { IConnectConfig } from "../ssh-helper/api"; 5 | import { ProjDepTree } from "./dep-tree/proj-dep-tree"; 6 | 7 | export async function onTheSameVms(scope: string, logFn: LogFunction) { 8 | if (!scope) { 9 | return true; 10 | } 11 | const sshHelperType = await GetSshHelperType(); 12 | if (!sshHelperType) { 13 | return true; 14 | } 15 | const sshHelper = new sshHelperType(logFn); 16 | const deps = new ProjDepTree().getDepList(scope); 17 | let testConnectionSettings: IConnectConfig | undefined; 18 | for (const dep of deps) { 19 | const cfg = await sshHelper.getSettings(dep); 20 | if (cfg) { 21 | const res = cfg.connectConfigResolver.testConnectConfig(cfg.connectionSection); 22 | if (res.settings) { 23 | if (!testConnectionSettings) { 24 | testConnectionSettings = res.settings; 25 | } else if (testConnectionSettings.host !== res.settings.host || 26 | testConnectionSettings.username !== res.settings.username) { 27 | return false; 28 | } 29 | } 30 | } 31 | } 32 | return true; 33 | } 34 | -------------------------------------------------------------------------------- /src/synchronizer/projectDepend.ts: -------------------------------------------------------------------------------- 1 | import { Event } from "vscode"; 2 | 3 | let _projectDependenciesChanged: Event | undefined; 4 | 5 | export function projectDependenciesChanged(): Event | undefined { 6 | return _projectDependenciesChanged; 7 | } 8 | 9 | export function setProjectDependenciesChanged(value: Event | undefined) { 10 | _projectDependenciesChanged = value; 11 | } -------------------------------------------------------------------------------- /src/synchronizer/sync/source.ts: -------------------------------------------------------------------------------- 1 | import { IFileEntry } from "../../common/main"; 2 | 3 | import { Readable, Writable } from "stream"; 4 | 5 | export interface IProgress { 6 | /** 7 | * Show progress 8 | * @param token name 9 | * @param addvalue amount of progress 10 | * @returns true on cancel 11 | */ 12 | addProgress(token: string, addvalue: number): boolean; 13 | 14 | /** 15 | * Set progress 16 | * @param token name 17 | * @param value current value 18 | * @param maxvalue max value 19 | */ 20 | setProgress(token: string, value: number, maxvalue?: number): boolean; 21 | } 22 | 23 | export type sourceType = "local" | "remote"; 24 | 25 | export interface ISource { 26 | root?: string; 27 | attempts?: number; 28 | enabled: boolean; 29 | createReadStream(filename: string): Promise; 30 | createWriteStream(filename: string): Promise; 31 | dispose(): void; 32 | ensureDirectory(directory: string): Promise; 33 | findFiles(include: string, exclude?: string, progress?: IProgress): Promise; 34 | getDate(filename: string): Promise; 35 | setDate(filename: string, date: Date): Promise; 36 | accessFile(filename: string): Promise; 37 | deleteFile(filename: string): Promise; 38 | } 39 | -------------------------------------------------------------------------------- /src/synchronizer/test/config/vms.ts: -------------------------------------------------------------------------------- 1 | export const Vms = { 2 | host: "10.11.108.21", 3 | keyFile: "h:/.ssh/sv01", 4 | port: 22, 5 | username: "vorfolomeev", 6 | }; 7 | -------------------------------------------------------------------------------- /src/synchronizer/test/problem.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | 3 | import { logConsoleFn, LogFunction, LogType } from "../../common/main"; 4 | 5 | import { inspect } from "util"; 6 | import { parseVmsOutput } from "../common/parse-output"; 7 | import { VmsPathConverter } from "../vms/vms-path-converter"; 8 | 9 | suite("Source tests", function(this: Mocha.Suite) { 10 | 11 | return; 12 | 13 | this.timeout(0); 14 | 15 | let debugLogFn: LogFunction | undefined; 16 | debugLogFn = logConsoleFn; 17 | 18 | const output = 19 | ` 20 | for (int i = 0; i < 10; ++j) { 21 | ..............................^ 22 | %CXX-E-UNDECLARED, identifier "j" is undefined 23 | at line number 9 in file WORK:[VORFOLOMEEV.WORK]main.cpp;6 24 | 25 | %CXX-I-MESSAGE, 1 error detected in the compilation of "WORK:[VORFOLOMEEV.WORK]main.cpp;6". 26 | %MMS-F-ABORT, For target [.OUT.DEBUG.OBJ]MAIN.OBJ, CLI returned abort status: %X15F61262. 27 | 28 | `; 29 | test("Test p1", async () => { 30 | const c1 = VmsPathConverter.fromVms("[.a.b]c.d"); 31 | const c2 = VmsPathConverter.fromVms("[a.b]c.d"); 32 | const result = parseVmsOutput(output.split(/[\r?|\r\n]/)); 33 | if (debugLogFn) { 34 | debugLogFn(LogType.debug, () => inspect(result)); 35 | } 36 | assert.ok(true, "ok"); 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /src/synchronizer/test/sftp-readdir.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | 3 | import { SshHelper } from "../../ssh-helper/ssh-helper"; 4 | 5 | import { logConsoleFn, LogFunction, LogType } from "../../common/main"; 6 | import { GetSshHelperType } from "../../ext-api/ext-api"; 7 | 8 | suite("Directory tests", function(this: Mocha.Suite) { 9 | 10 | return; 11 | 12 | this.timeout(0); 13 | 14 | let debugLogFn: LogFunction | undefined; 15 | debugLogFn = logConsoleFn; 16 | 17 | let sshHelper: SshHelper; 18 | 19 | this.beforeAll(async () => { 20 | const sshHelperType = await GetSshHelperType(); 21 | assert.notEqual(sshHelperType, undefined, `Cannot get ssh-helper api`); 22 | sshHelper = new sshHelperType!(debugLogFn); 23 | }); 24 | 25 | test(`Read local "" dirname`, async () => { 26 | const sftp = await sshHelper.getTestSftp({host: "localhost", port: 22, username: "user", password: "pass"}); 27 | assert.notEqual(sftp, undefined, "sftp must be defined"); 28 | const files = await sftp!.readDirectory(""); 29 | sftp!.dispose(); 30 | assert.notEqual(files, undefined, "files must be defined"); 31 | if (files) { 32 | assert.notEqual(files.length, 0, "files must not be empty"); 33 | } 34 | }); 35 | 36 | test(`Read local "WRK" dirname`, async () => { 37 | const sftp = await sshHelper.getTestSftp({host: "localhost", port: 22, username: "user", password: "pass"}); 38 | assert.notEqual(sftp, undefined, "sftp must be defined"); 39 | const files = await sftp!.readDirectory("WRK"); 40 | sftp!.dispose(); 41 | assert.notEqual(files, undefined, "files must be defined"); 42 | if (files) { 43 | assert.notEqual(files.length, 0, "files must not be empty"); 44 | } 45 | }); 46 | 47 | test(`Read local "unexist" dirname`, async () => { 48 | const sftp = await sshHelper.getTestSftp({host: "localhost", port: 22, username: "user", password: "pass"}); 49 | assert.notEqual(sftp, undefined, "sftp must be defined"); 50 | const files = await sftp!.readDirectory("unexist"); 51 | sftp!.dispose(); 52 | assert.equal(files, undefined, "files must be defined"); 53 | }); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /src/synchronizer/vms/vms-absolute-date-string.ts: -------------------------------------------------------------------------------- 1 | 2 | export function VmsAbsoluteDateString(date: Date, locale: string = "en-US"): string { 3 | const day = date.getDate().toString(10).padStart(2, "0"); 4 | const year = date.getFullYear().toString(10); 5 | const hour = date.getHours().toString(10).padStart(2, "0"); 6 | const minute = date.getMinutes().toString(10).padStart(2, "0"); 7 | const sec = date.getSeconds().toString(10).padStart(2, "0"); 8 | 9 | const f = new Intl.DateTimeFormat(locale, {month: "short"}); 10 | const month = f.format(date); 11 | 12 | const dateString = `${day}-${month}-${year} ${hour}:${minute}:${sec}`; 13 | return dateString; 14 | } 15 | -------------------------------------------------------------------------------- /src/task2cmd/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { tasks } from 'vscode'; 3 | import { Task2CmdProvider } from './task2cmd-prov'; 4 | import { GetConfigHelperFromApi } from '../ext-api/ext-api'; 5 | 6 | export async function activate(context: vscode.ExtensionContext) { 7 | 8 | const configApi = await GetConfigHelperFromApi(); 9 | if (!configApi) { 10 | return; 11 | } 12 | const logFn = configApi.createLogFunction("VMS-IDE"); 13 | 14 | const taskProvider = new Task2CmdProvider(logFn); 15 | let disposable = tasks.registerTaskProvider(Task2CmdProvider.taskType, taskProvider); 16 | 17 | context.subscriptions.push(disposable); 18 | context.subscriptions.push(taskProvider); 19 | } 20 | 21 | export function deactivate() { 22 | } -------------------------------------------------------------------------------- /src/test/.gitignore: -------------------------------------------------------------------------------- 1 | list/*.* -------------------------------------------------------------------------------- /src/test/a.a.test.ts: -------------------------------------------------------------------------------- 1 | 2 | import micromatch from 'micromatch' 3 | 4 | // mm(list, patterns[, options]); 5 | 6 | suite("MM tests", function(this: Mocha.Suite) { 7 | 8 | this.timeout(0); 9 | 10 | this.beforeAll(async () => { 11 | }); 12 | 13 | return; 14 | 15 | /***************************************************************************************/ 16 | /***************************************************************************************/ 17 | /***************************************************************************************/ 18 | 19 | test("MM 1", async() => { 20 | let options: micromatch.Options = { 21 | basename: false, 22 | dot: true, 23 | nocase: true, 24 | }; 25 | 26 | let list = [ 27 | '.vscode/a.js', 28 | '.vscode/test/null/b.js', 29 | 'any/.vscode/test/null/c.js', 30 | '.vscode/.test/null/d.js', 31 | '.vscode/test/.null/d.js', 32 | '.any/null/.vscode/test/d.js', 33 | 'any/.null/.vscode/test/d.js' 34 | ]; 35 | 36 | let pattern = [ 37 | '**/.vscode/**' 38 | ]; 39 | 40 | while(pattern.length > 0) { 41 | const testOne = micromatch(list, pattern, options); 42 | options.dot = true; 43 | const testTwo = micromatch(list, pattern, options); 44 | options.dot = false; 45 | const testThree = micromatch(list, pattern, options); 46 | 47 | pattern = []; 48 | 49 | console.log(testOne); 50 | console.log(testTwo); 51 | console.log(testThree); 52 | } 53 | }) 54 | }); -------------------------------------------------------------------------------- /src/test/cobol-unit.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import * as vscode from "vscode"; 3 | import { CobolAnalisisHelper } from "../vms_cobol/context/CobolAnalisisHelpers"; 4 | 5 | suite("COBOL UNIT tests", function(this: Mocha.Suite) { 6 | 7 | this.timeout(0); 8 | 9 | this.beforeAll(async () => { 10 | }); 11 | 12 | return; 13 | 14 | /***************************************************************************************/ 15 | /***************************************************************************************/ 16 | /***************************************************************************************/ 17 | 18 | test("literal", async() => { 19 | 20 | assert.equal("", CobolAnalisisHelper.stringLiteralContent("")); 21 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("abc")); 22 | assert.equal("nabc", CobolAnalisisHelper.stringLiteralContent("nabc")); 23 | assert.equal("Nabc", CobolAnalisisHelper.stringLiteralContent("Nabc")); 24 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("\"abc\"")); 25 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("'abc'")); 26 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("n'abc'")); 27 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("N'abc'")); 28 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("N\"abc\"")); 29 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("\"abc")); 30 | assert.equal("abc'", CobolAnalisisHelper.stringLiteralContent("\"abc'")); 31 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("'abc")); 32 | assert.equal("abc\"", CobolAnalisisHelper.stringLiteralContent("N'abc\"")); 33 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("N\"abc")); 34 | assert.equal("abc'", CobolAnalisisHelper.stringLiteralContent("\"abc'")); 35 | assert.equal("abc", CobolAnalisisHelper.stringLiteralContent("n'abc")); 36 | assert.equal("abc\"", CobolAnalisisHelper.stringLiteralContent("n'abc\"")); 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /src/test/long.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | 3 | suite("LONG tests", function(this: Mocha.Suite) { 4 | 5 | this.timeout(0); 6 | 7 | this.beforeAll(async () => { 8 | 9 | }); 10 | 11 | return; 12 | 13 | /***************************************************************************************/ 14 | /***************************************************************************************/ 15 | /***************************************************************************************/ 16 | 17 | test("long", async() => { 18 | 19 | console.log("start"); 20 | 21 | let stop = false; 22 | let max = 1000000; 23 | 24 | let lognAsyncFnWithAwait = async () => { 25 | let count: number = 0; 26 | for(let i = 0; i < max && !stop; ++i) { 27 | await new Promise(resolve => { 28 | setImmediate(() => { 29 | resolve(); 30 | }) 31 | }) 32 | ++count; 33 | } 34 | return count; 35 | } 36 | 37 | let result = lognAsyncFnWithAwait(); 38 | 39 | //stop = true; 40 | 41 | let counter = await result; 42 | 43 | console.log('stop'); 44 | 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /src/test/quotes.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { test_enclosing_quotes } from "../common/quotes"; 3 | 4 | suite("Quotes tests", function(this: Mocha.Suite) { 5 | 6 | this.timeout(0); 7 | 8 | this.beforeAll(async () => { 9 | // prepare 10 | }); 11 | 12 | test("Quotes test", async () => { 13 | let test_strs = [ 14 | { str: '"abcd"', enclosed: true }, 15 | { str: '"abcd', enclosed: false }, 16 | { str: '"ab\\"cd', enclosed: false }, 17 | { str: '"ab\\"cd"', enclosed: true }, 18 | { str: '"ab\\"', enclosed: false }, 19 | { str: '"ab\\\\"', enclosed: true }, 20 | ]; 21 | for(let test_str of test_strs) { 22 | assert.equal(test_enclosing_quotes(test_str.str).enclosed, test_str.enclosed, test_str.str); 23 | } 24 | }); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /src/vms_basic/context/AnalysisListener.ts: -------------------------------------------------------------------------------- 1 | import * as nls from "vscode-nls"; 2 | 3 | import { BasicParserListener } from '../parser/BasicParserListener'; 4 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 5 | import { Token } from "antlr4ts"; 6 | //import { TerminalNode } from "antlr4ts/tree"; 7 | import { 8 | ProgramContext 9 | } from "../parser/BasicParser"; 10 | import { ContextSymbolTable } from "./ContextSymbolTable"; 11 | //import { BaseSymbol, ScopedSymbol } from "antlr4-c3"; 12 | 13 | nls.config({messageFormat: nls.MessageFormat.both}); 14 | //const localize = nls.loadMessageBundle(); 15 | 16 | export class AnalysisListener implements BasicParserListener 17 | { 18 | constructor(public diagnostics: DiagnosticEntry[], public symbolTable: ContextSymbolTable) 19 | { } 20 | 21 | enterProgram(ctx: ProgramContext) 22 | { 23 | } 24 | 25 | /** 26 | * @returns true if doesn't exeed 27 | */ 28 | public testLength(value: string, maxlength: number, message: string, token: Token, type = DiagnosticType.Error ) 29 | { 30 | if (value.length > maxlength) 31 | { 32 | this.markToken(token, message, type); 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | /** 40 | * @returns true if value is in range 41 | */ 42 | public testRange(value: number, minvalue: number, maxvalue: number, message: string, token: Token, type = DiagnosticType.Error ) 43 | { 44 | if (minvalue <= value && value <= maxvalue) 45 | { 46 | return true; 47 | } 48 | 49 | this.markToken(token, message, type); 50 | return false; 51 | } 52 | 53 | public markToken(token: Token, message: string, type = DiagnosticType.Error ) 54 | { 55 | this.markText(message, token.charPositionInLine, token.line, (token.text? token.text.length : 0), type); 56 | } 57 | 58 | public markText(message: string, column: number, row: number, length: number, type = DiagnosticType.Error ) 59 | { 60 | const error: DiagnosticEntry = { 61 | type, 62 | message, 63 | range: 64 | { 65 | start: { column, row }, 66 | end: { column: column + length, row } 67 | } 68 | }; 69 | 70 | this.diagnostics.push(error); 71 | } 72 | } -------------------------------------------------------------------------------- /src/vms_basic/context/ContextErrorListener.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 4 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 5 | 6 | 7 | export class ContextLexerErrorListener implements ANTLRErrorListener 8 | { 9 | constructor(private errorList: DiagnosticEntry[]) 10 | { } 11 | 12 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 13 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 14 | { 15 | let error: DiagnosticEntry = { 16 | type: DiagnosticType.Error, 17 | message: msg, 18 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 19 | }; 20 | 21 | this.errorList.push(error); 22 | } 23 | } 24 | 25 | export class ContextErrorListener implements ANTLRErrorListener 26 | { 27 | constructor(private errorList: DiagnosticEntry[]) 28 | { } 29 | 30 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 31 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 32 | { 33 | let error: DiagnosticEntry = { 34 | type: DiagnosticType.Error, 35 | message: msg, 36 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 37 | }; 38 | 39 | if (offendingSymbol) 40 | { 41 | error.range.end.column = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 42 | } 43 | 44 | this.errorList.push(error); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_basic/providers/CompletionProvider.ts: -------------------------------------------------------------------------------- 1 | 2 | import { TextDocument, Position, CancellationToken, CompletionItem, ProviderResult, CompletionList } from 'vscode'; 3 | import { Facade } from '../context/Facade'; 4 | import { translateCompletionKind } from '../context/Symbol'; 5 | 6 | // Determines the sort order in the completion list. One value for each SymbolKind. 7 | const sortKeys = [ 8 | "99", // Other 9 | ]; 10 | 11 | // Descriptions for each symbol kind. 12 | const details = [ 13 | "Other", 14 | ]; 15 | 16 | export class BasicCompletionItemProvider 17 | { 18 | constructor(private backend: Facade) { } 19 | 20 | public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 21 | { 22 | let candidates = this.backend.getCodeCompletionCandidates(document.fileName, position.character, position.line + 1); 23 | let completionList: CompletionItem[] = []; 24 | 25 | candidates.forEach(info => { 26 | let item = new CompletionItem(info.name.toLowerCase(), translateCompletionKind(info.kind)); 27 | item.sortText = sortKeys[info.kind] + info.name; 28 | item.detail = (info.description !== undefined) ? info.description : details[info.kind]; 29 | completionList.push(item); 30 | }); 31 | 32 | return new CompletionList(completionList, false); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/vms_basic/providers/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class BasicDefinitionProvider implements DefinitionProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 9 | { 10 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character + 1, position.line + 1); 11 | 12 | if (!info) 13 | { 14 | return undefined; 15 | } 16 | 17 | if (info.definition) 18 | { 19 | let range = new Range( 20 | info.definition.range.start.row - 1, info.definition.range.start.column, 21 | info.definition.range.end.row - 1, info.definition.range.end.column 22 | ); 23 | return new Location(Uri.file(info.source), range); 24 | } 25 | else 26 | { 27 | // Empty for built-in entities or self-define attempts. 28 | return new Location(document.uri, position); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/vms_basic/providers/HoverProvider.ts: -------------------------------------------------------------------------------- 1 | import { HoverProvider, TextDocument, Position, CancellationToken, Hover } from "vscode"; 2 | import { Facade } from "../context/Facade"; 3 | import { symbolDescriptionFromEnum } from '../context/Symbol'; 4 | import { Basic } from '../extension'; 5 | import * as path from 'path'; 6 | 7 | 8 | export class BasicHoverProvider implements HoverProvider 9 | { 10 | constructor(private backend: Facade) { } 11 | 12 | public async provideHover(document: TextDocument, position: Position, token: CancellationToken)//: ProviderResult 13 | { 14 | let positionInfo = ""; 15 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character + 1, position.line + 1); 16 | 17 | if (!info) 18 | { 19 | return undefined; 20 | } 21 | 22 | if(info.definition) 23 | { 24 | if (info.definition.range) 25 | { 26 | positionInfo += ` at ${info.definition.range.start.row}:${info.definition.range.start.column}`; 27 | } 28 | } 29 | 30 | const description = symbolDescriptionFromEnum(info.kind); 31 | return new Hover([ 32 | "**" + description + "**\ndefined in: " + path.basename(info.source) + positionInfo, 33 | { language: Basic.language, value: (info.dataInfo? info.dataInfo : "") } 34 | ]); 35 | } 36 | } -------------------------------------------------------------------------------- /src/vms_basic/providers/ReferenceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | Location, 4 | Position, 5 | ProviderResult, 6 | Range, 7 | ReferenceContext, 8 | ReferenceProvider, 9 | TextDocument, 10 | Uri, 11 | } from 'vscode'; 12 | import { Facade } from '../context/Facade'; 13 | 14 | export class BasicReferenceProvider implements ReferenceProvider 15 | { 16 | constructor(private backend: Facade) { } 17 | 18 | public provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult 19 | { 20 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 21 | const result: Location[] = []; 22 | 23 | if (occurences.length > 0 ) 24 | { 25 | for (let symbol of occurences) 26 | { 27 | if (symbol.definition) 28 | { 29 | let range = new Range( 30 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 31 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 32 | ); 33 | 34 | const loc: Location = { 35 | range, 36 | uri: Uri.file(symbol.source), 37 | }; 38 | 39 | result.push(loc); 40 | } 41 | } 42 | } 43 | 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_basic/providers/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class BasicRenameProvider implements RenameProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, 9 | token: CancellationToken): ProviderResult 10 | { 11 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character+1, position.line + 1); 12 | 13 | if (occurences.length) 14 | { 15 | const result = new WorkspaceEdit(); 16 | 17 | for (let symbol of occurences) 18 | { 19 | if (symbol.definition) 20 | { 21 | let range = new Range( 22 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 23 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 24 | ); 25 | 26 | result.replace(Uri.file(symbol.source), range, newName); 27 | } 28 | } 29 | 30 | return result; 31 | } 32 | 33 | return undefined; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/vms_cobol/parser/cobolCopy.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | null 4 | null 5 | null 6 | null 7 | null 8 | null 9 | null 10 | null 11 | null 12 | null 13 | null 14 | null 15 | null 16 | ',' 17 | ';' 18 | null 19 | null 20 | null 21 | 22 | token symbolic names: 23 | null 24 | PSEUDO_TEXT_ 25 | STRING_LITERAL_ 26 | COPY 27 | IN 28 | OF 29 | FROM 30 | DICTIONARY 31 | REPLACING 32 | BY 33 | DOT_ 34 | NUMERIC_LITERAL_ 35 | HEX_LITERAL_ 36 | USER_DEFINED_WORD_ 37 | COMMA_ 38 | SEMI_ 39 | WHITESPACE_ 40 | NEWLINE_ 41 | ANY_CHAR_ 42 | 43 | rule names: 44 | copyStatement 45 | lastCopyStatement 46 | text_name 47 | library_name 48 | record_name 49 | repl_from 50 | repl_to 51 | 52 | 53 | atn: 54 | [3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 3, 20, 61, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 3, 2, 7, 2, 18, 10, 2, 12, 2, 14, 2, 21, 11, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 30, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 36, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 43, 10, 3, 13, 3, 14, 3, 44, 5, 3, 47, 10, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 19, 2, 2, 9, 2, 2, 4, 2, 6, 2, 8, 2, 10, 2, 12, 2, 14, 2, 2, 5, 3, 2, 6, 7, 4, 2, 4, 4, 15, 15, 5, 2, 3, 4, 13, 13, 15, 15, 2, 58, 2, 19, 3, 2, 2, 2, 4, 25, 3, 2, 2, 2, 6, 50, 3, 2, 2, 2, 8, 52, 3, 2, 2, 2, 10, 54, 3, 2, 2, 2, 12, 56, 3, 2, 2, 2, 14, 58, 3, 2, 2, 2, 16, 18, 11, 2, 2, 2, 17, 16, 3, 2, 2, 2, 18, 21, 3, 2, 2, 2, 19, 20, 3, 2, 2, 2, 19, 17, 3, 2, 2, 2, 20, 22, 3, 2, 2, 2, 21, 19, 3, 2, 2, 2, 22, 23, 5, 4, 3, 2, 23, 24, 7, 2, 2, 3, 24, 3, 3, 2, 2, 2, 25, 35, 7, 5, 2, 2, 26, 29, 5, 6, 4, 2, 27, 28, 9, 2, 2, 2, 28, 30, 5, 8, 5, 2, 29, 27, 3, 2, 2, 2, 29, 30, 3, 2, 2, 2, 30, 36, 3, 2, 2, 2, 31, 32, 5, 10, 6, 2, 32, 33, 7, 8, 2, 2, 33, 34, 7, 9, 2, 2, 34, 36, 3, 2, 2, 2, 35, 26, 3, 2, 2, 2, 35, 31, 3, 2, 2, 2, 36, 46, 3, 2, 2, 2, 37, 42, 7, 10, 2, 2, 38, 39, 5, 12, 7, 2, 39, 40, 7, 11, 2, 2, 40, 41, 5, 14, 8, 2, 41, 43, 3, 2, 2, 2, 42, 38, 3, 2, 2, 2, 43, 44, 3, 2, 2, 2, 44, 42, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 47, 3, 2, 2, 2, 46, 37, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 49, 7, 12, 2, 2, 49, 5, 3, 2, 2, 2, 50, 51, 9, 3, 2, 2, 51, 7, 3, 2, 2, 2, 52, 53, 9, 3, 2, 2, 53, 9, 3, 2, 2, 2, 54, 55, 9, 3, 2, 2, 55, 11, 3, 2, 2, 2, 56, 57, 9, 4, 2, 2, 57, 13, 3, 2, 2, 2, 58, 59, 9, 4, 2, 2, 59, 15, 3, 2, 2, 2, 7, 19, 29, 35, 44, 46] -------------------------------------------------------------------------------- /src/vms_cobol/parser/cobolCopy.tokens: -------------------------------------------------------------------------------- 1 | PSEUDO_TEXT_=1 2 | STRING_LITERAL_=2 3 | COPY=3 4 | IN=4 5 | OF=5 6 | FROM=6 7 | DICTIONARY=7 8 | REPLACING=8 9 | BY=9 10 | DOT_=10 11 | NUMERIC_LITERAL_=11 12 | HEX_LITERAL_=12 13 | USER_DEFINED_WORD_=13 14 | COMMA_=14 15 | SEMI_=15 16 | WHITESPACE_=16 17 | NEWLINE_=17 18 | ANY_CHAR_=18 19 | ','=14 20 | ';'=15 21 | -------------------------------------------------------------------------------- /src/vms_cobol/parser/cobolCopyLexer.tokens: -------------------------------------------------------------------------------- 1 | PSEUDO_TEXT_=1 2 | STRING_LITERAL_=2 3 | COPY=3 4 | IN=4 5 | OF=5 6 | FROM=6 7 | DICTIONARY=7 8 | REPLACING=8 9 | BY=9 10 | DOT_=10 11 | NUMERIC_LITERAL_=11 12 | HEX_LITERAL_=12 13 | USER_DEFINED_WORD_=13 14 | COMMA_=14 15 | SEMI_=15 16 | WHITESPACE_=16 17 | NEWLINE_=17 18 | ANY_CHAR_=18 19 | ','=14 20 | ';'=15 21 | -------------------------------------------------------------------------------- /src/vms_cobol/parser/cobolParserImpl.ts: -------------------------------------------------------------------------------- 1 | import { cobolParser } from "../parser/cobolParser"; 2 | import { TaskDivider } from "../../common/task-divider"; 3 | import { TokenStream } from "antlr4ts"; 4 | import { testTokenInAreaB } from "../../common/parser/helpers"; 5 | 6 | export class cobolParserImpl extends cobolParser { 7 | 8 | private thisTask: number; 9 | 10 | constructor(input: TokenStream, private taskDivider?: TaskDivider) { 11 | super(input); 12 | this.thisTask = taskDivider ? taskDivider.asyncValue : 0; 13 | } 14 | 15 | async cobol_source() { 16 | return super.cobol_source(); 17 | } 18 | 19 | async exitRule() { 20 | if (this.thisTask != (this.taskDivider ? await this.taskDivider.testValue() : 0)) { 21 | throw "task has been re-entered"; 22 | } 23 | return super.exitRule(); 24 | } 25 | 26 | public testCurrentWordInAreaB() { 27 | return testTokenInAreaB(this.inputStream.LT(1)); 28 | } 29 | } -------------------------------------------------------------------------------- /src/vms_cobol/stream/CopyManagerImpl.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | 4 | import { ICopyManager } from "./cobolInputStream"; 5 | import { VmsPathConverter } from "../../synchronizer/vms/vms-path-converter"; 6 | 7 | export class CopyManagerImpl implements ICopyManager { 8 | 9 | /** 10 | * key is VMS path 11 | */ 12 | private copyContents: Map = new Map(); 13 | private copySource: Map = new Map(); 14 | 15 | constructor(private root: string) { 16 | 17 | } 18 | 19 | getRoot() { 20 | return this.root; 21 | } 22 | 23 | public clear(fileName?: string): boolean { 24 | if (fileName) { 25 | for (let [name, file] of this.copySource) { 26 | if (file === fileName) { 27 | this.copyContents.delete(name); 28 | this.copySource.delete(name); 29 | return true; 30 | } 31 | } 32 | return false; 33 | } 34 | this.copyContents.clear(); 35 | this.copySource.clear(); 36 | return true; 37 | } 38 | 39 | getSourcePath(name: string): string | undefined { 40 | return this.copySource.get(name); 41 | } 42 | 43 | getLines(name: string): string[] { 44 | let lines: string[] | undefined = this.copyContents.get(name); 45 | if (!lines) { 46 | try { 47 | let converter = VmsPathConverter.fromVms(name); 48 | let filePath = path.join(this.root, converter.initial); 49 | if (!converter.fileExt) { 50 | filePath += ".lib"; 51 | } 52 | let buffer = fs.readFileSync(filePath); 53 | let content = buffer.toString("utf8"); 54 | lines = content.split(/\r?\n/g); 55 | this.copyContents.set(name, lines); 56 | this.copySource.set(name, filePath); 57 | } catch(e) { 58 | lines = undefined; 59 | } 60 | } 61 | if (lines) { 62 | return [...lines]; 63 | } 64 | return []; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/vms_cobol/stream/CopyManagers.ts: -------------------------------------------------------------------------------- 1 | import { ICopyManager } from "./cobolInputStream"; 2 | import { CopyManagerImpl } from "./CopyManagerImpl"; 3 | 4 | const _copyManagers = new Map(); 5 | 6 | export function GetCopyManager(scopeName: string, scopePath?: string): ICopyManager | undefined { 7 | let copyManager = _copyManagers.get(scopeName); 8 | if (!copyManager && scopePath) { 9 | copyManager = new CopyManagerImpl(scopePath); 10 | _copyManagers.set(scopeName, copyManager); 11 | } 12 | return copyManager; 13 | } -------------------------------------------------------------------------------- /src/vms_debug/parsers/debug_variable_info.ts: -------------------------------------------------------------------------------- 1 | export enum ReflectKind 2 | { 3 | Value = -1, 4 | Invalid = 0, 5 | Atomic, 6 | Block, 7 | Array, 8 | Class, 9 | Func, 10 | Map, 11 | Pointer, 12 | String, 13 | Struct 14 | } 15 | 16 | export interface DebugVariable 17 | { 18 | name: string; 19 | nameFull: string; 20 | addr: string; 21 | type: string; 22 | kind: ReflectKind; 23 | value: string; 24 | info: string; 25 | prefix: string; 26 | len: number; 27 | children: DebugVariable[]; 28 | unreadable: string; 29 | fullyQualifiedName: string; 30 | } 31 | 32 | export interface VariableFileInfo 33 | { 34 | filePath: string; 35 | moduleName: string; 36 | wrapName: string;//wrap function name 37 | functionName: string;//if "" => global variable 38 | variableName: string; 39 | variableNameFull: string; 40 | variableType: string; 41 | variableValue: string; 42 | variableInfo: string; 43 | variablePrefix: string; 44 | variableAddress: string; 45 | variableKind: ReflectKind; 46 | } 47 | 48 | export class HolderDebugVariableInfo 49 | { 50 | private variables = new Map(); 51 | 52 | 53 | public getSize() : number 54 | { 55 | return this.variables.size; 56 | } 57 | 58 | public getVariableFile(pathName : string) : VariableFileInfo[] | undefined 59 | { 60 | return this.variables.get(pathName); 61 | } 62 | 63 | public setVariableFile(pathName : string, vars: VariableFileInfo[]) : void 64 | { 65 | this.variables.set(pathName, vars); 66 | } 67 | } -------------------------------------------------------------------------------- /src/vms_debug/queue/queues.ts: -------------------------------------------------------------------------------- 1 | export class Queue 2 | { 3 | private data : any[] = []; 4 | 5 | push = (item: T) => this.data.push(item); 6 | pop = (): T => this.data.shift(); 7 | size = () : number => this.data.length; 8 | getv = (): T | undefined => 9 | { 10 | if(this.data.length > 0) 11 | { 12 | return this.data[0]; 13 | } 14 | 15 | return undefined; 16 | } 17 | } -------------------------------------------------------------------------------- /src/vms_debug/ui/status_bar.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { StatusBarItem, StatusBarAlignment } from "vscode"; 3 | 4 | 5 | export class StatusBarDebug 6 | { 7 | private barMessage: StatusBarItem = vscode.window.createStatusBarItem(StatusBarAlignment.Left); 8 | 9 | 10 | public setMessage(message : string) 11 | { 12 | this.barMessage.text = `$(bug) ${message}`; 13 | this.barMessage.show(); 14 | } 15 | 16 | public hideMessage() 17 | { 18 | this.barMessage.hide(); 19 | } 20 | 21 | dispose() 22 | { 23 | this.barMessage.dispose(); 24 | } 25 | } -------------------------------------------------------------------------------- /src/vms_fortran/context/ContextErrorListener.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 4 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 5 | 6 | 7 | export class ContextLexerErrorListener implements ANTLRErrorListener 8 | { 9 | constructor(private errorList: DiagnosticEntry[]) 10 | { } 11 | 12 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 13 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 14 | { 15 | let error: DiagnosticEntry = { 16 | type: DiagnosticType.Error, 17 | message: msg, 18 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 19 | }; 20 | 21 | this.errorList.push(error); 22 | } 23 | } 24 | 25 | export class ContextErrorListener implements ANTLRErrorListener 26 | { 27 | constructor(private errorList: DiagnosticEntry[]) 28 | { } 29 | 30 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 31 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 32 | { 33 | let error: DiagnosticEntry = { 34 | type: DiagnosticType.Error, 35 | message: msg, 36 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 37 | }; 38 | 39 | if (offendingSymbol) 40 | { 41 | error.range.end.column = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 42 | } 43 | 44 | this.errorList.push(error); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_fortran/providers/CompletionProvider.ts: -------------------------------------------------------------------------------- 1 | 2 | import { TextDocument, Position, CancellationToken, CompletionItem, ProviderResult, CompletionList } from 'vscode'; 3 | import { Facade } from '../context/Facade'; 4 | import { translateCompletionKind } from '../context/Symbol'; 5 | 6 | // Determines the sort order in the completion list. One value for each SymbolKind. 7 | const sortKeys = [ 8 | "99", // Other 9 | ]; 10 | 11 | // Descriptions for each symbol kind. 12 | const details = [ 13 | "Other", 14 | ]; 15 | 16 | export class FortranCompletionItemProvider 17 | { 18 | constructor(private backend: Facade) { } 19 | 20 | public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 21 | { 22 | let candidates = this.backend.getCodeCompletionCandidates(document.fileName, position.character, position.line + 1); 23 | let completionList: CompletionItem[] = []; 24 | 25 | candidates.forEach(info => { 26 | let item = new CompletionItem(info.name.toLowerCase(), translateCompletionKind(info.kind)); 27 | item.sortText = sortKeys[info.kind] + info.name; 28 | item.detail = (info.description !== undefined) ? info.description : details[info.kind]; 29 | completionList.push(item); 30 | }); 31 | 32 | return new CompletionList(completionList, false); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/vms_fortran/providers/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class FortranDefinitionProvider implements DefinitionProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 9 | { 10 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character + 1, position.line + 1); 11 | 12 | if (!info) 13 | { 14 | return undefined; 15 | } 16 | 17 | if (info.definition) 18 | { 19 | let range = new Range( 20 | info.definition.range.start.row - 1, info.definition.range.start.column, 21 | info.definition.range.end.row - 1, info.definition.range.end.column 22 | ); 23 | return new Location(Uri.file(info.source), range); 24 | } 25 | else 26 | { 27 | // Empty for built-in entities or self-define attempts. 28 | return new Location(document.uri, position); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/vms_fortran/providers/ReferenceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | Location, 4 | Position, 5 | ProviderResult, 6 | Range, 7 | ReferenceContext, 8 | ReferenceProvider, 9 | TextDocument, 10 | Uri, 11 | } from 'vscode'; 12 | import { Facade } from '../context/Facade'; 13 | 14 | export class FortranReferenceProvider implements ReferenceProvider 15 | { 16 | constructor(private backend: Facade) { } 17 | 18 | public provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult 19 | { 20 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 21 | const result: Location[] = []; 22 | 23 | if (occurences.length > 0 ) 24 | { 25 | for (let symbol of occurences) 26 | { 27 | if (symbol.definition) 28 | { 29 | let range = new Range( 30 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 31 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 32 | ); 33 | 34 | const loc: Location = { 35 | range, 36 | uri: Uri.file(symbol.source), 37 | }; 38 | 39 | result.push(loc); 40 | } 41 | } 42 | } 43 | 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_fortran/providers/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class FortranRenameProvider implements RenameProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, 9 | token: CancellationToken): ProviderResult 10 | { 11 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character+1, position.line + 1); 12 | 13 | if (occurences.length) 14 | { 15 | const result = new WorkspaceEdit(); 16 | 17 | for (let symbol of occurences) 18 | { 19 | if (symbol.definition) 20 | { 21 | let range = new Range( 22 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 23 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 24 | ); 25 | 26 | result.replace(Uri.file(symbol.source), range, newName); 27 | } 28 | } 29 | 30 | return result; 31 | } 32 | 33 | return undefined; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/vms_jvm_debug/drop.ts: -------------------------------------------------------------------------------- 1 | import { IDropCommand } from "./communication"; 2 | 3 | export class DropCommand implements IDropCommand { 4 | 5 | private _callback?: (reason?: any) => void; 6 | 7 | public onDropCommand(callback: (reason: any) => void): void { 8 | this._callback = callback; 9 | } 10 | 11 | public doDropCommand(reason?: any) { 12 | if (this._callback) { 13 | this._callback(reason); 14 | } 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/vms_jvm_debug/jvm-config.ts: -------------------------------------------------------------------------------- 1 | 2 | import { DebugProtocol } from "@vscode/debugprotocol"; 3 | import { DebugConfiguration } from "vscode"; 4 | 5 | /** 6 | * This interface describes the vms_jvm_debugger specific launch attributes 7 | * (which are not part of the Debug Adapter Protocol). 8 | * The schema for these attributes lives in the package.json of the mock-debug extension. 9 | * The interface should always match this schema. 10 | */ 11 | export interface IJvmLaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { 12 | /** a class to execute. */ 13 | class: string; 14 | /** a ':' separated list of directories, JAR archives, and ZIP archives to search for class files. */ 15 | classpath: string; 16 | /** a port to debug. */ 17 | port?: string; 18 | /** command line arguments */ 19 | arguments?: string; 20 | /** automatically stop target after launch. If not specified, target does not stop. */ 21 | stopOnEntry?: boolean; 22 | /** enable logging the Debug Adapter Protocol */ 23 | trace?: boolean; 24 | /** current scope */ 25 | scope?: string; 26 | } 27 | 28 | export interface IJvmDebugConfiguration extends DebugConfiguration { 29 | /** a class to execute. */ 30 | class: string; 31 | /** a ':' separated list of directories, JAR archives, and ZIP archives to search for class files. */ 32 | classpath: string; 33 | /** a port to debug. */ 34 | port?: string; 35 | /** command line arguments */ 36 | arguments?: string; 37 | /** automatically stop target after launch. If not specified, target does not stop. */ 38 | stopOnEntry?: boolean; 39 | /** enable logging the Debug Adapter Protocol */ 40 | trace?: boolean; 41 | } 42 | 43 | export function isJvmDebugConfiguration(candidate: any): candidate is IJvmDebugConfiguration { 44 | return !!candidate && 45 | typeof candidate.type === "string" && 46 | typeof candidate.name === "string" && 47 | typeof candidate.request === "string" && 48 | typeof candidate.class === "string" && 49 | typeof candidate.classpath === "string"; 50 | } -------------------------------------------------------------------------------- /src/vms_jvm_debug/jvm-state-machine.ts: -------------------------------------------------------------------------------- 1 | 2 | export enum JvmState { 3 | anyState, 4 | initial, 5 | askAttach, 6 | paused, 7 | askSetBreak, 8 | askClearBreak, 9 | askRun, 10 | askThreads, 11 | askLocals, 12 | askStack, 13 | askStep, 14 | askStop, 15 | running, 16 | waitThreadPrompt, 17 | }; 18 | 19 | export enum JvmAction { 20 | attach, 21 | setBreak, 22 | clearBreak, 23 | run, 24 | threads, 25 | locals, 26 | stack, 27 | step, 28 | stop, 29 | }; 30 | 31 | export interface IJvmMove { 32 | from: JvmState; 33 | to: JvmState; 34 | reason: JvmAction | RegExp; 35 | emits?: string[]; 36 | } 37 | 38 | const JvmMoves: IJvmMove[] = [ 39 | { from: JvmState.initial, 40 | to: JvmState.askAttach, 41 | reason: JvmAction.attach, 42 | }, 43 | { from: JvmState.askAttach, 44 | to: JvmState.initial, 45 | reason: /Unable to attach to target VM./, 46 | }, 47 | { from: JvmState.askAttach, 48 | to: JvmState.paused, 49 | reason: /main\[1\]/, 50 | }, 51 | { from: JvmState.anyState, 52 | to: JvmState.askSetBreak, 53 | reason: JvmAction.setBreak, 54 | }, 55 | { from: JvmState.paused, 56 | to: JvmState.askClearBreak, 57 | reason: JvmAction.clearBreak, 58 | }, 59 | { from: JvmState.paused, 60 | to: JvmState.askRun, 61 | reason: JvmAction.run, 62 | }, 63 | { from: JvmState.paused, 64 | to: JvmState.askThreads, 65 | reason: JvmAction.threads, 66 | }, 67 | { from: JvmState.paused, 68 | to: JvmState.askLocals, 69 | reason: JvmAction.locals, 70 | }, 71 | { from: JvmState.paused, 72 | to: JvmState.askStack, 73 | reason: JvmAction.stack, 74 | }, 75 | { from: JvmState.paused, 76 | to: JvmState.askStep, 77 | reason: JvmAction.step, 78 | }, 79 | { from: JvmState.paused, 80 | to: JvmState.askStop, 81 | reason: JvmAction.stop, 82 | }, 83 | { from: JvmState.askSetBreak, 84 | to: JvmState.askStop, 85 | reason: JvmAction.stop, 86 | }, 87 | ]; 88 | 89 | export class JvmStateMachine { 90 | 91 | 92 | 93 | } -------------------------------------------------------------------------------- /src/vms_jvm_debug/shell-splitter.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from "stream"; 2 | import { EventEmitter } from "events"; 3 | import { ICmdClient } from "./communication"; 4 | import { LogFunction, LogType } from "../common/main"; 5 | 6 | //const _rgxNL = /(?:\r)?\n/g; 7 | const _rgxNL = /\n/g; 8 | 9 | export class ShellSplitter extends Transform { 10 | 11 | public _lastError: string | undefined; 12 | 13 | constructor(private _client: ICmdClient, private _timeout = 100, private logFn?: LogFunction) { 14 | super(); 15 | 16 | this.on('close', () => { 17 | this._client.lineReceived(undefined); 18 | }); 19 | 20 | this.on('error', (err) => { 21 | this._lastError = String(err); 22 | this._client.lineReceived(undefined); 23 | }); 24 | 25 | this._client.onCommand((line: string) => { 26 | this.push(line.trim() + '\r'); 27 | }) 28 | 29 | this._client.onData((data: string) => { 30 | this.push(data); 31 | }) 32 | } 33 | 34 | private _buffer = ""; 35 | public _transform(chunk: any, encoding: string, callback: Function) { 36 | let content = ""; 37 | if (Buffer.isBuffer(chunk)) { 38 | content = chunk.toString("utf8"); 39 | } else if (typeof chunk === "string") { 40 | content = chunk; 41 | } 42 | if (this.logFn) { 43 | this.logFn(LogType.debug, () => '===' + content); 44 | } 45 | this._buffer += content; 46 | let matchNL = _rgxNL.exec(this._buffer); 47 | let start = 0; 48 | while (matchNL) { 49 | this.sendLine(this._buffer.slice(start, _rgxNL.lastIndex)); // `- matchNL[0].length` is removed, let client know about new line 50 | start = _rgxNL.lastIndex; 51 | matchNL = _rgxNL.exec(this._buffer); 52 | } 53 | this._buffer = this._buffer.slice(start); 54 | // for a prompt we will never receive new line, so wait a timeout and send buffer to the client 55 | setTimeout(() => { 56 | if (this._buffer) { 57 | this.sendLine(this._buffer); 58 | this._buffer = ""; 59 | } 60 | }, this._timeout); 61 | callback(); 62 | } 63 | 64 | private sendLine(line: string) { 65 | setImmediate(() => { 66 | this._client.lineReceived(line); 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/vms_jvm_debug/simple-cmd-client.ts: -------------------------------------------------------------------------------- 1 | import { ICmdClient } from "./communication"; 2 | import { EventEmitter } from "vscode"; 3 | 4 | export class SimpleCmdClient implements ICmdClient { 5 | 6 | constructor(private emitter: EventEmitter) { 7 | ; 8 | } 9 | 10 | onCommand(cmdListener: (line: string) => void): { dispose: () => void; } { 11 | // no commands allowed 12 | return { 13 | dispose: () => { 14 | return; 15 | } 16 | }; 17 | } 18 | 19 | onData(dataListener: (line: string) => void): { dispose: () => void; } { 20 | // no data allowed 21 | return { 22 | dispose: () => { 23 | return; 24 | } 25 | }; 26 | } 27 | 28 | lineReceived(line: string | undefined): boolean { 29 | this.emitter.fire(line); 30 | return true; 31 | } 32 | } -------------------------------------------------------------------------------- /src/vms_pascal/context/AnalysisListener.ts: -------------------------------------------------------------------------------- 1 | import * as nls from "vscode-nls"; 2 | 3 | import { pascalListener } from '../parser/pascalListener'; 4 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 5 | import { Token } from "antlr4ts"; 6 | //import { TerminalNode } from "antlr4ts/tree"; 7 | import { 8 | ProgramContext, 9 | IdentifierListContext, 10 | } from "../parser/pascalParser"; 11 | import { ContextSymbolTable } from "./ContextSymbolTable"; 12 | //import { BaseSymbol, ScopedSymbol } from "antlr4-c3"; 13 | 14 | nls.config({messageFormat: nls.MessageFormat.both}); 15 | //const localize = nls.loadMessageBundle(); 16 | 17 | export class AnalysisListener implements pascalListener 18 | { 19 | constructor(public diagnostics: DiagnosticEntry[], public symbolTable: ContextSymbolTable) 20 | { } 21 | 22 | enterProgram(ctx: ProgramContext) 23 | { 24 | } 25 | 26 | exitIdentifierList(ctx: IdentifierListContext) 27 | { 28 | } 29 | 30 | /** 31 | * @returns true if doesn't exeed 32 | */ 33 | public testLength(value: string, maxlength: number, message: string, token: Token, type = DiagnosticType.Error ) 34 | { 35 | if (value.length > maxlength) 36 | { 37 | this.markToken(token, message, type); 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | /** 45 | * @returns true if value is in range 46 | */ 47 | public testRange(value: number, minvalue: number, maxvalue: number, message: string, token: Token, type = DiagnosticType.Error ) 48 | { 49 | if (minvalue <= value && value <= maxvalue) 50 | { 51 | return true; 52 | } 53 | 54 | this.markToken(token, message, type); 55 | return false; 56 | } 57 | 58 | public markToken(token: Token, message: string, type = DiagnosticType.Error ) 59 | { 60 | this.markText(message, token.charPositionInLine, token.line, (token.text? token.text.length : 0), type); 61 | } 62 | 63 | public markText(message: string, column: number, row: number, length: number, type = DiagnosticType.Error ) 64 | { 65 | const error: DiagnosticEntry = { 66 | type, 67 | message, 68 | range: 69 | { 70 | start: { column, row }, 71 | end: { column: column + length, row } 72 | } 73 | }; 74 | 75 | this.diagnostics.push(error); 76 | } 77 | } -------------------------------------------------------------------------------- /src/vms_pascal/context/ContextErrorListener.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { ANTLRErrorListener, Recognizer, RecognitionException, Token, CommonToken } from 'antlr4ts'; 4 | import { DiagnosticEntry, DiagnosticType } from './Facade'; 5 | 6 | 7 | export class ContextLexerErrorListener implements ANTLRErrorListener 8 | { 9 | constructor(private errorList: DiagnosticEntry[]) 10 | { } 11 | 12 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 13 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 14 | { 15 | let error: DiagnosticEntry = { 16 | type: DiagnosticType.Error, 17 | message: msg, 18 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 19 | }; 20 | 21 | this.errorList.push(error); 22 | } 23 | } 24 | 25 | export class ContextErrorListener implements ANTLRErrorListener 26 | { 27 | constructor(private errorList: DiagnosticEntry[]) 28 | { } 29 | 30 | syntaxError(recognizer: Recognizer, offendingSymbol: T | undefined, line: number, 31 | charPositionInLine: number, msg: string, e: RecognitionException | undefined): void 32 | { 33 | let error: DiagnosticEntry = { 34 | type: DiagnosticType.Error, 35 | message: msg, 36 | range: { start: { column: charPositionInLine, row: line }, end: { column: charPositionInLine + 1, row: line }} 37 | }; 38 | 39 | if (offendingSymbol) 40 | { 41 | error.range.end.column = charPositionInLine + offendingSymbol.stopIndex - offendingSymbol.startIndex + 1; 42 | } 43 | 44 | this.errorList.push(error); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_pascal/providers/CompletionProvider.ts: -------------------------------------------------------------------------------- 1 | 2 | import { TextDocument, Position, CancellationToken, CompletionItem, ProviderResult, CompletionList } from 'vscode'; 3 | import { Facade } from '../context/Facade'; 4 | import { translateCompletionKind } from '../context/Symbol'; 5 | 6 | // Determines the sort order in the completion list. One value for each SymbolKind. 7 | const sortKeys = [ 8 | "99", // Other 9 | ]; 10 | 11 | // Descriptions for each symbol kind. 12 | const details = [ 13 | "Other", 14 | ]; 15 | 16 | export class PascalCompletionItemProvider 17 | { 18 | constructor(private backend: Facade) { } 19 | 20 | public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 21 | { 22 | let candidates = this.backend.getCodeCompletionCandidates(document.fileName, position.character, position.line + 1); 23 | let completionList: CompletionItem[] = []; 24 | 25 | candidates.forEach(info => { 26 | let item = new CompletionItem(info.name.toLowerCase(), translateCompletionKind(info.kind)); 27 | item.sortText = sortKeys[info.kind] + info.name; 28 | item.detail = (info.description !== undefined) ? info.description : details[info.kind]; 29 | completionList.push(item); 30 | }); 31 | 32 | return new CompletionList(completionList, false); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/vms_pascal/providers/DefinitionProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Location, Uri, ProviderResult, DefinitionProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class PascalDefinitionProvider implements DefinitionProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideDefinition(document: TextDocument, position: Position, token: CancellationToken): ProviderResult 9 | { 10 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character + 1, position.line + 1); 11 | 12 | if (!info) 13 | { 14 | return undefined; 15 | } 16 | 17 | if (info.definition) 18 | { 19 | let range = new Range( 20 | info.definition.range.start.row - 1, info.definition.range.start.column, 21 | info.definition.range.end.row - 1, info.definition.range.end.column 22 | ); 23 | return new Location(Uri.file(info.source), range); 24 | } 25 | else 26 | { 27 | // Empty for built-in entities or self-define attempts. 28 | return new Location(document.uri, position); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/vms_pascal/providers/HoverProvider.ts: -------------------------------------------------------------------------------- 1 | import { HoverProvider, TextDocument, Position, CancellationToken, Hover, Range, Uri, workspace } from "vscode"; 2 | import { SymbolKind, Facade } from "../context/Facade"; 3 | import { symbolDescriptionFromEnum } from '../context/Symbol'; 4 | import { Pascal } from '../extension'; 5 | import * as path from 'path'; 6 | 7 | 8 | export class PascalHoverProvider implements HoverProvider 9 | { 10 | constructor(private backend: Facade) { } 11 | 12 | public async provideHover(document: TextDocument, position: Position, token: CancellationToken)//: ProviderResult 13 | { 14 | let positionInfo = ""; 15 | let info = this.backend.symbolInfoAtPosition(document.fileName, position.character + 1, position.line + 1); 16 | 17 | if (!info) 18 | { 19 | return undefined; 20 | } 21 | 22 | if(info.definition) 23 | { 24 | if (info.definition.range) 25 | { 26 | positionInfo += ` at ${info.definition.range.start.row}:${info.definition.range.start.column}`; 27 | } 28 | } 29 | 30 | const description = symbolDescriptionFromEnum(info.kind); 31 | return new Hover([ 32 | "**" + description + "**\ndefined in: " + path.basename(info.source) + positionInfo, 33 | { language: Pascal.language, value: (info.dataInfo? info.dataInfo : "") } 34 | ]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/vms_pascal/providers/ReferenceProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CancellationToken, 3 | Location, 4 | Position, 5 | ProviderResult, 6 | Range, 7 | ReferenceContext, 8 | ReferenceProvider, 9 | TextDocument, 10 | Uri, 11 | } from 'vscode'; 12 | import { Facade } from '../context/Facade'; 13 | 14 | export class PascalReferenceProvider implements ReferenceProvider 15 | { 16 | constructor(private backend: Facade) { } 17 | 18 | public provideReferences(document: TextDocument, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult 19 | { 20 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 21 | const result: Location[] = []; 22 | 23 | if (occurences.length > 0 ) 24 | { 25 | for (let symbol of occurences) 26 | { 27 | if (symbol.definition) 28 | { 29 | let range = new Range( 30 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 31 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 32 | ); 33 | 34 | const loc: Location = { 35 | range, 36 | uri: Uri.file(symbol.source), 37 | }; 38 | 39 | result.push(loc); 40 | } 41 | } 42 | } 43 | 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/vms_pascal/providers/RenameProvider.ts: -------------------------------------------------------------------------------- 1 | import { TextDocument, Position, CancellationToken, Range, Uri, ProviderResult, WorkspaceEdit, RenameProvider } from 'vscode'; 2 | import { Facade } from '../context/Facade'; 3 | 4 | export class PascalRenameProvider implements RenameProvider 5 | { 6 | constructor(private backend: Facade) { } 7 | 8 | public provideRenameEdits(document: TextDocument, position: Position, newName: string, 9 | token: CancellationToken): ProviderResult 10 | { 11 | const occurences = this.backend.getSymbolOccurences(document.fileName, position.character, position.line + 1); 12 | 13 | if (occurences.length) 14 | { 15 | const result = new WorkspaceEdit(); 16 | 17 | for (let symbol of occurences) 18 | { 19 | if (symbol.definition) 20 | { 21 | let range = new Range( 22 | symbol.definition.range.start.row - 1, symbol.definition.range.start.column, 23 | symbol.definition.range.end.row - 1, symbol.definition.range.end.column 24 | ); 25 | 26 | result.replace(Uri.file(symbol.source), range, newName); 27 | } 28 | } 29 | 30 | return result; 31 | } 32 | 33 | return undefined; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/zip/extension.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as vscode from 'vscode'; 3 | import { ZipApi } from './zip-api'; 4 | 5 | export async function activate(context: vscode.ExtensionContext) { 6 | 7 | return ZipApi; 8 | } 9 | 10 | export function deactivate() { 11 | // do nothing 12 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { "*": ["types/*"] }, 4 | /* Basic Options */ 5 | "target": "es2018", 6 | "module": "commonjs", 7 | "lib": [ "es2018" ], 8 | "declaration": true, 9 | "sourceMap": true, 10 | "outDir": "./out", 11 | "rootDir": "./src", 12 | "strict": true, 13 | "esModuleInterop": true, 14 | "baseUrl": "./src" 15 | }, 16 | "exclude": [ 17 | "node_modules", 18 | ".vscode-test", 19 | "out" 20 | ] 21 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "max-line-length": false, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": false, 8 | "semicolon": [ true ], 9 | "triple-equals": true, 10 | "no-var-keyword": true, 11 | "no-bitwise": false 12 | } 13 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | context: path.resolve(__dirname, 'out'), 11 | node: { 12 | __filename: true, //return relative path of original file 13 | __dirname: false, //returns full path of output file 14 | }, 15 | entry: './extension.js', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 16 | output: { 17 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 18 | path: path.resolve(__dirname, 'out'), 19 | filename: 'index.js', 20 | libraryTarget: 'commonjs2', 21 | devtoolModuleFilenameTemplate: '../[resource-path]' 22 | }, 23 | devtool: 'source-map', 24 | externals: { 25 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 26 | }, 27 | resolve: { 28 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 29 | extensions: ['.ts', '.js'] 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.ts$/, 35 | exclude: /node_modules|test/, 36 | use: [ 37 | { 38 | loader: 'ts-loader' 39 | } 40 | ] 41 | }, 42 | { 43 | test: /\.node$/, 44 | use: 'raw-loader' 45 | } 46 | ] 47 | } 48 | }; 49 | module.exports = config; 50 | --------------------------------------------------------------------------------