├── .editorconfig ├── .github └── workflows │ ├── ci.yaml │ ├── native-image.yaml │ └── release.yml ├── .gitignore ├── .vscode-test.mjs ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── DCO ├── Jenkinsfile ├── LICENSE ├── NativeImage.jenkins ├── README.md ├── USAGE_DATA.md ├── docs ├── BindingWithGrammar.md ├── CodeLens.md ├── Commands.md ├── Extensions.md ├── Features.md ├── Features │ ├── DTDFeatures.md │ ├── RelaxNGFeatures.md │ ├── XIncludeFeatures.md │ ├── XMLCatalogFeatures.md │ ├── XMLColorsFeatures.md │ ├── XMLFeatures.md │ ├── XMLFilePathSupport.md │ ├── XMLReferencesFeatures.md │ └── XSDFeatures.md ├── Folding.md ├── Formatting.md ├── Preferences.md ├── Proxy.md ├── README.md ├── Refactor.md ├── Symbols.md ├── Troubleshooting.md ├── Validation.md └── images │ ├── BindingWithGrammar │ ├── BindToGrammarCodeAction.png │ ├── BindToGrammarCodeActionDropdown.png │ ├── BindToGrammarCodeLens.png │ ├── BindToGrammarCommand.png │ ├── BindingWizardDemo.gif │ ├── BindingWizardDropdown.png │ ├── BindingWizardFileExplorer.png │ ├── GenerateDTDFromXML.gif │ ├── GenerateRelaxNGFromXML.gif │ └── GenerateXSDFromXML.gif │ ├── CodeLens │ ├── DTDElementCodeLens.gif │ ├── XSDElementCodeLens.gif │ └── XSDTypeCodeLens.gif │ ├── Commands │ └── XMLCommands.png │ ├── Extensions │ ├── DebugAttachRemote.png │ ├── DebugConfigurations.png │ ├── DebugLemMinXExtensionInEclipse.png │ ├── DebugLemMinXExtensionInVSCode.png │ ├── DebugMultiRootSetup.png │ ├── DebugVSCodeXML.png │ ├── DebugVSCodeXMLSingleRoot.png │ ├── EclipseRunDebugConfigurations.png │ ├── EclipseWithLemMinXExtensionOpen.png │ ├── HitABreakpointVSCode.png │ ├── InstallVSCodeExtensionForLemMinXExtension.png │ ├── LaunchVSCodeExtensionForLemMinXExtension.png │ ├── NewDebugConfiguration.png │ ├── PackageVSCodeExtensionForLemMinXExtension.png │ ├── ProjectWindowAndDebugWindow.png │ ├── ProjectWindowAndDebugWindowSingleRoot.png │ ├── TerminalInstallVSCodeExtensionForLemMinXExtension.png │ └── VSCodeExtensionForLemMinXExtension.png │ ├── Features │ ├── AttributeCompletionXML.gif │ ├── AutoCloseTagEndXML.gif │ ├── AutoCloseTagEndXSD.gif │ ├── AutoCloseTagSlashXML.gif │ ├── AutoCloseTagSlashXSD.gif │ ├── CodeLensBind.png │ ├── CodeLensCatalogRegistration.gif │ ├── CodeLensDTD.gif │ ├── CodeLensReferencesDTD.gif │ ├── CodeLensReferencesXSD.gif │ ├── CodeLensXSD.gif │ ├── CompletionBasedOnDTD.gif │ ├── CompletionBasedOnXSD.gif │ ├── FoldingSetTrueXML.gif │ ├── FoldingXML.gif │ ├── FormatXML.gif │ ├── GenerateXMLSchemaSnippet.gif │ ├── GenerateXMLSnippet.gif │ ├── HighlightCorrespondingXML.gif │ ├── HighlightOccurrenceXSD.gif │ ├── HoverBasedOnDTD.gif │ ├── HoverBasedOnXSD.gif │ ├── JumpToClosingTagXML.gif │ ├── JumpToClosingTagXSD.gif │ ├── JumpToElementDeclarationDTD.gif │ ├── JumpToOpeningTagXML.gif │ ├── JumpToOpeningTagXSD.gif │ ├── JumpToTypeDefinitionXSD.gif │ ├── JumpToXSDDefFromXML.gif │ ├── LinkedEditingXML.gif │ ├── RenameTagXML.gif │ ├── RenameTagXSD.gif │ ├── RenameTypeReferenceXSD.gif │ ├── SelectionRange.gif │ ├── SymbolOutlineXML.gif │ ├── TypeAutocompleteXSD.gif │ ├── ValidateXSDSameName.gif │ ├── ValidateXSDType.gif │ ├── ValidationDTD.gif │ ├── ValidationXML.gif │ ├── XIncludeDocumentLink.gif │ ├── XIncludeValidation.png │ ├── XMLColorsFeatures.png │ ├── XMLFilePathsInAttrFeatures.png │ ├── XMLFilePathsInTextFeatures.png │ ├── XMLReferencesWithDocbook.gif │ ├── XMLReferencesWithTEI.gif │ └── XMLReferencesWithWebXML.gif │ ├── Preferences │ └── HoverDocumentationQuickDemo.gif │ ├── Refactor │ ├── SurroundWithCDATA.gif │ ├── SurroundWithComments.gif │ └── SurroundWithTags.gif │ ├── RelaxNG │ ├── GoToTypeDefinitionMenu.png │ ├── GoToTypeDefinitionResult.png │ ├── RNGDefineSupport.gif │ ├── RNGHrefSupport.gif │ ├── RelaxNGCompactSyntaxOverview.png │ ├── RelaxNGCompletionAndDocumentation.png │ ├── RelaxNGHoverAndDocumentation.png │ ├── RelaxNGSnippetsSupport.gif │ ├── RelaxNGSupport.gif │ ├── RelaxNGValidation.png │ ├── RelaxNGXMLSyntaxOverview.png │ └── XMLValidatedWithRelaxNG.png │ ├── Symbols │ ├── ShowReferencedGrammars.png │ ├── SymbolsBeansWithIdAttrFilter.png │ ├── SymbolsBuildWithInlineAttrFilter.png │ ├── SymbolsPOMWithTextFilter.png │ └── SymbolsPOMWithoutFilter.png │ ├── Validation │ ├── DoctypeError1.png │ ├── DoctypeError2.png │ ├── ExternalEntityResolvingDemonstration.gif │ ├── GenerateXSD.gif │ ├── XMLGrammarError.png │ ├── XMLSyntaxError.png │ └── XMLSyntaxErrorCodeAction.gif │ ├── pre-release.png │ └── vscode-xml-maven.gif ├── eslint.config.mjs ├── gulpfile.js ├── icons └── icon128.png ├── images ├── DebugAttachRemote.png ├── DebugMenuCallStack.png ├── DownloadBinaryArtifacts.png ├── DownloadBinaryChecks.png └── LaunchExtension.png ├── package-lock.json ├── package.json ├── rnc.language-configuration.json ├── schemas └── package.schema.json ├── src ├── api │ ├── xmlExtensionApi.ts │ └── xmlExtensionApiImplementation.ts ├── client │ ├── clientErrorHandler.ts │ ├── indentation.ts │ ├── languageParticipants.ts │ ├── tagClosing.ts │ └── xmlClient.ts ├── commands │ ├── clientCommandConstants.ts │ ├── lspCommandConstants.ts │ ├── registerCommands.ts │ └── serverCommandConstants.ts ├── extension.ts ├── lsp-commands.ts ├── markdownPreviewProvider.ts ├── plugin.ts ├── server │ ├── binary │ │ ├── binaryHashManager.ts │ │ └── binaryServerStarter.ts │ ├── java │ │ ├── javaServerStarter.ts │ │ └── jvmArguments.ts │ ├── requirements.ts │ └── serverStarter.ts ├── settings │ ├── externalXmlSettings.ts │ ├── proxySettings.ts │ ├── settings.ts │ └── variableSubstitution.ts ├── telemetry.ts ├── test │ └── smoke.test.ts └── utils │ └── fileUtils.ts ├── syntaxes ├── dtd.tmLanguage.json └── rnc.tmLanguage.json ├── test-workspace └── .vscode │ └── settings.json ├── tsconfig.json ├── webpack.config.js └── webview-resources ├── document.css ├── highlight.css └── markdown.css /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | charset = utf-8 4 | trim_trailing_whitespace = true 5 | insert_final_newline = false 6 | 7 | [*.{ts,js,json,md}] 8 | indent_style = space 9 | indent_size = 2 -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | on: [ push, pull_request ] 3 | jobs: 4 | 5 | lint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - name: Install dependencies 10 | run: npm i --also=dev 11 | - name: Run TypeScript compiler (under webpack) 12 | run: npm run compile 13 | - name: Run ESLint 14 | run: npm run eslint 15 | 16 | build-test-native-image: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | repository: 'eclipse/lemminx' 22 | - uses: graalvm/setup-graalvm@557ffcf459751b4d92319ee255bf3bec9b73964c #v1.2.5 23 | with: 24 | distribution: graalvm-community 25 | java-version: 17 26 | - run: ./mvnw -B package -Dnative -DskipTests -Dgraalvm.static=-H:+StaticExecutableWithDynamicLibC -Dcbi.jarsigner.skip=true 27 | - run: mv org.eclipse.lemminx/target/lemminx-* lemminx-linux 28 | - uses: actions/upload-artifact@v4 29 | with: 30 | name: lemminx-linux 31 | path: lemminx-linux 32 | if-no-files-found: error 33 | 34 | smoke-test: 35 | runs-on: ubuntu-latest 36 | needs: build-test-native-image 37 | steps: 38 | - uses: actions/checkout@v4 39 | - uses: actions/download-artifact@v4 40 | with: 41 | name: lemminx-linux 42 | path: server 43 | - name: Make lemminx binary executable 44 | run: chmod u+x ./server/lemminx-linux 45 | - name: Make lemminx binary trusted 46 | run: sha256sum ./server/lemminx-linux > ./server/lemminx-linux.sha256 47 | - name: Install dependencies 48 | run: npm i --also=dev 49 | - name: Run smoke test suite 50 | run: xvfb-run npm test 51 | - name: Delete lemminx binary 52 | if: always() 53 | uses: geekyeggo/delete-artifact@e46cfb9575865f907c2beb2e4170b5f4c7d77c52 54 | with: 55 | name: lemminx-linux 56 | -------------------------------------------------------------------------------- /.github/workflows/native-image.yaml: -------------------------------------------------------------------------------- 1 | name: native-image 2 | on: 3 | workflow_call: 4 | inputs: 5 | publishPreRelease: 6 | description: 'Publish a pre-release ?' 7 | required: true 8 | type: string 9 | default: 'true' 10 | jobs: 11 | setup-xml-version: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | xml-server-version: ${{ steps.setup-xml-version.outputs.XML_SERVER_VERSION }} 15 | steps: 16 | - name: Check Out VS Code XML 17 | uses: actions/checkout@v4 18 | - id: setup-xml-version 19 | run: echo "XML_SERVER_VERSION=$(cat package.json | jq -r .xmlServer.version)" >> $GITHUB_OUTPUT 20 | build-binary-unix: 21 | runs-on: ${{ matrix.os }} 22 | needs: setup-xml-version 23 | env: 24 | GRAALVM_DISTRO: graalvm-community 25 | GRAALVM_JAVA: 17 26 | strategy: 27 | fail-fast: true 28 | matrix: 29 | label: [osx-x86_64, osx-aarch_64, linux] 30 | include: 31 | - label: osx-x86_64 32 | os: macos-13 33 | - label: osx-aarch_64 34 | os: macos-latest 35 | - label: linux 36 | os: ubuntu-22.04 37 | prop: -Dgraalvm.static=-H:+StaticExecutableWithDynamicLibC 38 | steps: 39 | - uses: actions/checkout@v4 40 | with: 41 | repository: 'eclipse/lemminx' 42 | ref: ${{ inputs.publishPreRelease == 'true' && 'main' || needs.setup-xml-version.outputs.xml-server-version }} 43 | - name: Cache Maven dependencies 44 | uses: actions/cache@v4 45 | with: 46 | path: | 47 | ~/.m2/repository 48 | ~/.m2/wrapper 49 | !~/.m2/repository/org/eclipse/lemminx 50 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 51 | restore-keys: | 52 | ${{ runner.os }}-maven- 53 | - name: Cache GraalVM 54 | uses: actions/cache@v4 55 | with: 56 | path: | 57 | /opt/hostedtoolcache/${{env.GRAALVM_DISTRO}}-jdk-* 58 | ~/hostedtoolcache/${{env.GRAALVM_DISTRO}}-jdk-* 59 | key: ${{ runner.os }}-${{env.GRAALVM_DISTRO}}-jdk-${{ env.GRAALVM_JAVA }} 60 | restore-keys: | 61 | ${{ runner.os }}-${{env.GRAALVM_DISTRO}}-jdk- 62 | - uses: graalvm/setup-graalvm@557ffcf459751b4d92319ee255bf3bec9b73964c #v1.2.5 63 | with: 64 | distribution: ${{env.GRAALVM_DISTRO}} 65 | java-version: ${{env.GRAALVM_JAVA}} 66 | - run: ./mvnw -B package -Dnative -DskipTests ${{ matrix.prop }} -Dcbi.jarsigner.skip=true 67 | - run: mv org.eclipse.lemminx/target/lemminx-* lemminx-${{ matrix.label }} 68 | - uses: actions/upload-artifact@v4 69 | with: 70 | name: lemminx-${{ matrix.label }} 71 | path: lemminx-${{ matrix.label }} 72 | if-no-files-found: error 73 | build-binary-windows: 74 | runs-on: windows-latest 75 | needs: setup-xml-version 76 | env: 77 | GRAALVM_DISTRO: graalvm-community 78 | GRAALVM_JAVA: 17 79 | steps: 80 | - name: Check out LemMinX 81 | uses: actions/checkout@v4 82 | with: 83 | repository: 'eclipse/lemminx' 84 | ref: ${{ inputs.publishPreRelease == 'true' && 'main' || needs.setup-xml-version.outputs.xml-server-version }} 85 | - name: Cache Maven dependencies 86 | uses: actions/cache@v4 87 | with: 88 | path: | 89 | ~/.m2/repository 90 | ~/.m2/wrapper 91 | !~/.m2/repository/org/eclipse/lemminx 92 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 93 | restore-keys: | 94 | ${{ runner.os }}-maven- 95 | - name: Cache GraalVM 96 | uses: actions/cache@v4 97 | with: 98 | path: | 99 | C:\hostedtoolcache\windows\${{env.GRAALVM_DISTRO}}-* 100 | key: ${{ runner.os }}-${{env.GRAALVM_DISTRO}}-jdk-${{ env.GRAALVM_JAVA }} 101 | restore-keys: | 102 | ${{ runner.os }}-${{env.GRAALVM_DISTRO}}-jdk- 103 | - uses: ilammy/msvc-dev-cmd@7315a94840631165970262a99c72cfb48a65d25d #v1.12.0 104 | - uses: graalvm/setup-graalvm@557ffcf459751b4d92319ee255bf3bec9b73964c #v1.2.5 105 | with: 106 | distribution: ${{env.GRAALVM_DISTRO}} 107 | java-version: ${{env.GRAALVM_JAVA}} 108 | - run: .\mvnw.cmd -B package -Dnative -DskipTests -D "cbi.jarsigner.skip=true" 109 | - run: mv org.eclipse.lemminx\target\lemminx-*.exe lemminx-win32.exe 110 | - uses: actions/upload-artifact@v4 111 | with: 112 | name: lemminx-win32 113 | path: lemminx-win32.exe 114 | if-no-files-found: error 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/out 2 | *.vsix 3 | server/** 4 | node_modules/ 5 | dist/ 6 | .gradle/ 7 | .idea/ 8 | .vscode-test/ 9 | .DS_Store -------------------------------------------------------------------------------- /.vscode-test.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 Red Hat, Inc. and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v2.0 5 | * which accompanies this distribution, and is available at 6 | * https://www.eclipse.org/legal/epl-v20.html 7 | * 8 | * Contributors: 9 | * Red Hat Inc. - initial API and implementation 10 | */ 11 | import { defineConfig } from '@vscode/test-cli'; 12 | 13 | export default defineConfig({ 14 | files: 'out/src/test/**/*.test.js', 15 | workspaceFolder: 'test-workspace' 16 | }); 17 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "EditorConfig.EditorConfig", 5 | "amodio.tsl-problem-matcher" 6 | ] 7 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": [ 11 | "--extensionDevelopmentPath=${workspaceRoot}" 12 | ], 13 | "sourceMaps": true, 14 | "outFiles": [ 15 | "${workspaceRoot}/dist/**/*.js" 16 | ], 17 | "preLaunchTask": "npm: watch", 18 | "env": { 19 | "VSCODE_REDHAT_TELEMETRY_DEBUG": "true", 20 | "LEMMINX_DEBUG": "1" 21 | } 22 | }, 23 | { 24 | "name": "Launch Extension & Wait for remote debugger", 25 | "type": "extensionHost", 26 | "request": "launch", 27 | "runtimeExecutable": "${execPath}", 28 | "args": [ 29 | "--extensionDevelopmentPath=${workspaceRoot}" 30 | ], 31 | "sourceMaps": true, 32 | "outFiles": [ 33 | "${workspaceRoot}/dist/**/*.js" 34 | ], 35 | "preLaunchTask": "npm: watch", 36 | "env": { 37 | "SUSPEND_SERVER": "true", 38 | "VSCODE_REDHAT_TELEMETRY_DEBUG": "true", 39 | "LEMMINX_DEBUG": "1" 40 | } 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "typescript.tsdk": "./node_modules/typescript/lib", 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": [ 10 | "$eslint-stylish", 11 | "$ts-webpack-watch" 12 | ], 13 | "isBackground": true, 14 | "presentation": { 15 | "reveal": "never" 16 | }, 17 | "group": { 18 | "kind": "build", 19 | "isDefault": true 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules 3 | src/ 4 | tsconfig.json 5 | .eslintrc.json 6 | .eslintignore 7 | webpack.config.js 8 | gulpfile.js 9 | .editorconfig 10 | CONTRIBUTING.md 11 | Jenkinsfile 12 | *.jenkins 13 | images/ 14 | !docs/images 15 | .tool-versions 16 | .github/ 17 | .gitignore 18 | test-workspace 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | Contributions are essential for keeping this extension great. We try to keep it as easy as possible to contribute changes and we are open to suggestions for making it even easier. There are only a few guidelines that we need contributors to follow. 4 | 5 | ## Development 6 | 7 | ### Installation Prerequisites: 8 | 9 | * latest [Visual Studio Code](https://code.visualstudio.com/) 10 | * [Node.js](https://nodejs.org/) v4.0.0 or higher 11 | * [JDK 11+](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 12 | * [Maven](https://maven.apache.org/) 13 | 14 | ### Steps 15 | 1. Fork and clone this repository 16 | 17 | 2. Fork and clone the [LemMinX - XML Language Server ](https://github.com/eclipse/lemminx) 18 | 19 | * **Note:** The directory format has to match the following: 20 | 21 | ``` 22 | YOUR_FOLDER/ 23 | ├──── lemminx/ 24 | │ 25 | ├──── vscode-xml/ 26 | ``` 27 | 28 | 3. `cd lemminx/` 29 | 30 | 4. Install the maven dependencies Mac/Linux: 31 | ```bash 32 | $ ./mvnw verify 33 | ``` 34 | or for Windows: 35 | ```bash 36 | $ mvnw.cmd verify 37 | ``` 38 | 39 | 40 | 5. `cd vscode-xml/` 41 | 42 | 6. Install the dependencies: 43 | ```bash 44 | $ npm install 45 | ``` 46 | 47 | 7. In `vscode-xml/`, build the server by running: 48 | 49 | ```bash 50 | $ npm run build-server 51 | ``` 52 | 53 | 8. To run the extension, open the Debugging tab in VSCode. 54 | 9. Select and run 'Launch Extension (vscode-xml)' at the top left: 55 | 56 | ![ Launch Extension ](./images/LaunchExtension.png) 57 | 58 | ### Debugging Language Server 59 | 60 | After completing the prerequisite steps above, and after launching the **Extension Development Host** for `vscode-xml`, you can also debug the language `server/lemminx` and can be used as follows: 61 | 62 | #### On VSCode 63 | 64 | 1. Ensure that the most recent changes of `lemminx` have been built before launching the **Extension Development Host** (as per Step 7 in [Steps](#Steps)), and that the **Extension Development Host** is running. 65 | 66 | 2. Open `lemminx` in VSCode. This should display the "Debug (Attach) - Remote" option in the "Debugging" tab. 67 | 68 | 3. To run the debugger, open the "Debugging" tab in VSCode. 69 | 70 | 4. Select and run "Debug (Attach) - Remote" at the top left: 71 | 72 | ![Debug Attach Remote](./images/DebugAttachRemote.png) 73 | 74 | This will make the `lemminx` debugger attach to the **Extension Development Host** instance. 75 | 76 | To confirm that the debugger has properly attached, the "Call Stack" dropdown in the "Debugging" tab should be populated as follows: 77 | 78 | ![Debug Menu Call Stack](./images/DebugMenuCallStack.png) 79 | 80 | Now that the `lemminx` debugger is properly attached, any language server interactions can be debugged and breakpoints in `lemminx` will be tracked. 81 | 82 | ## Binary server development 83 | 84 | ### Testing a binary version of LemMinX 85 | 86 | 1. Copy the binary version of LemMinX to: 87 | 88 | | OS | Location (relative to root of repository) | 89 | | --- | --- | 90 | | Linux | `./server/lemminx-linux` | 91 | | macOS | `./server/lemminx-darwin-x86_64` | 92 | | Windows | `.\server\lemminx-win32.exe` | 93 | 94 | Alternatively, you can set the `xml.server.binary.path` preference to specify the path of the binary to run. 95 | 96 | 2. Make sure that you set `xml.server.preferBinary` to `true`, 97 | disable any [LemMinX extensions](./docs/Extensions.md) 98 | by commenting out `xml.extension.jars` in your `settings.json`, 99 | and uninstall or disable any VS Code extensions that provide extra LemMinX features. 100 | 101 | 3. Launch vscode-xml in development mode, and double check that the binary server is running by checking the server logging (Output > XML Support) 102 | 103 | ### Downloading the GitHub Actions binary for your PR 104 | 105 | 1. Open the GitHub page for your PR. 106 | 107 | 2. Click on "Checks": 108 | 109 | ![](./images/DownloadBinaryChecks.png) 110 | 111 | 3. Click "Artifacts", then select the binary for your operating system: 112 | 113 | ![](./images/DownloadBinaryArtifacts.png) 114 | 115 | ### Building a binary with GraalVM locally 116 | 117 | If you submit a LemMinX PR, GitHub Actions will generate a binary for your PR that you can use for testing. 118 | If you need to generate a LemMinX binary locally for whatever reason, follow these steps: 119 | 120 | 1. Download and set up [GraalVM and its dependencies](https://www.graalvm.org/docs/getting-started/) 121 | * The latest version should work 122 | 2. Make sure that the environment variable `JAVA_HOME` points to the GraalVM installation. 123 | 3. Run `./mvnw clean package -DskipTests -Dnative` from the root of the LemMinX repository 124 | * This will use a lot of memory (> 4 GB) and take a while 125 | 4. The binary is generated in `./org.eclipse.lemminx/target` 126 | 127 | ### Certificate of Origin 128 | 129 | By contributing to this project you agree to the Developer Certificate of 130 | Origin (DCO). This document was created by the Linux Kernel community and is a 131 | simple statement that you, as a contributor, have the legal right to make the 132 | contribution. See the [DCO](DCO) file for details. 133 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | def installBuildRequirements(){ 4 | def nodeHome = tool 'nodejs-14.19.1' 5 | env.PATH="${env.PATH}:${nodeHome}/bin" 6 | sh "npm install -g typescript" 7 | sh 'npm install -g --force "@vscode/vsce"' 8 | } 9 | 10 | def buildVscodeExtension(){ 11 | sh "npm install" 12 | sh "npm run vscode:prepublish" 13 | } 14 | 15 | def buildLemMinXBinary() { 16 | sh "curl -Lo NativeImage.jenkins https://raw.githubusercontent.com/${params.FORK}/vscode-xml/${params.BRANCH}/NativeImage.jenkins" 17 | load "NativeImage.jenkins" 18 | } 19 | 20 | node('rhel8'){ 21 | sh "curl -Lo package.json https://raw.githubusercontent.com/${params.FORK}/vscode-xml/${params.BRANCH}/package.json" 22 | def packageJson = readJSON file: 'package.json' 23 | def serverVersion = packageJson?.xmlServer?.version 24 | def files = [] 25 | if (serverVersion && publishToMarketPlace.equals('true')) { 26 | stage 'Download XML LS' 27 | def serverUrl = "https://repo.eclipse.org/content/repositories/lemminx-releases/org/eclipse/lemminx/org.eclipse.lemminx/${serverVersion}/org.eclipse.lemminx-${serverVersion}-uber.jar" 28 | sh "curl -Lo org.eclipse.lemminx-${serverVersion}-uber.jar ${serverUrl}" 29 | files = findFiles(glob: 'org.eclipse.lemminx*-uber.jar') 30 | } 31 | 32 | buildLemMinXBinary() 33 | 34 | if (!files[0]) { 35 | stage 'Build XML LS' 36 | git url: 'https://github.com/eclipse/lemminx.git', branch: 'main' 37 | sh "./mvnw clean verify -B -U -e -P!jboss-maven-repos,!redhat-ga-repository,!redhat-ea-repository" 38 | sh "mv org.eclipse.lemminx/target/org.eclipse.lemminx*-uber.jar ." 39 | files = findFiles(glob: 'org.eclipse.lemminx*-uber.jar') 40 | } 41 | stash name: 'server_distro', includes :files[0].path 42 | } 43 | 44 | node('rhel8'){ 45 | stage 'Checkout vscode-xml code' 46 | deleteDir() 47 | def gitUrl = "${GIT_REPO}" 48 | 49 | git url: gitUrl?:'https://github.com/redhat-developer/vscode-xml.git', branch: params.BRANCH?: 'main' 50 | 51 | stage 'set the link to download the binary server' 52 | def packageJson = readJSON file: 'package.json' 53 | def binaryUploadFolder = 'latest' 54 | def downloadLocation = 'https://github.com/redhat-developer/vscode-xml' 55 | if (publishToMarketPlace.equals('true')) { 56 | sh "sed -i -e 's|${downloadLocation}/releases/download/latest|${downloadLocation}/releases/download/${packageJson.version}|g' package.json" 57 | } 58 | 59 | stage 'install vscode-xml build requirements' 60 | installBuildRequirements() 61 | 62 | stage 'Build vscode-xml' 63 | buildVscodeExtension() 64 | unstash 'server_distro' 65 | def files = findFiles(glob: '**/org.eclipse.lemminx*-uber.jar') 66 | sh "mkdir ./server" 67 | sh "mv ${files[0].path} ./server" 68 | 69 | env.publishPreReleaseFlag = "" 70 | if(publishPreRelease.equals('true')){ 71 | stage "Prepare for pre-release" 72 | sh "npx gulp prepare_pre_release" 73 | packageJson = readJSON file: 'package.json' 74 | env.publishPreReleaseFlag = "--pre-release" 75 | } 76 | 77 | stage "Package vscode-xml" 78 | sh "mkdir ../staging" 79 | unstash 'binaries' 80 | unstash 'checksums' 81 | sh "mv lemminx-* ../staging" 82 | def platformToTarget = [ "linux-x64" : "linux", "win32-x64" : "win32", "darwin-x64" : "osx-x86_64", "darwin-arm64" : "osx-x86_64"] 83 | for(entry in platformToTarget){ 84 | def target = entry.key 85 | def platform = entry.value 86 | sh "unzip -d ./server ../staging/lemminx-${platform}.zip" 87 | sh "cp ../staging/lemminx-${platform}.sha256 ./server" 88 | sh "vsce package ${env.publishPreReleaseFlag} --target ${target} -o vscode-xml-${target}-${packageJson.version}-${env.BUILD_NUMBER}.vsix" 89 | sh "rm ./server/lemminx-*" 90 | } 91 | // This vsix only gets published to OpenVSX (if option is set) 92 | // server folder still needed to publish generic vsix below 93 | sh "cp ../staging/lemminx-*.sha256 ./server" 94 | sh "vsce package -o vscode-xml-${packageJson.version}-${env.BUILD_NUMBER}.vsix" 95 | 96 | //stage 'Test vscode-xml for staging' 97 | //wrap([$class: 'Xvnc']) { 98 | // sh "npm test --silent" 99 | //} 100 | 101 | stage 'Archive artifacts' 102 | archiveArtifacts artifacts: '*.vsix' 103 | stash name:'vsix', includes:'*.vsix' 104 | } 105 | 106 | node('rhel8'){ 107 | sh 'npm install -g --force "@vscode/vsce"' 108 | sh 'npm install -g "ovsx"' 109 | if(publishToMarketPlace.equals('true') || publishToOVSX.equals('true') || publishPreRelease.equals('true')){ 110 | 111 | if (publishToMarketPlace.equals('true') || publishToOVSX.equals('true')) { 112 | timeout(time:2, unit:'DAYS') { 113 | input message:'Approve deployment?', submitter: 'fbricon,rgrunber,azerr,davthomp' 114 | } 115 | } 116 | 117 | stage "Publish to Marketplaces" 118 | unstash 'vsix' 119 | def vsix = findFiles(glob: '**.vsix') 120 | def platformVsixes = findFiles(glob: '**.vsix', excludes: vsix[0].path) 121 | 122 | // VS Code Marketplace 123 | if (publishToMarketPlace.equals('true') || publishPreRelease.equals('true')) { 124 | withCredentials([[$class: 'StringBinding', credentialsId: 'vscode_java_marketplace', variable: 'TOKEN']]) { 125 | for(platformVsix in platformVsixes){ 126 | sh 'vsce publish -p ${TOKEN}' + " --packagePath ${platformVsix.path}" 127 | } 128 | // Cannot combine packagePath & target, so re-generate (generic) package and publish 129 | sh 'vsce publish -p ${TOKEN}' + " ${env.publishPreReleaseFlag}" 130 | } 131 | } 132 | 133 | // Open-VSX Marketplace 134 | if (publishToOVSX.equals('true') || publishPreRelease.equals('true')) { 135 | withCredentials([[$class: 'StringBinding', credentialsId: 'open-vsx-access-token', variable: 'OVSX_TOKEN']]) { 136 | for(platformVsix in platformVsixes){ 137 | sh 'ovsx publish -p ${OVSX_TOKEN}' + " --packagePath ${platformVsix.path}" 138 | } 139 | 140 | sh 'ovsx publish -p ${OVSX_TOKEN}' + " ${env.publishPreReleaseFlag}" 141 | } 142 | } 143 | 144 | }// if any publishing 145 | } 146 | -------------------------------------------------------------------------------- /NativeImage.jenkins: -------------------------------------------------------------------------------- 1 | // Parameters that need to be declared for this pipeline: 2 | // * GRAALVM_VERSION: The version of GraalVM to download in the Windows an macOS builds 3 | // * publishToMarketPlace: Upload to the "stable" folder if true, upload to the "snapshots" folder if false 4 | // * UPLOAD_LOCATION: The base location where the artifacts (binaries and sha256 hashes) will be uploaded 5 | // * FORK: The fork of vscode-xml that is being built for 6 | // * BRANCH: The branch of vscode-xml that is being built for 7 | pipeline { 8 | agent none 9 | stages { 10 | stage("native-image") { 11 | parallel { 12 | // Assumes GraalVM is set up on the rhel8 agent, and the environment variable "GRAALVM_PATH" points to its location 13 | stage("Linux native-image") { 14 | agent { 15 | label "rhel8" 16 | } 17 | steps { 18 | sh "rm -f lemminx-linux" 19 | sh "rm -rf lemminx" 20 | script { 21 | if (publishToMarketPlace.equals('true')) { 22 | sh "curl -Lo package.json https://raw.githubusercontent.com/${params.FORK}/vscode-xml/${params.BRANCH}/package.json" 23 | def packageJson = readJSON file: 'package.json' 24 | def lemminxVersion = packageJson?.xmlServer?.version 25 | sh "git clone -b ${lemminxVersion} https://github.com/eclipse/lemminx.git" 26 | } else { 27 | sh "git clone https://github.com/eclipse/lemminx.git" 28 | } 29 | } 30 | sh "cd lemminx && JAVA_HOME=\$GRAALVM_PATH ./mvnw clean package -B -Dnative -DskipTests -Dgraalvm.static='-H:+StaticExecutableWithDynamicLibC' && cd .." 31 | sh "rm lemminx/org.eclipse.lemminx/target/*.build_artifacts.txt" 32 | sh "cp lemminx/org.eclipse.lemminx/target/lemminx-linux* lemminx-linux" 33 | stash name: 'lemminx-linux', includes: 'lemminx-linux' 34 | } 35 | } 36 | stage("Windows native-image") { 37 | agent { 38 | label "win10" 39 | } 40 | steps { 41 | powershell """ 42 | if (Test-Path lemminx-win32.exe) { Remove-Item lemminx-win32.exe } 43 | Remove-Item -Recurse -Force lemminx 44 | """ 45 | script { 46 | if (publishToMarketPlace.equals('true')) { 47 | powershell """ 48 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 49 | Invoke-WebRequest https://raw.githubusercontent.com/${params.FORK}/vscode-xml/${params.BRANCH}/package.json -OutFile package.json 50 | """ 51 | def packageJson = readJSON file: 'package.json' 52 | def lemminxVersion = packageJson?.xmlServer?.version 53 | powershell """ 54 | git clone -b ${lemminxVersion} git@github.com:eclipse/lemminx.git 55 | """ 56 | } else { 57 | powershell """ 58 | git clone git@github.com:eclipse/lemminx.git 59 | """ 60 | } 61 | } 62 | powershell """ 63 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 64 | if (-not (Test-Path graalvm-windows-${params.GRAALVM_VERSION}.zip)) { 65 | Invoke-WebRequest https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${params.GRAALVM_VERSION}/graalvm-ce-java17-windows-amd64-${params.GRAALVM_VERSION}.zip -OutFile graalvm-windows-${params.GRAALVM_VERSION}.zip 66 | Expand-Archive graalvm-windows-${params.GRAALVM_VERSION}.zip 67 | .\\graalvm-windows-${params.GRAALVM_VERSION}\\graalvm-ce-java17-${params.GRAALVM_VERSION}\\bin\\gu install native-image 68 | } 69 | """ 70 | bat """ 71 | pushd . 72 | setlocal 73 | set JAVA_HOME=%cd%\\graalvm-windows-${params.GRAALVM_VERSION}\\graalvm-ce-java17-${params.GRAALVM_VERSION} 74 | call \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat\" 75 | popd 76 | cd lemminx 77 | .\\mvnw.cmd clean package -B -Dnative -DskipTests 78 | endlocal 79 | cd .. 80 | """ 81 | powershell "mv lemminx\\org.eclipse.lemminx\\target\\lemminx-windows*.exe lemminx-win32.exe" 82 | stash name: 'lemminx-win32.exe', includes: 'lemminx-win32.exe' 83 | } 84 | } 85 | stage("macOS native-image") { 86 | agent { 87 | label "mac" 88 | } 89 | steps { 90 | sh "rm -f lemminx-osx-x86_64.zip lemminx-osx-x86_64.sha256" 91 | sh "rm -rf lemminx" 92 | script { 93 | if (publishToMarketPlace.equals('true')) { 94 | sh "curl -Lo package.json https://raw.githubusercontent.com/${params.FORK}/vscode-xml/${params.BRANCH}/package.json" 95 | def packageJson = readJSON file: 'package.json' 96 | def lemminxVersion = packageJson?.xmlServer?.version 97 | sh "git clone -b ${lemminxVersion} https://github.com/eclipse/lemminx.git" 98 | } else { 99 | sh "git clone https://github.com/eclipse/lemminx.git" 100 | } 101 | } 102 | sh """ 103 | if [ ! -f graalvm-darwin-${params.GRAALVM_VERSION}.tar.gz ]; then 104 | curl https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${params.GRAALVM_VERSION}/graalvm-ce-java17-darwin-amd64-${params.GRAALVM_VERSION}.tar.gz -L --output graalvm-darwin-${params.GRAALVM_VERSION}.tar.gz 105 | tar -xzf graalvm-darwin-${params.GRAALVM_VERSION}.tar.gz 106 | ./graalvm-ce-java17-${params.GRAALVM_VERSION}/Contents/Home/bin/gu install native-image 107 | fi 108 | """ 109 | sh "cd lemminx && JAVA_HOME=`pwd`/../graalvm-ce-java17-${params.GRAALVM_VERSION}/Contents/Home ./mvnw clean package -B -Dnative -DskipTests && cd .." 110 | sh "rm lemminx/org.eclipse.lemminx/target/*.build_artifacts.txt" 111 | sh "cp lemminx/org.eclipse.lemminx/target/lemminx-osx-x86_64* lemminx-osx-x86_64" 112 | 113 | stash name: 'lemminx-osx-x86_64', includes: 'lemminx-osx-x86_64' 114 | } 115 | } 116 | } 117 | } 118 | stage ("Zip and upload") { 119 | agent { 120 | label "rhel8" 121 | } 122 | steps { 123 | unstash name: 'lemminx-linux' 124 | unstash name: 'lemminx-win32.exe' 125 | unstash name: 'lemminx-osx-x86_64' 126 | 127 | sh "zip lemminx-linux.zip lemminx-linux" 128 | sh "zip lemminx-win32.zip lemminx-win32.exe" 129 | sh "zip lemminx-osx-x86_64.zip lemminx-osx-x86_64" 130 | 131 | // get the sha256 hash of the binaries 132 | sh "sha256sum lemminx-linux > lemminx-linux.sha256" 133 | sh "sha256sum lemminx-win32.exe > lemminx-win32.sha256" 134 | sh "sha256sum lemminx-osx-x86_64 > lemminx-osx-x86_64.sha256" 135 | stash name: 'checksums', includes: 'lemminx-*.sha256' 136 | stash name: 'binaries', includes: 'lemminx-*.zip' 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /USAGE_DATA.md: -------------------------------------------------------------------------------- 1 | # Data collection 2 | 3 | vscode-xml has opt-in telemetry collection, provided by [vscode-redhat-telemetry](https://github.com/redhat-developer/vscode-redhat-telemetry). 4 | 5 | ## What's included in the vscode-xml telemetry data 6 | 7 | * JVM information: 8 | * Whether LemMinX is being run with Java or as a GraalVM native image (binary) 9 | * The name of the vm (`java.vm.name`) 10 | * The name of the runtime (`java.runtime.name`) 11 | * The version of the JVM (`java.version`) 12 | * The free, total, and max VM memory 13 | * LemMinX Version information: 14 | * The server version number 15 | * Does NOT include the `JAVA_HOME` environment variable for privacy reasons 16 | * The value of the `xml.server.preferBinary` setting 17 | * A telemetry event is sent every time the binary server download succeeds, fails, or is stopped by the user 18 | * If the download fails, the associated error is attached to the telemetry event 19 | * A telemetry event is sent every time you click the "Open Proxy Configuration Documentation" link that is provided when the language server binary download fails due to a proxy related issue. 20 | * A telemetry event is sent every time you click the "Download Java" link that appears when you have [LemMinX extensions](./docs/Extensions.md) installed but don't have Java installed. 21 | * A telemetry event is sent every time the Java XML language server crashes due to an Out Of Memory Error, which also contains the maximum heap space for the JVM (-Xmx) that you've set. 22 | * A telemetry event is sent every time you click on the link to the documentation that appears after the Java XML language server crashes due to an Out Of Memory Error. 23 | * Text Document Information 24 | * When a document is opened : 25 | * The file extension (eg. `xml`, `xsd`, `dtd`, `rng`) 26 | * The associated grammar types (eg. `none`, `doctype`, `xml-model`, `xsi:schemaLocation`, `xsi:noNamespaceSchemaLocation`) 27 | * The grammar identifiers for an XML document (eg. `http://maven.apache.org/xsd/maven-4.0.0.xsd`) 28 | * The resolver used to resolve the grammar identifier (eg. `catalog`, `file association`, `embedded catalog.xsd`, `embedded xml.xsd`, `embedded xslt.xsd`, `relaxng.rng`) 29 | 30 | ## What's included in the general telemetry data 31 | 32 | Please see the 33 | [vscode-redhat-telemetry data collection information](https://github.com/redhat-developer/vscode-redhat-telemetry/blob/HEAD/USAGE_DATA.md#usage-data-being-collected-by-red-hat-extensions) 34 | for information on what data it collects. 35 | 36 | ## How to opt in or out 37 | 38 | Use the `redhat.telemetry.enabled` setting in order to enable or disable telemetry collection. 39 | Note that this extension abides by Visual Studio Code's telemetry level: if `telemetry.telemetryLevel` is set to off, then no telemetry events will be sent to Red Hat, even if `redhat.telemetry.enabled` is set to true. If `telemetry.telemetryLevel` is set to `error` or `crash`, only events containing an error or errors property will be sent to Red Hat. 40 | -------------------------------------------------------------------------------- /docs/BindingWithGrammar.md: -------------------------------------------------------------------------------- 1 | # Binding with Grammar 2 | 3 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides support for automatic XML schema/grammar binding through generation and/or using an existing `.xsd/.dtd` file. 4 | 5 | ![Binding Wizard Demo](./images/BindingWithGrammar/BindingWizardDemo.gif) 6 | 7 | [Validation with XSD grammar](Validation.md#validation-with-xsd-grammar) and [Validation with DTD grammar](Validation.md#validation-with-dtd-grammar) provide more information on manual binding of an XML document. 8 | 9 | In the following sections, we would like to bind the XML document `foo.xml`: 10 | ```xml 11 | 12 | 13 | 14 | ``` 15 | with an associated grammar file. 16 | 17 | ## Binding with Existing Grammar 18 | 19 | Consider an XSD document, `foo.xsd` (in the same directory as `foo.xml`), defined as follows : 20 | ```xsd 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | and a DTD document, `foo.dtd` (in the same directory as `foo.xml`), defined as follows: 33 | ```dtd 34 | 35 | 36 | ``` 37 | 38 | Either file can be bound using the [XML Binding Wizard](#the-xml-binding-wizard), which can be triggered by [Command](#command), [CodeLens](#codelens) or [Quick Fix](#quick-fix). 39 | 40 | ### The XML Binding Wizard 41 | 42 | After opening the binding wizard using one of the methods mentioned above, a dropdown with the following 2 options will appear at the Command Palette: 43 | 44 | ![Binding Wizard Dropdown](./images/BindingWithGrammar/BindingWizardDropdown.png) 45 | 46 | 1. Standard (xsi, DOCTYPE) 47 | 48 | If the selected file is an XSD file, this option will bind the grammar file by adding the `xmlns:xsi` (with the value as "http://www.w3.org/2001/XMLSchema-instance") and `xsi:noNamespaceSchemaLocation` (with the value as the path to the grammar file) attributes to the root tag: 49 | ```xml 50 | 52 | 53 | 54 | ``` 55 | 56 | If the XSD file contains a `targetNamespace` attribute, with an `elementFormDefault` attribute with value "qualified" in the `xs:schema` tag, as follows: 57 | ```xsd 58 | 59 | ``` 60 | then the XML document will have the `targetNamespace` set as a `xmlns` attribute and an additional attribute for `xsi:schemaLocation`: 61 | ```xml 62 | 65 | 66 | 67 | ``` 68 | 69 | If the selected file is a DTD file, this option will bind the grammar file by adding a ` SYSTEM "">` tag at the beginning of the document: 70 | ```xml 71 | 72 | 73 | 74 | 75 | ``` 76 | 77 | 2. XML Model association 78 | 79 | This option will bind the grammar file by adding the `xml-model` tag at the beginning of the document, with an `href` value as the path to the grammar file: 80 | ```xml 81 | 82 | 83 | 84 | 85 | ``` 86 | The same applies when selecting `foo.dtd`. 87 | 88 | After selecting an option, you can select the desired grammar file using your file explorer: 89 | 90 | ![Binding Wizard File Explorer](./images/BindingWithGrammar/BindingWizardFileExplorer.png) 91 | 92 | ### Command 93 | 94 | The command "XML: Bind to grammar/schema file" can be executed from the VSCode command palette, as well as be bound to a shortcut. 95 | 96 | ![Bind To Grammar Command](./images/BindingWithGrammar/BindToGrammarCommand.png) 97 | 98 | If the current XML document is not bound using an existing grammar/schema, the command will have the user select a existing `.xsd/.dtd` grammar file to bind to the XML document. 99 | 100 | Otherwise, an error will be thrown on the client if the XML document already has a bound grammar/schema. 101 | 102 | ### CodeLens 103 | 104 | When [CodeLenses](./Preferences.md#code-lens) are enabled, an unbound XML document will display a CodeLens above the root element as follows: 105 | 106 | ![Bind To Grammar Command](./images/BindingWithGrammar/BindToGrammarCodeLens.png) 107 | 108 | ### Quick Fix 109 | 110 | For any unbound XML document, a Quick Fix suggestion will appear beside the root element. 111 | 112 | ![Bind To Grammar CodeAction](./images/BindingWithGrammar/BindToGrammarCodeAction.png) 113 | 114 | With the cursor on the first opening tag, use `Ctrl + .`, `Quick Fix...` or the lightbulb that appears and select the "Bind to existing grammar/schema" 115 | 116 | ![Bind To Grammar CodeAction Dropdown](./images/BindingWithGrammar/BindToGrammarCodeActionDropdown.png) 117 | 118 | ## Binding with New Grammar 119 | 120 | Consider the case where the directory only contains `foo.xml` (i.e. there does not exist an appropriate `.xsd/.dtd` file to bind). 121 | 122 | A file can be generated using a [Quick Fix](#quick-fix-1). 123 | 124 | ### Quick Fix 125 | 126 | #### Generate XSD from XML 127 | 128 | When an unbound XML file is open, an XML Schema/XSD file can be generated from the opening tag in the XML file. 129 | 130 | With the cursor on the first opening tag, use `Ctrl + .` or `Quick Fix...` or the lightbulb that appears and select "Generate foo.xsd and bind with *" to create the file in the the same directory. 131 | 132 | ![GenerateXSDFromXML](./images/BindingWithGrammar/GenerateXSDFromXML.gif) 133 | 134 | #### Generate DTD from XML 135 | 136 | When an unbound XML file is open, a Document Type Definition/DTD file can be generated from the opening tag in the XML file. 137 | 138 | With the cursor on the first opening tag, use `Ctrl + .` or `Quick Fix...` or the lightbulb that appears and select "Generate foo.dtd and bind with *" to create the file in the the same directory. 139 | 140 | ![GenerateDTDFromXML](./images/BindingWithGrammar/GenerateDTDFromXML.gif) 141 | 142 | #### Generate RELAX NG from XML 143 | 144 | When an unbound XML file is open, a RELAX NG schema can be generated from the opening tag in the XML file. 145 | 146 | With the cursor on the first opening tag, use `Ctrl + .` or `Quick Fix...` or the lightbulb that appears and select "Generate foo.rng and bind with RelaxNG" to create the file in the the same directory. 147 | 148 | ![GenerateRelaxNGFromXML](./images/BindingWithGrammar/GenerateRelaxNGFromXML.gif) 149 | -------------------------------------------------------------------------------- /docs/CodeLens.md: -------------------------------------------------------------------------------- 1 | 2 | ## Code Lens 3 | 4 | ### XML Features 5 | 6 | CodeLens provides grammar binding for unbound XML documents, appearing above the root element, which will trigger the [XML Binding Wizard](BindingWithGrammar.md#the-xml-binding-wizard). 7 | 8 | ![CodeLens Bind](./images/Features/CodeLensBind.png) 9 | 10 | ### DTD features 11 | 12 | Code lens is provided in `.dtd` files to show where elements defined in the DTD are referenced. 13 | For instance, in the following code: 14 | 15 | ```xml 16 | 17 | 18 | 19 | 20 | 21 | ``` 22 | 23 | There will be a code lens entry after the first line that points from the 24 | definition of the element `to` to where it is used in the definition of the 25 | element `letter`. 26 | 27 | Here is a demonstration of the above Code Lens: 28 | 29 | ![A letter DTD element is declared, which consists of to, from title, and body elements. The definitions for these sub elements have a code lens above, which allows ofr navigating to the letter element declaration.](./images/CodeLens/DTDElementCodeLens.gif) 30 | 31 | ### XSD Features 32 | 33 | Code lens is also provided in `.xsd` files. It shows where top level types 34 | and elements are referenced. For instance, in the following code: 35 | 36 | ```xml 37 | 38 | 42 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ``` 52 | 53 | There will be a code lens above the line where the `yell` type is defined 54 | that points to where it is referenced when defining the `root-element` element. 55 | 56 | Here is a demonstration of the above Code Lens: 57 | 58 | ![The code lens provides the number of references and links to references for an `xs:simpleType`.](./images/CodeLens/XSDTypeCodeLens.gif) 59 | 60 | Here is a demonstration of the code lens for `xs:element`: 61 | 62 | ![An element root is declared that contains an element boot. Above the declaration of boot, there is a code lens that links to the reference in root.](./images/CodeLens/XSDElementCodeLens.gif) 63 | -------------------------------------------------------------------------------- /docs/Commands.md: -------------------------------------------------------------------------------- 1 | # Commands 2 | 3 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides several vscode commands which are available with `Ctrl+Shift+P`. 4 | 5 | ![XML Commands](images/Commands/XMLCommands.png) 6 | 7 | ## Bind to grammar/schema file 8 | 9 | This command triggers the [XML Binding Wizard](BindingWithGrammar.md#the-xml-binding-wizard) for the current file. 10 | 11 | Details on the command are described [here](BindingWithGrammar.md#command). 12 | 13 | ## Open XML Documentation 14 | 15 | This command opens the `XML Documentation`. 16 | 17 | ## Revalidate current XML file 18 | 19 | This command re-triggers the [XML Validation](Validation.md#xml-validation) for the current file. 20 | 21 | When the [Server Cache Path](Preferences.md#server-cache-path) is activated, the command removes the referenced XSD, DTD grammar from the local cache. 22 | 23 | ## Revalidate all open XML files 24 | 25 | This command re-triggers the [XML Validation](Validation.md#xml-validation) for the all opened XML files. 26 | 27 | When the [Server Cache Path](Preferences.md#server-cache-path) is activated, the command clears the remote grammar cache and revalidates all opened files. 28 | 29 | ## Restart XML Language Server 30 | 31 | This command restarts the XML language server. 32 | -------------------------------------------------------------------------------- /docs/Features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) has a number of notable features available for XML, XSD and DTD support. 4 | 5 | - [XML features](Features/XMLFeatures.md#xml-features) 6 | - [XSD features](Features/XSDFeatures.md#xsd-features) 7 | - [DTD features](Features/DTDFeatures.md#dtd-features) 8 | - [RelaxNG features](Features/RelaxNGFeatures.md#relaxng-features) 9 | - [XInclude features](Features/XIncludeFeatures.md#xinclude-features) 10 | - [XML Catalog features](Features/XMLCatalogFeatures.md#xml-catalog-features) 11 | - [XML References features](Features/XMLReferencesFeatures.md#xml-references-features) 12 | - [XML Colors features](Features/XMLColorsFeatures.md#xml-colors-features) -------------------------------------------------------------------------------- /docs/Features/DTDFeatures.md: -------------------------------------------------------------------------------- 1 | # DTD Features 2 | 3 | ## CodeLens Support 4 | 5 | CodeLens is supported for `.dtd` files, which can show where an element declaration is referenced. 6 | 7 | ![CodeLens DTD](../images/Features/CodeLensDTD.gif) 8 | 9 | This feature also supports listing and highlighting the number of references to an element declaration and the line(s) referenced on. 10 | 11 | ![CodeLens References DTD ](../images/Features/CodeLensReferencesDTD.gif) 12 | 13 | ### Read more 14 | 15 | See [CodeLens](../CodeLens.md#code-lens) for more details. 16 | 17 | ## Category Accessibility 18 | 19 | After defining an `!ELEMENT` tag in the `.dtd` file, there are features available for categories. 20 | 21 | ### Jump to element declaration 22 | 23 | For an `!ELEMENT` tag that contains a category/element-content attribute, there is support for navigating to its definition element. 24 | 25 | ![Jump To Element Declaration DTD](../images/Features/JumpToElementDeclarationDTD.gif) 26 | 27 | ## Syntax Validation 28 | 29 | DTD syntax validation is enabled for any `.dtd` file. 30 | 31 | ![Validation DTD](../images/Features/ValidationDTD.gif) 32 | -------------------------------------------------------------------------------- /docs/Features/RelaxNGFeatures.md: -------------------------------------------------------------------------------- 1 | # RelaxNG features 2 | 3 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides validation, completion, hover in XML file based on [RelaxNG schemas](https://relaxng.org/) since `0.22.0`: 4 | 5 | ![RelaxNG support](../images/RelaxNG/RelaxNGSupport.gif) 6 | 7 | It supports both: 8 | 9 | * [RelaxNG XML syntax (*.rng files)](https://relaxng.org/tutorial-20011203.html). 10 | * [RelaxNG Compact syntax (*.rnc files)](https://relaxng.org/compact-tutorial-20030326.html). 11 | 12 | ![XML Validated with RelaxNG](../images/RelaxNG/XMLValidatedWithRelaxNG.png) 13 | 14 | You can associate your XML file with `RelaxNG grammar` (`file` or `URL`) using : 15 | 16 | * an `xml-model` processing instruction 17 | 18 | ```xml 19 | 20 | 21 | ... 22 | 23 | ``` 24 | 25 | * an `XML catalog` using the same method as [XSD](Validation.md#XML-catalog-with-XSD) 26 | * a `file association` using the same method as [XSD](Validation.md#XML-file-association-with-xsd) 27 | 28 | ## RelaxNG grammar 29 | 30 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides support for `RelaxNG grammars`: 31 | 32 | * for [RelaxNG XML syntax (*.rng files)](https://relaxng.org/tutorial-20011203.html), it provides the same support as XSD/DTD grammars (completion, hover, validation, etc). 33 | 34 | ![RelaxNG grammar XML Syntax Overview](../images/RelaxNG/RelaxNGXMLSyntaxOverview.png) 35 | 36 | * for [RelaxNG Compact syntax (*.rnc files)](https://relaxng.org/compact-tutorial-20030326.html) it provides only syntax coloration. 37 | 38 | ![RelaxNG Compact Syntax Overview](../images/RelaxNG/RelaxNGCompactSyntaxOverview.png) 39 | 40 | ### RelaxNG grammar XML Syntax 41 | 42 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides support for reference between `define/@name` and `ref/@name` with codelens, definition, completion, highlighting, references, rename: 43 | 44 | ![RelaxNG XML Syntax Define support](../images/RelaxNG/RNGDefineSupport.gif) 45 | 46 | It also provides support for `include/@href` and `externalRef/@href` attributes to navigate easily to the referenced `rng` grammar file: 47 | 48 | ![RelaxNG XML Syntax Href support](../images/RelaxNG/RNGHrefSupport.gif) 49 | 50 | # Validation 51 | 52 | XML validation based on RelaxNG (rng, rnc) is supported: 53 | 54 | ![RelaxNG Validation](../images/RelaxNG/RelaxNGValidation.png) 55 | 56 | # Completion 57 | 58 | XML completion based on RelaxNG (rng, rnc) is supported. The completion for rng can show the documentation: 59 | 60 | ![RelaxNG Completion And Documentation](../images/RelaxNG/RelaxNGCompletionAndDocumentation.png) 61 | 62 | # Hover 63 | 64 | Hover based on RelaxNG rng can show the documentation: 65 | 66 | ![RelaxNG Hover And Documentation](../images/RelaxNG/RelaxNGHoverAndDocumentation.png) 67 | 68 | # Go to Type Definition 69 | 70 | From the XML document you can go to the type definition to navigate to the element/attribute declaration for both `rnc` and `rng`. 71 | 72 | To do this, select an XML element/attribute and use the contextual menu `Go to Type Definition`: 73 | 74 | ![Go to Type Definition Menu](../images/RelaxNG/GoToTypeDefinitionMenu.png) 75 | 76 | When you click on this menu item, VS Code will open the `rng` or `rnc` grammar file and place the cursor on the proper `element/attribute` declaration: 77 | 78 | ![Go to Type Definition result](../images/RelaxNG/GoToTypeDefinitionResult.png) 79 | 80 | # How to start? 81 | 82 | ## Using snippets 83 | 84 | You can use snippets to quickly create: 85 | 86 | * an XML file associated with a RelaxNG grammar 87 | * a RelaxNG XML file 88 | 89 | Here's a demo: 90 | 91 | ![RelaxNG snippets support](../images/RelaxNG/RelaxNGSnippetsSupport.gif) 92 | 93 | ## Creating XML, rng, rnc files 94 | 95 | You can create a RelaxNG grammar that uses the XML syntax by making a file with the extension `.rng`. 96 | For instance, here is a file `addressBook.rng` that defines a RelaxNG grammar: 97 | 98 | ```xml 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | ``` 120 | 121 | You can create a RelaxNG grammar that uses the [compact syntax](https://relaxng.org/compact-tutorial-20030326.html) by making a file with the extension `.rnc`. 122 | For instance, here is a file `addressBook.rnc` that defines the same RelaxNG grammar as `addressBook.rng`: 123 | 124 | ```rnc 125 | element addressBook { 126 | element card { 127 | element name { text }, 128 | element email { text } 129 | }* 130 | } 131 | ``` 132 | 133 | The following file, `addressBook.xml`, references `addressBook.rng` using the `xml-model` processing instruction. 134 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) will provide the features based on the grammar shown in [the demo at the beginning of this page](#relaxng-features) when you open `addressBook.xml`. 135 | 136 | ```xml 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | ``` 145 | 146 | # Generate RELAX NG from XML 147 | 148 | When an unbound XML file is open, a RELAX NG schema can be generated from the opening tag in the XML file. 149 | 150 | See: [Generate RELAX NG from XML](../BindingWithGrammar.md#generate-relax-ng-from-xml). 151 | -------------------------------------------------------------------------------- /docs/Features/XIncludeFeatures.md: -------------------------------------------------------------------------------- 1 | # XInclude Features 2 | 3 | ## Validation 4 | 5 | XML validation with [XInclude](https://www.w3.org/TR/xinclude/) is supported, which can be enabled / disabled with the `xml.validation.xInclude.enabled` setting. 6 | 7 | ![Xinclude Validation Example](../images/Features/XIncludeValidation.png) 8 | 9 | ## Document Link 10 | 11 | Document link is supported with `href` attribute. 12 | 13 | ![Xinclude Document Link Demo](../images/Features/XIncludeDocumentLink.gif) 14 | -------------------------------------------------------------------------------- /docs/Features/XMLCatalogFeatures.md: -------------------------------------------------------------------------------- 1 | # XML Catalog Features 2 | 3 | ## Validation 4 | 5 | XML Catalog is supported with both DTD and XSD. Please see here for more information on the usage of [XML Catalog With DTD](../Validation.md#xml-catalog-with-dtd) and [XML Catalog With XSD](../Validation.md#xml-catalog-with-xsd). 6 | 7 | ## Code Lens 8 | 9 | CodeLens is supported for XML catalogs, which shows whether the catalog is registered or not. 10 | It also provides the ability to register or unregister the catalog in settings.json. 11 | 12 | ![CodeLens Catalog Registration](../images/Features/CodeLensCatalogRegistration.gif) 13 | -------------------------------------------------------------------------------- /docs/Features/XMLColorsFeatures.md: -------------------------------------------------------------------------------- 1 | # XML Colors Features 2 | 3 | XML colors support provides the capability to mark a DOM node (attribute or text) as color with the `xml.colors` settings by using XPath expression : 4 | 5 | * `color/text()` defines the text node of the `color` element. 6 | * `item/@color` defines the `color` attribute node of the `item` element. 7 | 8 | ## Define Color in Text Content with `color/text()` 9 | 10 | Given this [android color](https://developer.android.com/guide/topics/resources/more-resources#Color) XML file sample: 11 | 12 | ```xml 13 | 14 | 15 | #f00 16 | rgb(222,82,0.82) 17 | #0cffffff 18 | 19 | ``` 20 | 21 | In this sample, text of `color` tag element `#f00` declare a color with hexadecimal. [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides a color support with the `xml.colors` settings. For [android color](https://developer.android.com/guide/topics/resources/more-resources#Color) case, you can declare this settings: 22 | 23 | ```json 24 | "xml.colors": [ 25 | { 26 | "pattern": "**/res/values/colors.xml", 27 | "expressions": [ 28 | { 29 | "xpath": "resources/color/text()" 30 | }, 31 | { 32 | "xpath": "resources/drawable/text()" 33 | } 34 | ] 35 | } 36 | ] 37 | ``` 38 | 39 | After saving this setting, you will get color support for the text node of `color` tag element in the `colors.xml` file: 40 | 41 | ![XML Colors](../images/Features/XMLColorsFeatures.png) 42 | 43 | ## Define Color in Attribute with `item/@color` 44 | 45 | Attribute values may also be marked as color by using the proper XPath. 46 | 47 | Given this `colors.xml` XML file: 48 | 49 | ```xml 50 | 51 | 52 | 53 | 54 | 55 | ``` 56 | 57 | You can declare this settings: 58 | 59 | ```json 60 | "xml.colors": [ 61 | { 62 | "pattern": "**/colors.xml", 63 | "expressions": [ 64 | { 65 | "xpath": "item/@color" 66 | } 67 | ] 68 | } 69 | ] 70 | ``` -------------------------------------------------------------------------------- /docs/Features/XMLFeatures.md: -------------------------------------------------------------------------------- 1 | # XML Features 2 | 3 | [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides a number of notable features, with demos below. 4 | 5 | ## Formatting 6 | 7 | To format an XML document, you can use the formatting shortcut `Ctrl + Shift + K`. 8 | 9 | ![Format XML](../images/Features/FormatXML.gif) 10 | 11 | For more information on formatting capabilities, see [Formatting](../Formatting.md#formatting). 12 | 13 | ## Folding 14 | 15 | XML tag folding is supported: 16 | 17 | To collapse and expand a tag, press the arrow. 18 | 19 | ![Folding XML](../images/Features/FoldingXML.gif) 20 | 21 | For more information on folding capabilities, see [Folding](../Folding.md#folding). 22 | 23 | ## XML Tag Auto Close 24 | 25 | XML tag `auto-close` is supported: 26 | 27 | Using `/` in an opening tag will auto close the tag. 28 | 29 | ![Auto Close Tag Slash](../images/Features/AutoCloseTagSlashXML.gif) 30 | 31 | ## Auto Rename Tag 32 | 33 | Linked editing is supported, allowing for simultaneous changes an opening and closing tag pair. 34 | 35 | To enable this feature, the setting `editor.linkedEditing` must be set to `true` in your `settings.json`. 36 | 37 | ![Linked Editing](../images/Features/LinkedEditingXML.gif) 38 | 39 | ## Jump to Start/End Tag 40 | 41 | For quick navigation, you can use `Ctrl + Click` on a closing tag to jump to the corresponding opening tag. 42 | 43 | ![Jump To Opening Tag](../images/Features/JumpToOpeningTagXML.gif) 44 | 45 | The same applies to jumping from an opening tag to the respective closing tag. 46 | 47 | ![Jump To Closing Tag](../images/Features/JumpToClosingTagXML.gif) 48 | 49 | ## Rename Tag 50 | 51 | To rename a single tag and its corresponding opening/closing, highlight the tag and press `F2` or use the dropdown to select `Rename Symbol`. 52 | 53 | ![Rename Tag](../images/Features/RenameTagXML.gif) 54 | 55 | ## Tag Name Highlighting 56 | 57 | When placing the cursor on an XML tag, the corresponding opening/closing tag will be highlighted. 58 | 59 | ![Highlight Corresponding XML](../images/Features/HighlightCorrespondingXML.gif) 60 | 61 | ## Symbols from Outline and Breadcrumbs 62 | 63 | The `OUTLINE` dropdown under `EXPLORER` details the XML tags in the document and their children. The `Breadcrumbs` bar also shows the hierarchy of the tag that the cursor is on. Both features permit jumping to the tag(s) displayed. 64 | 65 | ![Symbol Outline XML](../images/Features/SymbolOutlineXML.gif) 66 | 67 | ## Snippet Generation 68 | 69 | When starting a new XML document, `Ctrl` + `Space` lists different snippet options to set up the document. 70 | 71 | ![Generate XML Snippet](../images/Features/GenerateXMLSnippet.gif) 72 | 73 | There are also a number of keywords that will be recognized as snippets and autocompleted. For example, typing `schema` will list schema related snippet options. 74 | 75 | ![Generate XML Schema Snippet](../images/Features/GenerateXMLSchemaSnippet.gif) 76 | 77 | ## Completion Support 78 | 79 | ### Basic completion 80 | 81 | If an XML file is not associated to a bound grammar file, you can utilize XML completion which uses existing XML tag elements. 82 | 83 | ### Attribute value completion 84 | 85 | For an XML tag attribute, there is autocompletion support for the attribute value. For example, for path completion, type `.` or `/`. 86 | 87 | ![Attribute Completion XML](../images/Features/AttributeCompletionXML.gif) 88 | 89 | ### Completion based on grammar 90 | 91 | #### Completion based on XSD 92 | 93 | When an XML file is associated with an XSD file, there is support for completion based on the tags, attribute names and values defined in the XML Schema/XSD file. 94 | 95 | ![Completion Based On XSD](../images/Features/CompletionBasedOnXSD.gif) 96 | 97 | #### Completion based on DTD 98 | 99 | When XML file is associated with a DTD file, completion based on tags, attributes name and value defined in the DTD file are supported. 100 | 101 | ![Completion Based On DTD](../images/Features/CompletionBasedOnDTD.gif) 102 | 103 | ## Jump to Grammar Definition 104 | 105 | If an XML file is associated with an XSD file, there is support for jumping from the XML tag to the schema definition. 106 | 107 | ![Jump to XSD Def From XML](../images/Features/JumpToXSDDefFromXML.gif) 108 | 109 | ## Hover Support 110 | 111 | ### Hover based on grammar 112 | 113 | #### Hover based on XSD 114 | 115 | When XML file is associated with an XSD file, hover documentation based on tags, attributes name and value defined in the XML Schema/XSD file are supported. 116 | 117 | ![Hover Based On XSD](../images/Features/HoverBasedOnXSD.gif) 118 | 119 | #### Hover based on DTD 120 | 121 | When XML file is associated with a DTD file, hover documentation based on tags, attributes name and value defined in the DTD file are supported. 122 | 123 | ![Hover Based On DTD](../images/Features/HoverBasedOnDTD.gif) 124 | 125 | ## Validation Support 126 | 127 | ### Syntax validation 128 | 129 | LemMinX will show syntax errors in your XML documentation, and will provide quick fixes to resolve these errors. 130 | 131 | ![Validate XML](../images/Features/ValidationXML.gif) 132 | 133 | There is also validation based on grammar when an XSD or DTD file is associated with the XML document. 134 | 135 | ### Read more 136 | 137 | See [XML Validation](../Validation.md#xml-validation) for more details. 138 | 139 | ## Binding Grammar to an XML Document 140 | 141 | For any XML document, should you need to bind a grammar or schema with the file, you can do so by either using an existing grammar file, or by generating one using the built-in schema generator. 142 | 143 | See [Binding with Existing Grammar](../BindingWithGrammar.md#binding-with-existing-grammar) for info on binding to an existing schema. 144 | 145 | See [Binding with New Grammar](../BindingWithGrammar.md#binding-with-new-grammar) for info on grammar generation. 146 | 147 | ## Selection Range 148 | 149 | You can use `Alt + Shift + Right Arrow` to expand your selection range according to the structure of the XML document. 150 | 151 | For instance, if you expand the selection range in an element with text content, it will first select all the text content, then the element. 152 | 153 | This also works for other portions of an XML document, such as attributes and the DTD subset. 154 | 155 | ![Selection Range](../images/Features/SelectionRange.gif) 156 | 157 | ## CodeLens 158 | 159 | CodeLens is supported for `.xml` files for a number of different features. 160 | 161 | ### CodeLens 'Bind to grammar/schema...' 162 | 163 | If the current XML document is not bound to an existing grammar/schema, a CodeLens will appear above the root element, which will trigger the [XML Binding Wizard](../BindingWithGrammar.md#the-xml-binding-wizard). 164 | 165 | ![CodeLens Bind](../images/Features/CodeLensBind.png) 166 | 167 | For more information on CodeLens capabilities, see [CodeLens](../CodeLens.md#code-lens). 168 | 169 | ## Custom Feature Implementation 170 | 171 | You can implement your own feature with a [Java extension](../Extensions.md). 172 | -------------------------------------------------------------------------------- /docs/Features/XMLFilePathSupport.md: -------------------------------------------------------------------------------- 1 | # XML File Paths Features 2 | 3 | XML file path support provides the capability to mark a DOM node (attribute or text) as file path with the `xml.filePathSupport.mappings` setting, by using XPath expression : 4 | 5 | * `path/text()` defines the text node of the `path` element. 6 | * `item/@path` defines the `path` attribute node of the `item` element. 7 | 8 | Once the DOM node is designated as a file path, you will enjoy the benefits of file completion. 9 | 10 | * Files completion. 11 | 12 | ## Define File path in Text Content with `path/text()` 13 | 14 | Given this XML file `items.xml` sample: 15 | 16 | ```xml 17 | 18 | 19 | path/to/file.xml 20 | 21 | ``` 22 | 23 | In this example: 24 | 25 | The text within the `path` tag element `path/to/file.xml` represents a file path. The [vscode-xml](https://github.com/redhat-developer/vscode-xml) extension offers file path support through the `xml.filePathSupport.mappings` settings. You can configure this setting as follows: 26 | 27 | ```json 28 | "xml.filePathSupport.mappings": [ 29 | { 30 | "pattern": "**/items.xml", 31 | "expressions": [ 32 | { 33 | "xpath": "items/path/text()" 34 | } 35 | ] 36 | } 37 | ] 38 | ``` 39 | 40 | After saving this setting, you will get file path completion support for the text node of `path` tag element: 41 | 42 | ![XML File Paths in Text](../images/Features/XMLFilePathsInTextFeatures.png) 43 | 44 | ## Define File path in Attribute with `item/@path` 45 | 46 | Attribute values may also be marked as file path by using the proper XPath. 47 | 48 | Given this `items.xml` XML file: 49 | 50 | ```xml 51 | 52 | 53 | 54 | 55 | 56 | ``` 57 | 58 | You can declare this settings: 59 | 60 | ```json 61 | "xml.filePathSupport.mappings": [ 62 | { 63 | "pattern": "**/items.xml", 64 | "expressions": [ 65 | { 66 | "xpath": "item/@path" 67 | } 68 | ] 69 | } 70 | ] 71 | ``` 72 | 73 | After saving this setting, you will get file path completion support for the text node of `path` attribute: 74 | 75 | ![XML File Paths in Attr](../images/Features/XMLFilePathsInAttrFeatures.png) 76 | 77 | ## Filter the file path completion result 78 | 79 | Given this `images.xml` file: 80 | 81 | ```xml 82 | 83 | 84 | 85 | ``` 86 | 87 | If you need to restrict file path completion on `image/@src` files with the `.png`, `.gif` or `.jpg` extensions, you can use the `filter` property, with this settings: 88 | 89 | ```json 90 | "xml.filePathSupport.mappings": [ 91 | { 92 | "pattern": "**/images.xml", 93 | "expressions": [ 94 | { 95 | "xpath": "image/@src", 96 | "filter": [".png", ".gif", ".jpg"] 97 | } 98 | ] 99 | } 100 | ] 101 | ``` 102 | 103 | ## Separator to declare multiple file paths. 104 | 105 | Given this `paths.xml` file: 106 | 107 | ```xml 108 | 109 | 110 | 111 | ``` 112 | 113 | If you want to handle file path completion for `item/@paths` by declaring several file paths separated by `;`, you can use the `separator` property with these settings: 114 | 115 | ```json 116 | "xml.filePathSupport.mappings": [ 117 | { 118 | "pattern": "**/paths.xml", 119 | "expressions": [ 120 | { 121 | "xpath": "item/@paths", 122 | "separator": ";" 123 | } 124 | ] 125 | } 126 | ] 127 | ``` 128 | -------------------------------------------------------------------------------- /docs/Features/XMLReferencesFeatures.md: -------------------------------------------------------------------------------- 1 | # XML References Features 2 | 3 | XML References support provides the capability to reference a DOM node (attribute or text) to an another DOM node (attribute or text) with the `xml.references` settings by using XPath expression : 4 | 5 | * `foo/@attr` defines the `attr` attribute node of the `foo` element. 6 | * `foo/text()` defines the text node of the `foo` element. 7 | 8 | Once you have declared those reference, you will benefit with completion, definition, highlight, validation, rename, find references, and show references count with codelens: 9 | 10 | ![XML References with TEI](../images/Features/XMLReferencesWithTEI.gif) 11 | 12 | ## Attribute node references (foo/@attr) 13 | 14 | Given this [docbook](https://docbook.org/) XML file sample: 15 | 16 | ```xml 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | 32 | At first, please note that [resolve external entities](https://github.com/redhat-developer/vscode-xml/blob/main/docs/Validation.md#resolve-external-entities) must be enabled for this DTD to work. 33 | 34 | In this sample, `linkend` attribute in `` references the `chapter-1` declared in ``. [vscode-xml](https://github.com/redhat-developer/vscode-xml) provides a completion, definition, highlighting support to support this kind of references easily with the `xml.references` settings. For docbook case, you can declare this settings: 35 | 36 | ```json 37 | "xml.references": [ 38 | { 39 | "pattern": "**/*.xml", 40 | "expressions": [ 41 | { 42 | "from": "xref/@linkend", 43 | "to": "@id" 44 | } 45 | ] 46 | } 47 | ] 48 | ``` 49 | 50 | After saving this setting, you will get completion, go to definition, and highlighting for `xref` in the docbook file: 51 | 52 | ![XML References with docbook](../images/Features/XMLReferencesWithDocbook.gif) 53 | 54 | The `xml.references` settings is an array of objects with the following properties: 55 | 56 | * `pattern`: matches the files that reference declared with `expressions` applies to. See [glob syntax](https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob) for more information about the pattern syntax. 57 | * `prefix (optional)`: the prefix to use (ex : '#') for from for all the declared reference expressions. 58 | * `multiple (optional)`: true if the from attribute, text can declare several from references and false otherwise for all the declared reference expressions. 59 | * `expressions`: array of reference expression: 60 | * `prefix (optional)`: the prefix to use (ex : '#') for from. 61 | * `multiple (optional)`: true if the from attribute, text can declare several from references and false otherwise. 62 | * `from`: the from reference DOM node (attribute, text) declared with XPath (ex: `foo/@attr`, `foo/text()`). 63 | * `to`: the to reference DOM node (attribute, text) declared with XPath (ex: `foo/@attr`, `foo/text()`). 64 | 65 | ### prefix 66 | 67 | Given this [TEI](https://tei-c.org/) XML file sample: 68 | 69 | ```xml 70 | 71 | 72 | 73 | 74 | 75 | 76 | Title 77 | 78 | 79 |

Publication information

80 |
81 | 82 |

Information about the source

83 |
84 |
85 |
86 | 87 | 88 |

Some text here.

89 | 90 | 91 |
92 |
93 | ``` 94 | 95 | In this sample, `corresp` attribute in `` references the `body-id` (without `#`) declared in ``. It means that the `corresp` attribute value (with `#`) reference `@xml:id` attribute (without `#`). To support that, you can configure settings by using `prefix`: 96 | 97 | ```json 98 | "xml.references": [ 99 | { 100 | "pattern": "**/*.xml", 101 | "prefix": "#", 102 | "expressions": [ 103 | { 104 | "from": "@resp", 105 | "to": "persName/@xml:id" 106 | }, 107 | { 108 | "from": "@corresp", 109 | "to": "@xml:id" 110 | } 111 | ] 112 | } 113 | ] 114 | ``` 115 | ## Multiple target 116 | 117 | If the `origin` attribute (which matches the `from` reference path) declares multiple targets (which matches the `to` reference path), you can use `multiple` 118 | 119 | Given this XML file where `target` attribute defines several targets separated with whitespace (#body-id #p-id): 120 | 121 | ```xml 122 | 123 |

Some text here.

124 | 125 | 126 | ``` 127 | 128 | In this sample, `target` attribute in `` references the `body-id` and `p-id` (without `#`) declared in `` and `

`. It means that the `target` attribute value (with `#`) reference `@xml:id` attribute (without `#`). To support that, you can configure settings by using `multiple`: 129 | 130 | ```json 131 | "xml.references": [ 132 | { 133 | "pattern": "**/*.xml", 134 | "prefix": "#", 135 | "multiple": true, 136 | "expressions": [ 137 | { 138 | "from": "link/@target", 139 | "to": "@xml:id" 140 | } 141 | ] 142 | } 143 | ] 144 | ``` 145 | 146 | ## Text node references (foo/text()) 147 | 148 | Given this *web.xml* sample: 149 | 150 | ```xml 151 | 155 | 156 | comingsoon 157 | mysite.server.ComingSoonServlet 158 | 159 | 160 | comingsoon 161 | /* 162 | 163 | 164 | ``` 165 | 166 | In this sample, `servlet-mapping/servlet-name` text in `comingsoon` references the `comingsoon` declared in ``servlet/servlet-name` text. To support that, you can configure settings like this: 167 | 168 | ```json 169 | "xml.references": [ 170 | { 171 | "pattern": "**/web.xml", 172 | "expressions": [ 173 | { 174 | "from": "servlet-mapping/servlet-name/text()", 175 | "to": "servlet/servlet-name/text()" 176 | } 177 | ] 178 | } 179 | ] 180 | ``` 181 | 182 | ![XML References with web.xml](../images/Features/XMLReferencesWithWebXML.gif) 183 | 184 | ### Limitation 185 | 186 | XML references have some limitation: 187 | 188 | * *references works only for a given XML file*: it is not possible to reference some DOM nodes coming from another XML files. However if the file uses include (like xi:include) the reference will only work in the file which has the include statement, and not in the file being included. 189 | 190 | If you need those support, please [create an issue](https://github.com/redhat-developer/vscode-xml/issues) -------------------------------------------------------------------------------- /docs/Features/XSDFeatures.md: -------------------------------------------------------------------------------- 1 | # XSD Features 2 | 3 | ## CodeLens Support 4 | 5 | CodeLens is supported for `.xsd` files, which can show where a type is referenced. 6 | 7 | ![CodeLens XSD](../images/Features/CodeLensXSD.gif) 8 | 9 | This feature also supports listing the number of references to a type and the line(s) referenced on. 10 | 11 | ![CodeLens References XSD](../images/Features/CodeLensReferencesXSD.gif) 12 | 13 | ### Read more 14 | 15 | See [CodeLens](../CodeLens.md#code-lens) for more details. 16 | 17 | ## XSD Tag Support 18 | 19 | After defining a `Type` or `element` tag in the `.xsd` file, there are a number of features supported in relation to types/elements. 20 | 21 | ### Type completion 22 | 23 | There is autocompletion support for assigning these types to element tags. 24 | 25 | ![Type Autocompletion XSD](../images/Features/TypeAutocompleteXSD.gif) 26 | 27 | ### Jump to type definition 28 | 29 | For an `element` tag that is assigned a type, there is support for navigating to its definition from any type assignment. 30 | 31 | ![Jump To Type Definition XSD](../images/Features/JumpToTypeDefinitionXSD.gif) 32 | 33 | ### Highlight type instances 34 | 35 | After defining a `Type` or `element`, selecting the `name` attribute will highlight all occurrences. 36 | 37 | ![Highlight Occurrences XSD](../images/Features/HighlightOccurrenceXSD.gif) 38 | 39 | ### Change all type occurrences 40 | 41 | To rename a `Type` definition and its associated `element` `type` attribute values, highlight the `name` attribute of the `Type` and press `F2` or use the dropdown to select `Rename Symbol`. 42 | 43 | ![Rename Type Reference XSD](../images/Features/RenameTypeReferenceXSD.gif) 44 | 45 | ## Syntax Validation 46 | 47 | XSD syntax validation is enabled for any `.xsd` file. 48 | 49 | ### Validate element name with same type 50 | 51 | Validation of `.xsd` files enforces all `element` tags that share a type to have different names. 52 | 53 | ![Validate XSD Same Name](../images/Features/ValidateXSDSameName.gif) 54 | 55 | ### Validate type definition exists 56 | 57 | Validation of `.xsd` files enforces all `element` tags to be assigned a type that has already been defined. 58 | 59 | ![Validate XSD Type](../images/Features/ValidateXSDType.gif) 60 | -------------------------------------------------------------------------------- /docs/Folding.md: -------------------------------------------------------------------------------- 1 | ## Folding 2 | 3 | ### xml.foldings.includeClosingTagInFold 4 | 5 | When folding, the closing tag will remain unfolded by default. 6 | 7 | ![Folding XML](images/Features/FoldingXML.gif) 8 | 9 | To change this to minimize the closing tag within the fold, set folding.includeClosingTagInFold to `true`. 10 | 11 | ![Folding XML](images/Features/FoldingSetTrueXML.gif) 12 | -------------------------------------------------------------------------------- /docs/Proxy.md: -------------------------------------------------------------------------------- 1 | # Proxy 2 | 3 | This page explains how to get vscode-xml to work through a proxy. 4 | 5 | ## Prerequisites 6 | 7 | You need to make sure that you can access any online XML schemas that you want to work with through the proxy. 8 | Also, if are using open-vsx.org instead of Visual Studio Marketplace for extensions 9 | and you want to use the binary language server, 10 | then you will need to make sure that your proxy allows connections to GitHub, 11 | since the binary language server is downloaded from GitHub when using open-vsx.org [for the time being](https://github.com/redhat-developer/vscode-xml/issues/739). 12 | 13 | ## Setting up the proxy in VS Code 14 | 15 | VS Code provides a setting called `http.proxySupport`. 16 | If you set it to `override`, VS Code will attempt to rewrite the requests from extensions to go through the proxy that is configured for VS Code. 17 | However, this method sometimes does not work correctly. 18 | 19 | The tested way to get vscode-xml to use your proxy is to set the following settings: 20 | * `http.proxy`: 21 | The address at which the proxy can be accessed. 22 | As an example, use `"http://localhost:3128"` for a proxy running on your machine on port 3128. 23 | vscode-xml (as well as VS Code) assumes that the same proxy address is used for the HTTP and HTTPS requests. 24 | * `http.proxyAuthorization`: 25 | The authorization header to use for the proxy requests. 26 | This is only needed when the proxy requires authorization. 27 | This follows the form `"[type] [credientials]"`, 28 | where `type` is the authorization type that the proxy uses, 29 | and `credentials` are your credentials for accessing the proxy. 30 | The format of the `credentials` is different for each authorization type. 31 | For instance, `"Basic dXNlcm5hbWU6cGFzc3dvcmQ="` is the authorization header 32 | for a proxy that uses Basic authorization, 33 | where your username is `username` and your password is `password`. 34 | The credentials, `"dXNlcm5hbWU6cGFzc3dvcmQ="`, is `username:password` encoded in base64, 35 | which is the format that is expected for Basic authorization. 36 | Please refer to [this MDN link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) for more information about authorization headers. 37 | 38 | Once these settings are set, 39 | vscode-xml will forward any requests that it makes through the proxy, 40 | such as the binary server download request 41 | and requests from the language server to download schema. 42 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # XML Documentation 2 | 3 | Welcome to the [vscode-xml](https://github.com/redhat-developer/vscode-xml) documentation. 4 | 5 | ## User Guide 6 | 7 | * [XML Validation](Validation.md#xml-validation): How to validate XML with a grammar (XSD/DTD/RelaxNG)? 8 | * [Preferences](Preferences.md#preferences): More info on available [vscode-xml](https://github.com/redhat-developer/vscode-xml) preferences. 9 | * [Formatting](Formatting.md#formatting): More info on the available formatting preferences. 10 | * [XML Commands](Commands.md#commands): More info on the available XML vscode commands. 11 | * [Symbols](Symbols.md#symbols): More info on the available settings for the document symbols (outline). 12 | * [Troubleshooting](Troubleshooting.md#troubleshooting): Info on troubleshooting and fixes to issues. 13 | * [Features](Features.md#features): Notable info and demos on features available to use. 14 | * [Proxy](Proxy.md#proxy): Instructions for setting up vscode-xml to work behind a proxy. 15 | * [Binding With Grammar](BindingWithGrammar.md#binding-with-grammar): Extension feature to bind an XML document to a grammar/schema file. 16 | 17 | ## Developer Guide 18 | 19 | * [Extensions](Extensions.md#extensions): How to extend vscode-xml settings and XML features (completion, validation, hover, etc)? -------------------------------------------------------------------------------- /docs/Refactor.md: -------------------------------------------------------------------------------- 1 | # Refactor 2 | 3 | ## Surround with Tags (Wrap) 4 | 5 | This refactor command gives the capability to select an XML content and surround it with a given tag. To execute this command you can: 6 | 7 | * use command palette (`Ctrl+P`) and type `Surround` 8 | 9 | ![Surround with Tags](images/Refactor/SurroundWithTags.gif) 10 | 11 | * use contextual menu 12 | 13 | If you prefer using keyboard to process `Surround with Tags (Wrap)`,you need to associate this command with a keybinding. See [Keyboard Shortcuts editor](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-editor) for more informations. 14 | 15 | ## Surround with Comments 16 | 17 | Similar to `Surround with Tags (Wrap)`, you can comment out the selected XML content: 18 | 19 | ![Surround with Tags](images/Refactor/SurroundWithComments.gif) 20 | 21 | ## Surround with CDATA 22 | 23 | Similar to `Surround with Tags (Wrap)`, you can surround the selected XML content with CDATA: 24 | 25 | ![Surround with Tags](images/Refactor/SurroundWithCDATA.gif) -------------------------------------------------------------------------------- /docs/Troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ## Issues 4 | 5 | Please create [vscode-xml issues](https://github.com/redhat-developer/vscode-xml/issues) for any problem. 6 | 7 | ### No support on xml file. 8 | 9 | Sometimes an old instance of the XML Language Server is still running. 10 | 11 | You can check if the server is not working in VSCode by going to: 12 | 1) Turning on `xml.trace.server` in the VSCode preferences 13 | 2) `View -> Output -> XML Support` (drop down menu top right) 14 | If it is not working it will indicate the server has Shutdown. 15 | 16 | You can kill the process by: 17 | 18 | 1) Run `jps` command in terminal 19 | 2) Check if multiple instances of `org.eclipse.lemminx-uber.jar` or `XMLServerLauncher` 20 | 3) According to your OS: 21 | 22 | * on Windows OS: run `taskkill /F /PID ...` all instances 23 | * on other OS: run `kill -9 ...` all instances 24 | 25 | ### The Language Server Crashes Due to an Out Of Memory Error 26 | 27 | If you are working with large XML files or referencing large schema files, 28 | this may lead to the language server running out of memory. 29 | The Java language server is more likely to run out memory than the binary language server. 30 | [Switching to the binary language server](Preferences.md#server-binary-mode) 31 | (via the `xml.server.preferBinary` setting) 32 | or increasing the memory available to the Java language server could resolve this issue. 33 | 34 | If you get an Out of Memory Error, but aren't working with large XML files, 35 | then there may be a memory leak in the language server. 36 | Please [file a issue](https://github.com/redhat-developer/vscode-xml/issues) with a description of what you were doing if this is the case. 37 | 38 | #### How to increase the amount of memory available to the Java Language Server 39 | 40 | 1. Go to settings 41 | 2. Navigate to the setting `xml.server.vmargs` 42 | 3. Add `-Xmx512m` to the setting string. This allows the language server to use at most 512 megabytes of memory. 43 | 4. If the problem persists, you can increase the `512m` to `1G` or higher 44 | -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindToGrammarCodeAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindToGrammarCodeAction.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindToGrammarCodeActionDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindToGrammarCodeActionDropdown.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindToGrammarCodeLens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindToGrammarCodeLens.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindToGrammarCommand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindToGrammarCommand.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindingWizardDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindingWizardDemo.gif -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindingWizardDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindingWizardDropdown.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/BindingWizardFileExplorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/BindingWizardFileExplorer.png -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/GenerateDTDFromXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/GenerateDTDFromXML.gif -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/GenerateRelaxNGFromXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/GenerateRelaxNGFromXML.gif -------------------------------------------------------------------------------- /docs/images/BindingWithGrammar/GenerateXSDFromXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/BindingWithGrammar/GenerateXSDFromXML.gif -------------------------------------------------------------------------------- /docs/images/CodeLens/DTDElementCodeLens.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/CodeLens/DTDElementCodeLens.gif -------------------------------------------------------------------------------- /docs/images/CodeLens/XSDElementCodeLens.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/CodeLens/XSDElementCodeLens.gif -------------------------------------------------------------------------------- /docs/images/CodeLens/XSDTypeCodeLens.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/CodeLens/XSDTypeCodeLens.gif -------------------------------------------------------------------------------- /docs/images/Commands/XMLCommands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Commands/XMLCommands.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugAttachRemote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugAttachRemote.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugConfigurations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugConfigurations.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugLemMinXExtensionInEclipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugLemMinXExtensionInEclipse.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugLemMinXExtensionInVSCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugLemMinXExtensionInVSCode.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugMultiRootSetup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugMultiRootSetup.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugVSCodeXML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugVSCodeXML.png -------------------------------------------------------------------------------- /docs/images/Extensions/DebugVSCodeXMLSingleRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/DebugVSCodeXMLSingleRoot.png -------------------------------------------------------------------------------- /docs/images/Extensions/EclipseRunDebugConfigurations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/EclipseRunDebugConfigurations.png -------------------------------------------------------------------------------- /docs/images/Extensions/EclipseWithLemMinXExtensionOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/EclipseWithLemMinXExtensionOpen.png -------------------------------------------------------------------------------- /docs/images/Extensions/HitABreakpointVSCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/HitABreakpointVSCode.png -------------------------------------------------------------------------------- /docs/images/Extensions/InstallVSCodeExtensionForLemMinXExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/InstallVSCodeExtensionForLemMinXExtension.png -------------------------------------------------------------------------------- /docs/images/Extensions/LaunchVSCodeExtensionForLemMinXExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/LaunchVSCodeExtensionForLemMinXExtension.png -------------------------------------------------------------------------------- /docs/images/Extensions/NewDebugConfiguration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/NewDebugConfiguration.png -------------------------------------------------------------------------------- /docs/images/Extensions/PackageVSCodeExtensionForLemMinXExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/PackageVSCodeExtensionForLemMinXExtension.png -------------------------------------------------------------------------------- /docs/images/Extensions/ProjectWindowAndDebugWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/ProjectWindowAndDebugWindow.png -------------------------------------------------------------------------------- /docs/images/Extensions/ProjectWindowAndDebugWindowSingleRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/ProjectWindowAndDebugWindowSingleRoot.png -------------------------------------------------------------------------------- /docs/images/Extensions/TerminalInstallVSCodeExtensionForLemMinXExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/TerminalInstallVSCodeExtensionForLemMinXExtension.png -------------------------------------------------------------------------------- /docs/images/Extensions/VSCodeExtensionForLemMinXExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Extensions/VSCodeExtensionForLemMinXExtension.png -------------------------------------------------------------------------------- /docs/images/Features/AttributeCompletionXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/AttributeCompletionXML.gif -------------------------------------------------------------------------------- /docs/images/Features/AutoCloseTagEndXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/AutoCloseTagEndXML.gif -------------------------------------------------------------------------------- /docs/images/Features/AutoCloseTagEndXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/AutoCloseTagEndXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/AutoCloseTagSlashXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/AutoCloseTagSlashXML.gif -------------------------------------------------------------------------------- /docs/images/Features/AutoCloseTagSlashXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/AutoCloseTagSlashXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/CodeLensBind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensBind.png -------------------------------------------------------------------------------- /docs/images/Features/CodeLensCatalogRegistration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensCatalogRegistration.gif -------------------------------------------------------------------------------- /docs/images/Features/CodeLensDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/CodeLensReferencesDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensReferencesDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/CodeLensReferencesXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensReferencesXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/CodeLensXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CodeLensXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/CompletionBasedOnDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CompletionBasedOnDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/CompletionBasedOnXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/CompletionBasedOnXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/FoldingSetTrueXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/FoldingSetTrueXML.gif -------------------------------------------------------------------------------- /docs/images/Features/FoldingXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/FoldingXML.gif -------------------------------------------------------------------------------- /docs/images/Features/FormatXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/FormatXML.gif -------------------------------------------------------------------------------- /docs/images/Features/GenerateXMLSchemaSnippet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/GenerateXMLSchemaSnippet.gif -------------------------------------------------------------------------------- /docs/images/Features/GenerateXMLSnippet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/GenerateXMLSnippet.gif -------------------------------------------------------------------------------- /docs/images/Features/HighlightCorrespondingXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/HighlightCorrespondingXML.gif -------------------------------------------------------------------------------- /docs/images/Features/HighlightOccurrenceXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/HighlightOccurrenceXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/HoverBasedOnDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/HoverBasedOnDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/HoverBasedOnXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/HoverBasedOnXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToClosingTagXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToClosingTagXML.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToClosingTagXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToClosingTagXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToElementDeclarationDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToElementDeclarationDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToOpeningTagXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToOpeningTagXML.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToOpeningTagXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToOpeningTagXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToTypeDefinitionXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToTypeDefinitionXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/JumpToXSDDefFromXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/JumpToXSDDefFromXML.gif -------------------------------------------------------------------------------- /docs/images/Features/LinkedEditingXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/LinkedEditingXML.gif -------------------------------------------------------------------------------- /docs/images/Features/RenameTagXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/RenameTagXML.gif -------------------------------------------------------------------------------- /docs/images/Features/RenameTagXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/RenameTagXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/RenameTypeReferenceXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/RenameTypeReferenceXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/SelectionRange.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/SelectionRange.gif -------------------------------------------------------------------------------- /docs/images/Features/SymbolOutlineXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/SymbolOutlineXML.gif -------------------------------------------------------------------------------- /docs/images/Features/TypeAutocompleteXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/TypeAutocompleteXSD.gif -------------------------------------------------------------------------------- /docs/images/Features/ValidateXSDSameName.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/ValidateXSDSameName.gif -------------------------------------------------------------------------------- /docs/images/Features/ValidateXSDType.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/ValidateXSDType.gif -------------------------------------------------------------------------------- /docs/images/Features/ValidationDTD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/ValidationDTD.gif -------------------------------------------------------------------------------- /docs/images/Features/ValidationXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/ValidationXML.gif -------------------------------------------------------------------------------- /docs/images/Features/XIncludeDocumentLink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XIncludeDocumentLink.gif -------------------------------------------------------------------------------- /docs/images/Features/XIncludeValidation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XIncludeValidation.png -------------------------------------------------------------------------------- /docs/images/Features/XMLColorsFeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLColorsFeatures.png -------------------------------------------------------------------------------- /docs/images/Features/XMLFilePathsInAttrFeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLFilePathsInAttrFeatures.png -------------------------------------------------------------------------------- /docs/images/Features/XMLFilePathsInTextFeatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLFilePathsInTextFeatures.png -------------------------------------------------------------------------------- /docs/images/Features/XMLReferencesWithDocbook.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLReferencesWithDocbook.gif -------------------------------------------------------------------------------- /docs/images/Features/XMLReferencesWithTEI.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLReferencesWithTEI.gif -------------------------------------------------------------------------------- /docs/images/Features/XMLReferencesWithWebXML.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Features/XMLReferencesWithWebXML.gif -------------------------------------------------------------------------------- /docs/images/Preferences/HoverDocumentationQuickDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Preferences/HoverDocumentationQuickDemo.gif -------------------------------------------------------------------------------- /docs/images/Refactor/SurroundWithCDATA.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Refactor/SurroundWithCDATA.gif -------------------------------------------------------------------------------- /docs/images/Refactor/SurroundWithComments.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Refactor/SurroundWithComments.gif -------------------------------------------------------------------------------- /docs/images/Refactor/SurroundWithTags.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Refactor/SurroundWithTags.gif -------------------------------------------------------------------------------- /docs/images/RelaxNG/GoToTypeDefinitionMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/GoToTypeDefinitionMenu.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/GoToTypeDefinitionResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/GoToTypeDefinitionResult.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/RNGDefineSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RNGDefineSupport.gif -------------------------------------------------------------------------------- /docs/images/RelaxNG/RNGHrefSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RNGHrefSupport.gif -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGCompactSyntaxOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGCompactSyntaxOverview.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGCompletionAndDocumentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGCompletionAndDocumentation.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGHoverAndDocumentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGHoverAndDocumentation.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGSnippetsSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGSnippetsSupport.gif -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGSupport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGSupport.gif -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGValidation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGValidation.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/RelaxNGXMLSyntaxOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/RelaxNGXMLSyntaxOverview.png -------------------------------------------------------------------------------- /docs/images/RelaxNG/XMLValidatedWithRelaxNG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/RelaxNG/XMLValidatedWithRelaxNG.png -------------------------------------------------------------------------------- /docs/images/Symbols/ShowReferencedGrammars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Symbols/ShowReferencedGrammars.png -------------------------------------------------------------------------------- /docs/images/Symbols/SymbolsBeansWithIdAttrFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Symbols/SymbolsBeansWithIdAttrFilter.png -------------------------------------------------------------------------------- /docs/images/Symbols/SymbolsBuildWithInlineAttrFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Symbols/SymbolsBuildWithInlineAttrFilter.png -------------------------------------------------------------------------------- /docs/images/Symbols/SymbolsPOMWithTextFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Symbols/SymbolsPOMWithTextFilter.png -------------------------------------------------------------------------------- /docs/images/Symbols/SymbolsPOMWithoutFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Symbols/SymbolsPOMWithoutFilter.png -------------------------------------------------------------------------------- /docs/images/Validation/DoctypeError1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/DoctypeError1.png -------------------------------------------------------------------------------- /docs/images/Validation/DoctypeError2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/DoctypeError2.png -------------------------------------------------------------------------------- /docs/images/Validation/ExternalEntityResolvingDemonstration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/ExternalEntityResolvingDemonstration.gif -------------------------------------------------------------------------------- /docs/images/Validation/GenerateXSD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/GenerateXSD.gif -------------------------------------------------------------------------------- /docs/images/Validation/XMLGrammarError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/XMLGrammarError.png -------------------------------------------------------------------------------- /docs/images/Validation/XMLSyntaxError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/XMLSyntaxError.png -------------------------------------------------------------------------------- /docs/images/Validation/XMLSyntaxErrorCodeAction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/Validation/XMLSyntaxErrorCodeAction.gif -------------------------------------------------------------------------------- /docs/images/pre-release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/pre-release.png -------------------------------------------------------------------------------- /docs/images/vscode-xml-maven.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/docs/images/vscode-xml-maven.gif -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from '@eslint/js'; 4 | import tseslint from 'typescript-eslint'; 5 | import globals from "globals"; 6 | 7 | export default tseslint.config( 8 | eslint.configs.recommended, 9 | tseslint.configs.recommended, 10 | { 11 | ignores: [ 12 | "node_modules/**", 13 | "dist/**", 14 | "server/**", 15 | "out/**", 16 | ], 17 | }, 18 | { 19 | files: [ "src/**/*" ], 20 | rules: { 21 | "@typescript-eslint/no-unused-vars": [ 22 | "warn", 23 | { 24 | "argsIgnorePattern": "^_", 25 | "caughtErrorsIgnorePattern": "^_" 26 | } 27 | ], 28 | "@typescript-eslint/no-explicit-any": "warn", 29 | } 30 | }, { 31 | files: [ 32 | "gulpfile.js", 33 | "webpack.config.js" 34 | ], 35 | languageOptions: { 36 | sourceType: "commonjs", 37 | globals: globals.node 38 | }, 39 | rules: { 40 | "@typescript-eslint/no-var-requires": "off", 41 | "@typescript-eslint/no-require-imports": "off" 42 | } 43 | } 44 | ); 45 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const gulp = require('gulp'); 3 | const cp = require('child_process'); 4 | const fse = require('fs-extra'); 5 | const glob = require('glob'); 6 | 7 | const server_dir = '../lemminx'; 8 | 9 | gulp.task('build_server', function (done) { 10 | cp.execSync(mvnw() + " clean verify -DskipTests", { cwd: server_dir, stdio: [0, 1, 2] }); 11 | gulp.src(server_dir + '/org.eclipse.lemminx/target/org.eclipse.lemminx-uber.jar', { encoding: false }) 12 | .pipe(gulp.dest('./server')); 13 | done(); 14 | }); 15 | 16 | gulp.task('build_server_with_binary', function (done) { 17 | cp.execSync(mvnw() + " clean verify -DskipTests -Dnative", { cwd: server_dir, stdio: [0, 1, 2] }); 18 | gulp.src([server_dir + '/org.eclipse.lemminx/target/org.eclipse.lemminx-uber.jar', server_dir + '/org.eclipse.lemminx/target/lemminx-*'], { encoding: false }) 19 | .pipe(gulp.dest('./server')) 20 | .on('end', function () { 21 | glob.Glob('./server/lemminx-*.txt', (_er, txtfiles) => { 22 | fse.removeSync(txtfiles[0]); 23 | glob.Glob('./server/lemminx-*-*', (_err, binfiles) => { 24 | fse.moveSync(binfiles[0], './server/lemminx-' + (isWin() ? 'win32.exe' : (isMac() ? 'osx-x86_64' : 'linux')), { overwrite: true }); 25 | }); 26 | }); 27 | }); 28 | done(); 29 | }); 30 | 31 | gulp.task('prepare_pre_release', function (done) { 32 | const json = JSON.parse(fse.readFileSync("./package.json").toString()); 33 | const stableVersion = json.version.match(/(\d+)\.(\d+)\.(\d+)/); 34 | const major = stableVersion[1]; 35 | const minor = stableVersion[2]; 36 | const date = new Date(); 37 | const month = date.getMonth() + 1; 38 | const day = date.getDate(); 39 | const hours = date.getHours(); 40 | const patch = `${date.getFullYear()}${prependZero(month)}${prependZero(day)}${prependZero(hours)}`; 41 | const insiderPackageJson = Object.assign(json, { 42 | version: `${major}.${minor}.${patch}`, 43 | }); 44 | fse.writeFileSync("./package.json", JSON.stringify(insiderPackageJson, null, 2)); 45 | done(); 46 | }); 47 | 48 | function isWin() { 49 | return /^win/.test(process.platform); 50 | } 51 | 52 | function isMac() { 53 | return /^darwin/.test(process.platform); 54 | } 55 | 56 | function mvnw() { 57 | return isWin() ? "mvnw.cmd" : server_dir + "/mvnw"; 58 | } 59 | 60 | function prependZero(number) { 61 | if (number > 99) { 62 | throw "Unexpected value to prepend with zero"; 63 | } 64 | return `${number < 10 ? "0" : ""}${number}`; 65 | } 66 | -------------------------------------------------------------------------------- /icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/icons/icon128.png -------------------------------------------------------------------------------- /images/DebugAttachRemote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/images/DebugAttachRemote.png -------------------------------------------------------------------------------- /images/DebugMenuCallStack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/images/DebugMenuCallStack.png -------------------------------------------------------------------------------- /images/DownloadBinaryArtifacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/images/DownloadBinaryArtifacts.png -------------------------------------------------------------------------------- /images/DownloadBinaryChecks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/images/DownloadBinaryChecks.png -------------------------------------------------------------------------------- /images/LaunchExtension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-developer/vscode-xml/f6aaeba81da7f74292e72341a09c4fe7bbc0df20/images/LaunchExtension.png -------------------------------------------------------------------------------- /rnc.language-configuration.json: -------------------------------------------------------------------------------- 1 | // Copy of https://github.com/RussGlover/relaxNgCompactSyntaxHighlighter/blob/master/language-configuration.json 2 | { 3 | "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 | } -------------------------------------------------------------------------------- /schemas/package.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "XML Language server contributions to package.json", 4 | "type": "object", 5 | "properties": { 6 | "contributes": { 7 | "type": "object", 8 | "properties": { 9 | "xml.javaExtensions": { 10 | "type": "array", 11 | "markdownDescription": "XML language server extensions", 12 | "items": { 13 | "type": "string", 14 | "description": "Relative path to a XML language server extension JAR file" 15 | } 16 | }, 17 | "xmlLanguageParticipants": { 18 | "type": "array", 19 | "description": "A list of languages that participate with the XML language server.", 20 | "items": { 21 | "type": "object", 22 | "properties": { 23 | "languageId": { 24 | "type": "string", 25 | "description": "The id of the language that participates with XML language server." 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/api/xmlExtensionApi.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface for APIs exposed from the extension. 3 | * 4 | * @remarks 5 | * A sample code to use these APIs are as following: 6 | * const ext = await vscode.extensions.getExtension('redhat.vscode-xml').activate(); 7 | * ext.addXMLCatalogs(...); 8 | * ext.removeXMLCatalogs(...); 9 | * ext.addXMLFileAssociations(...); 10 | * ext.removeXMLFileAssociations(...); 11 | */ 12 | export interface XMLExtensionApi { 13 | /** 14 | * Adds XML Catalogs in addition to the catalogs defined in the settings.json file. 15 | * 16 | * @remarks 17 | * An example is to call this API: 18 | * ```ts 19 | * addXMLCatalogs(['path/to/catalog.xml', 'path/to/anotherCatalog.xml']) 20 | * ``` 21 | * @param catalogs - A list of path to XML catalogs 22 | * @returns None 23 | */ 24 | addXMLCatalogs(catalogs: string[]): void; 25 | /** 26 | * Removes XML Catalogs from the extension. 27 | * 28 | * @remarks 29 | * An example is to call this API: 30 | * ```ts 31 | * removeXMLCatalogs(['path/to/catalog.xml', 'path/to/anotherCatalog.xml']) 32 | * ``` 33 | * @param catalogs - A list of path to XML catalogs 34 | * @returns None 35 | */ 36 | removeXMLCatalogs(catalogs: string[]): void; 37 | /** 38 | * Adds XML File Associations in addition to the catalogs defined in the settings.json file. 39 | * 40 | * @remarks 41 | * An example is to call this API: 42 | * ```ts 43 | * addXMLFileAssociations([{ 44 | * "systemId": "path/to/file.xsd", 45 | * "pattern": "file1.xml" 46 | * },{ 47 | * "systemId": "http://www.w3.org/2001/XMLSchema.xsd", 48 | * "pattern": "file2.xml" 49 | * }]) 50 | * ``` 51 | * @param fileAssociations - A list of file association 52 | * @returns None 53 | */ 54 | addXMLFileAssociations(fileAssociations: XMLFileAssociation[]): void; 55 | /** 56 | * Removes XML File Associations from the extension. 57 | * 58 | * @remarks 59 | * An example is to call this API: 60 | * ```ts 61 | * removeXMLFileAssociations([{ 62 | * "systemId": "path/to/file.xsd", 63 | * "pattern": "file1.xml" 64 | * },{ 65 | * "systemId": "http://www.w3.org/2001/XMLSchema.xsd", 66 | * "pattern": "file2.xml" 67 | * }]) 68 | * ``` 69 | * @param fileAssociations - A list of file association 70 | * @returns None 71 | */ 72 | removeXMLFileAssociations(fileAssociations: XMLFileAssociation[]): void; 73 | 74 | } 75 | 76 | /** 77 | * Interface for the FileAssociation shape. 78 | * @param systemId - The path to a valid XSD. 79 | * @param pattern - The file pattern associated with the XSD. 80 | * 81 | * @returns None 82 | */ 83 | export interface XMLFileAssociation { 84 | systemId: string, 85 | pattern: string; 86 | } -------------------------------------------------------------------------------- /src/api/xmlExtensionApiImplementation.ts: -------------------------------------------------------------------------------- 1 | import { DidChangeConfigurationNotification } from "vscode-languageclient"; 2 | import { LanguageClient } from "vscode-languageclient/node"; 3 | import { RequirementsData } from "../server/requirements"; 4 | import { ExternalXmlSettings } from "../settings/externalXmlSettings"; 5 | import { getXMLSettings, onConfigurationChange } from "../settings/settings"; 6 | import { XMLExtensionApi, XMLFileAssociation } from "./xmlExtensionApi"; 7 | 8 | /** 9 | * Returns the implementation of the vscode-xml extension API 10 | * 11 | * @param languageClient 12 | * @param logfile 13 | * @param externalXmlSettings 14 | * @param requirementsData 15 | * @return the implementation of the vscode-xml extension API 16 | */ 17 | export function getXmlExtensionApiImplementation(languageClient: LanguageClient, logfile: string, externalXmlSettings: ExternalXmlSettings, requirementsData: RequirementsData): XMLExtensionApi { 18 | return { 19 | // add API set catalogs to internal memory 20 | addXMLCatalogs: (catalogs: string[]) => { 21 | const externalXmlCatalogs = externalXmlSettings.xmlCatalogs; 22 | catalogs.forEach(element => { 23 | if (!externalXmlCatalogs.includes(element)) { 24 | externalXmlCatalogs.push(element); 25 | } 26 | }); 27 | languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); 28 | onConfigurationChange(); 29 | }, 30 | // remove API set catalogs to internal memory 31 | removeXMLCatalogs: (catalogs: string[]) => { 32 | catalogs.forEach(element => { 33 | const externalXmlCatalogs = externalXmlSettings.xmlCatalogs; 34 | if (externalXmlCatalogs.includes(element)) { 35 | const itemIndex = externalXmlCatalogs.indexOf(element); 36 | externalXmlCatalogs.splice(itemIndex, 1); 37 | } 38 | }); 39 | languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); 40 | onConfigurationChange(); 41 | }, 42 | // add API set fileAssociations to internal memory 43 | addXMLFileAssociations: (fileAssociations: XMLFileAssociation[]) => { 44 | const externalfileAssociations = externalXmlSettings.xmlFileAssociations; 45 | fileAssociations.forEach(element => { 46 | if (!externalfileAssociations.some(fileAssociation => fileAssociation.pattern === element.pattern)) { 47 | externalfileAssociations.push(element); 48 | } 49 | }); 50 | languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); 51 | onConfigurationChange(); 52 | }, 53 | // remove API set fileAssociations to internal memory 54 | removeXMLFileAssociations: (fileAssociations: XMLFileAssociation[]) => { 55 | const externalfileAssociations = externalXmlSettings.xmlFileAssociations; 56 | fileAssociations.forEach(element => { 57 | const itemIndex = externalfileAssociations.findIndex(fileAssociation => fileAssociation.pattern === element.pattern) //returns -1 if item not found 58 | if (itemIndex > -1) { 59 | externalfileAssociations.splice(itemIndex, 1); 60 | } 61 | }); 62 | languageClient.sendNotification(DidChangeConfigurationNotification.type, { settings: getXMLSettings(requirementsData.java_home, logfile, externalXmlSettings) }); 63 | onConfigurationChange(); 64 | } 65 | } as XMLExtensionApi; 66 | } 67 | -------------------------------------------------------------------------------- /src/client/clientErrorHandler.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs-extra"; 2 | import { commands, ConfigurationTarget, ExtensionContext, window, workspace } from "vscode"; 3 | import { CloseAction, CloseHandlerResult, ErrorAction, ErrorHandler, ErrorHandlerResult, Message } from "vscode-languageclient"; 4 | import * as ClientCommandConstants from "../commands/clientCommandConstants"; 5 | import { HEAP_DUMP_LOCATION } from "../server/java/jvmArguments"; 6 | import * as Telemetry from "../telemetry"; 7 | import * as glob from "glob"; 8 | import { totalmem } from "os"; 9 | 10 | /** 11 | * An error handler that restarts the language server, 12 | * unless it has been restarted 5 times in the last 10 minutes, 13 | * or if it crashed due to an Out Of Memory Error 14 | * 15 | * Adapted from [vscode-java](https://github.com/redhat-developer/vscode-java) 16 | */ 17 | export class ClientErrorHandler implements ErrorHandler { 18 | 19 | private restarts: number[]; 20 | private name: string; 21 | private context: ExtensionContext; 22 | private heapDumpFolder: string; 23 | 24 | constructor(name: string, context: ExtensionContext) { 25 | this.name = name; 26 | this.restarts = []; 27 | this.context = context; 28 | this.heapDumpFolder = getHeapDumpFolderFromSettings() || context.globalStorageUri.fsPath; 29 | } 30 | 31 | error(_error: Error, _message: Message, _count: number): ErrorHandlerResult { 32 | return { 33 | action: ErrorAction.Continue 34 | }; 35 | } 36 | 37 | closed(): CloseHandlerResult { 38 | return { 39 | action: this.doClosed() 40 | } 41 | } 42 | 43 | doClosed(): CloseAction { 44 | this.restarts.push(Date.now()); 45 | const heapProfileGlob = new glob.GlobSync(`${this.heapDumpFolder}/java_*.hprof`); 46 | if (heapProfileGlob.found.length) { 47 | // Only clean heap dumps that are generated in the default location. 48 | // The default location is the extension global storage 49 | // This means that if users change the folder where the heap dumps are placed, 50 | // then they will be able to read the heap dumps, 51 | // since they aren't immediately deleted. 52 | cleanUpHeapDumps(this.context); 53 | Telemetry.sendTelemetry(Telemetry.JAVA_OOM_EVT, { 'jvm.xmx': getXmxFromSettings() }); 54 | showOOMMessage(); 55 | return CloseAction.DoNotRestart; 56 | } 57 | if (this.restarts.length < 5) { 58 | return CloseAction.Restart; 59 | } else { 60 | const diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; 61 | if (diff <= 10 * 60 * 1000) { 62 | window.showErrorMessage(`The ${this.name} language server crashed 5 times in the last 10 minutes. The server will not be restarted.`); 63 | return CloseAction.DoNotRestart; 64 | } 65 | this.restarts.shift(); 66 | return CloseAction.Restart; 67 | } 68 | } 69 | 70 | } 71 | 72 | /** 73 | * Deletes all the heap dumps generated by Out Of Memory errors 74 | * 75 | * @returns when the heap dumps have been deleted 76 | */ 77 | export async function cleanUpHeapDumps(context: ExtensionContext): Promise { 78 | const heapProfileGlob = new glob.GlobSync(`${context.globalStorageUri.fsPath}/java_*.hprof`); 79 | for (const heapProfile of heapProfileGlob.found) { 80 | await fs.remove(heapProfile); 81 | } 82 | } 83 | 84 | /** 85 | * Shows a message about the server crashing due to an out of memory issue 86 | */ 87 | async function showOOMMessage(): Promise { 88 | const DOCS = 'More info...'; 89 | const DOUBLE = 'Double allocated memory'; 90 | const result = await window.showErrorMessage('The XML Language Server crashed due to an Out Of Memory Error, and will not be restarted. ', // 91 | DOUBLE, DOCS); 92 | if (result === DOCS) { 93 | Telemetry.sendTelemetry(Telemetry.OPEN_OOM_DOCS_EVT); 94 | await commands.executeCommand(ClientCommandConstants.OPEN_DOCS, 95 | { 96 | page: 'Troubleshooting', 97 | section: 'the-language-server-crashes-due-to-an-out-of-memory-error' 98 | } 99 | ); 100 | } else if (result === DOUBLE) { 101 | doubleAllocatedMemory(); 102 | } 103 | } 104 | 105 | const HEAP_DUMP_FOLDER_EXTRACTOR = new RegExp(`${HEAP_DUMP_LOCATION}(?:'([^']+)'|"([^"]+)"|([^\\s]+))`); 106 | const MAX_HEAP_SIZE_EXTRACTOR = new RegExp(`-Xmx([0-9]+)[kKmMgG]`); 107 | 108 | /** 109 | * Returns the heap dump folder defined in the user's preferences, or undefined if the user does not set the heap dump folder 110 | * 111 | * @returns the heap dump folder defined in the user's preferences, or undefined if the user does not set the heap dump folder 112 | */ 113 | function getHeapDumpFolderFromSettings(): string { 114 | const jvmArgs: string = workspace.getConfiguration('xml.server').get('vmargs'); 115 | const results = HEAP_DUMP_FOLDER_EXTRACTOR.exec(jvmArgs); 116 | if (!results || !results[0]) { 117 | return undefined; 118 | } 119 | return results[1] || results[2] || results[3]; 120 | } 121 | 122 | const XMX_EXTRACTOR = /-Xmx([^\s]+)/; 123 | 124 | /** 125 | * Returns the value that the user set for Xmx, or DEFAULT if the user didn't set Xmx 126 | * 127 | * @returns the value that the user set for Xmx, or DEFAULT if the user didn't set Xmx 128 | */ 129 | function getXmxFromSettings(): string { 130 | const vmargs: string = workspace.getConfiguration('xml.server').get('vmargs', null); 131 | if (vmargs != null) { 132 | const extractOfVmargs: RegExpExecArray = XMX_EXTRACTOR.exec(vmargs); 133 | if (extractOfVmargs.length && extractOfVmargs[1]) { 134 | return extractOfVmargs[1]; 135 | } 136 | } 137 | return 'DEFAULT'; 138 | } 139 | 140 | /** 141 | * Double the memory allocated to lemminx in the vmargs parameter 142 | */ 143 | async function doubleAllocatedMemory() { 144 | let vmargs: string = workspace.getConfiguration('xml.server').get('vmargs', null); 145 | const results = MAX_HEAP_SIZE_EXTRACTOR.exec(vmargs); 146 | if (results && results[0]) { 147 | const maxMemArg: string = results[0]; 148 | const maxMemValue = Number(results[1]); 149 | const newMaxMemArg: string = maxMemArg.replace(maxMemValue.toString(), (maxMemValue * 2).toString()); 150 | vmargs = vmargs.replace(maxMemArg, newMaxMemArg); 151 | await workspace.getConfiguration().update("xml.server.vmargs", vmargs, ConfigurationTarget.Global); 152 | } else { 153 | // by default, many JVM take 1/4 of the physical memory as -Xmx 154 | // in the case it crashes, set -Xmx to half of total physical memory, in megabytes 155 | vmargs = `-Xmx ${Math.trunc(totalmem()/2/1000000)}m ${vmargs}`; 156 | await workspace.getConfiguration().update("xml.server.vmargs", vmargs, ConfigurationTarget.Global); 157 | } 158 | } -------------------------------------------------------------------------------- /src/client/indentation.ts: -------------------------------------------------------------------------------- 1 | import { IndentAction, LanguageConfiguration } from "vscode"; 2 | 3 | export function getIndentationRules(): LanguageConfiguration { 4 | return { 5 | 6 | // indentationRules referenced from: 7 | // https://github.com/microsoft/vscode/blob/d00558037359acceea329e718036c19625f91a1a/extensions/html-language-features/client/src/htmlMain.ts#L114-L115 8 | indentationRules: { 9 | increaseIndentPattern: /<(?!\?|[^>]*\/>)([-_.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!.*<\/\1>)|)|\{[^}"']*$/, 10 | decreaseIndentPattern: /^\s*(<\/[-_.A-Za-z0-9]+\b[^>]*>|-->|\})/ 11 | }, 12 | onEnterRules: [ 13 | { 14 | beforeText: /<(?:[_:\w][_:\w\-.\d]*)(?:(?:[^'"/>]|"[^"]*"|'[^']*')*?(?!\/)>)[^<]*$/i, 15 | afterText: /^<\/(?:[_:\w][_:\w-.\d]*)\s*>/i, 16 | action: { indentAction: IndentAction.IndentOutdent } 17 | }, 18 | { 19 | beforeText: /<(?:\w[\w\d]*)(?:(?:[^'"/>]|"[^"]*"|'[^']*')*?(?!\/)>)[^<]*$/i, 20 | action: { indentAction: IndentAction.Indent } 21 | } 22 | ] 23 | }; 24 | } -------------------------------------------------------------------------------- /src/client/languageParticipants.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { Event, EventEmitter, extensions } from 'vscode'; 7 | import { DocumentFilter, DocumentSelector } from 'vscode-languageclient'; 8 | 9 | const SCHEMES: string[] = [ 10 | 'untitled', 11 | 'file', 12 | 'ftp', 13 | 'http', 14 | 'https', 15 | 'ssh', 16 | 'streamfile', 17 | ]; 18 | 19 | /** 20 | * XML language participant contribution. 21 | */ 22 | interface LanguageParticipantContribution { 23 | /** 24 | * The id of the language which participates with the XML language server. 25 | */ 26 | languageId: string; 27 | } 28 | 29 | export interface LanguageParticipants { 30 | readonly onDidChange: Event; 31 | readonly documentSelector: DocumentSelector; 32 | hasLanguage(languageId: string): boolean; 33 | dispose(): void; 34 | } 35 | 36 | export function getLanguageParticipants(): LanguageParticipants { 37 | const onDidChangeEmmiter = new EventEmitter(); 38 | let languages = new Set(); 39 | 40 | function update() { 41 | const oldLanguages = languages; 42 | 43 | languages = new Set(); 44 | languages.add('xml'); 45 | languages.add('xsl'); 46 | languages.add('dtd'); 47 | languages.add('svg'); 48 | 49 | for (const extension of extensions.all /*extensions.allAcrossExtensionHosts*/) { 50 | const xmlLanguageParticipants = extension.packageJSON?.contributes?.xmlLanguageParticipants as LanguageParticipantContribution[]; 51 | if (Array.isArray(xmlLanguageParticipants)) { 52 | for (const xmlLanguageParticipant of xmlLanguageParticipants) { 53 | const languageId = xmlLanguageParticipant.languageId; 54 | if (typeof languageId === 'string') { 55 | languages.add(languageId); 56 | } 57 | } 58 | } 59 | } 60 | return !isEqualSet(languages, oldLanguages); 61 | } 62 | update(); 63 | 64 | const changeListener = extensions.onDidChange(_ => { 65 | if (update()) { 66 | onDidChangeEmmiter.fire(); 67 | } 68 | }); 69 | 70 | return { 71 | onDidChange: onDidChangeEmmiter.event, 72 | get documentSelector() { 73 | return SCHEMES.flatMap(scheme => { 74 | return Array.from(languages).map(language => { 75 | return { 76 | language, 77 | scheme 78 | } as DocumentFilter; 79 | }); 80 | }); 81 | }, 82 | hasLanguage(languageId: string) { return languages.has(languageId); }, 83 | dispose: () => changeListener.dispose() 84 | }; 85 | } 86 | 87 | function isEqualSet(s1: Set, s2: Set) { 88 | if (s1.size !== s2.size) { 89 | return false; 90 | } 91 | for (const e of s1) { 92 | if (!s2.has(e)) { 93 | return false; 94 | } 95 | } 96 | return true; 97 | } 98 | -------------------------------------------------------------------------------- /src/client/tagClosing.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * 5 | * Retrieved from: https://github.com/Microsoft/vscode/blob/f707828426bd87e88c17d2da34f2ceed0019d8bd/extensions/html-language-features/client/src/tagClosing.ts 6 | *--------------------------------------------------------------------------------------------*/ 7 | 'use strict'; 8 | 9 | import { window, workspace, Disposable, TextDocumentContentChangeEvent, TextDocument, Position, SnippetString, Range } from 'vscode'; 10 | 11 | export interface AutoCloseResult { 12 | snippet: string, 13 | range?: Range 14 | } 15 | 16 | export function activateTagClosing(tagProvider: (document: TextDocument, position: Position) => Thenable, supportedLanguages: { [id: string]: boolean }, configName: string): Disposable { 17 | 18 | const disposables: Disposable[] = []; 19 | workspace.onDidChangeTextDocument(event => onDidChangeTextDocument(event.document, event.contentChanges), null, disposables); 20 | 21 | let isEnabled = false; 22 | updateEnabledState(); 23 | window.onDidChangeActiveTextEditor(updateEnabledState, null, disposables); 24 | 25 | let timeout: NodeJS.Timeout | undefined = undefined; 26 | 27 | function updateEnabledState() { 28 | isEnabled = false; 29 | const editor = window.activeTextEditor; 30 | if (!editor) { 31 | return; 32 | } 33 | const document = editor.document; 34 | if (!supportedLanguages[document.languageId]) { 35 | return; 36 | } 37 | if (!workspace.getConfiguration(undefined, document.uri).get(configName)) { 38 | return; 39 | } 40 | isEnabled = true; 41 | } 42 | 43 | function onDidChangeTextDocument(document: TextDocument, changes: ReadonlyArray) { 44 | if (!isEnabled) { 45 | return; 46 | } 47 | const activeDocument = window.activeTextEditor && window.activeTextEditor.document; 48 | if (document !== activeDocument || changes.length === 0) { 49 | return; 50 | } 51 | if (typeof timeout !== 'undefined') { 52 | clearTimeout(timeout); 53 | } 54 | const lastChange = changes[changes.length - 1]; 55 | const lastCharacter = lastChange.text[lastChange.text.length - 1]; 56 | if (lastChange.rangeLength > 0 || lastCharacter !== '>' && lastCharacter !== '/') { 57 | return; 58 | } 59 | const rangeStart = lastChange.range.start; 60 | const version = document.version; 61 | timeout = setTimeout(() => { 62 | const position = new Position(rangeStart.line, rangeStart.character + lastChange.text.length); 63 | tagProvider(document, position).then(result => { 64 | const text = result?.snippet; 65 | if (text && isEnabled) { 66 | const activeEditor = window.activeTextEditor; 67 | if (activeEditor) { 68 | const activeDocument = activeEditor.document; 69 | if (document === activeDocument && activeDocument.version === version) { 70 | const selections = activeEditor.selections; 71 | if (selections.length > 1 && selections.some(s => s.active.isEqual(position))) { 72 | // multiple cusror case 73 | activeEditor.insertSnippet(new SnippetString(text), selections.map(s => s.active)); 74 | } else { 75 | // no multiple cursor we use the range coming from le LSP closeTag request to support 'xml.completion.autoCloseRemovesContent' setting 76 | activeEditor.insertSnippet(new SnippetString(text), getReplaceLocation(result.range, position)); 77 | } 78 | } 79 | } 80 | } 81 | }, (_reason: any) => { 82 | console.log('xml/closeTag request has been cancelled'); 83 | }); 84 | timeout = void 0; 85 | }, 100); 86 | } 87 | return Disposable.from(...disposables); 88 | } 89 | 90 | function getReplaceLocation(range: Range, position: Position): Range | Position { 91 | if (range != null) { 92 | // re-create Range 93 | let line = range.start.line; 94 | let character = range.start.character; 95 | const startPosition = new Position(line, character); 96 | line = range.end.line; 97 | character = range.end.character; 98 | const endPosition = new Position(line, character); 99 | return new Range(startPosition, endPosition); 100 | } 101 | return position; 102 | } -------------------------------------------------------------------------------- /src/commands/clientCommandConstants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * VScode client commands. 3 | */ 4 | 5 | /** 6 | * Show XML references 7 | */ 8 | export const SHOW_REFERENCES = 'xml.show.references'; 9 | 10 | /** 11 | * Show editor references 12 | */ 13 | export const EDITOR_SHOW_REFERENCES = 'editor.action.showReferences'; 14 | 15 | /** 16 | * Reload VS Code window 17 | */ 18 | export const RELOAD_WINDOW = 'workbench.action.reloadWindow'; 19 | 20 | /** 21 | * Open settings command 22 | * 23 | * A `settingId: string` parameter can be optionally provided 24 | */ 25 | export const OPEN_SETTINGS = 'xml.open.settings'; 26 | 27 | /** 28 | * Open settings command 29 | * 30 | * A `settingId: string` parameter can be optionally provided 31 | */ 32 | export const OPEN_URI = 'xml.open.uri'; 33 | 34 | /** 35 | * Render markdown string to html string 36 | */ 37 | export const MARKDOWN_API_RENDER = 'markdown.api.render'; 38 | 39 | export const OPEN_DOCS = 'xml.open.docs'; 40 | 41 | /** 42 | * Commands to revalidate files with an LSP command on the XML Language Server 43 | */ 44 | export const VALIDATE_CURRENT_FILE = 'xml.validation.current.file'; 45 | 46 | export const VALIDATE_ALL_FILES = 'xml.validation.all.files'; 47 | 48 | export const OPEN_DOCS_HOME = 'xml.open.docs.home'; 49 | 50 | /** 51 | * VSCode client commands to open the binding wizard to bind a XML to a grammar/schema. 52 | */ 53 | export const OPEN_BINDING_WIZARD = 'xml.open.binding.wizard'; 54 | 55 | /** 56 | * VSCode client command to open the grammar/schema binding wizard from command menu. 57 | */ 58 | export const COMMAND_PALETTE_BINDING_WIZARD = 'xml.command.bind.grammar'; 59 | 60 | /** 61 | * Client command to execute an XML command on XML Language Server side. 62 | */ 63 | export const EXECUTE_WORKSPACE_COMMAND = 'xml.workspace.executeCommand'; 64 | 65 | /** 66 | * Command to restart connection to language server. 67 | */ 68 | export const RESTART_LANGUAGE_SERVER = 'xml.restart.language.server'; 69 | 70 | /** 71 | * Command to wrap element. 72 | */ 73 | export const REFACTOR_SURROUND_WITH_TAGS = 'xml.refactor.surround.with.tags'; 74 | 75 | export const REFACTOR_SURROUND_WITH_COMMENTS = 'xml.refactor.surround.with.comments'; 76 | 77 | export const REFACTOR_SURROUND_WITH_CDATA = 'xml.refactor.surround.with.cdata'; -------------------------------------------------------------------------------- /src/commands/lspCommandConstants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * LSP Command Constants. 3 | */ 4 | 5 | /** 6 | * Command to register/unregister catalog. 7 | */ 8 | export const UPDATE_CONFIGURATION = 'xml.update.configuration' 9 | -------------------------------------------------------------------------------- /src/commands/serverCommandConstants.ts: -------------------------------------------------------------------------------- 1 | import * as ClientCommandConstants from "./clientCommandConstants"; 2 | 3 | /** 4 | * XML Language Server commands. 5 | */ 6 | 7 | /** 8 | * Auto close tags 9 | */ 10 | export const AUTO_CLOSE_TAGS = 'xml.completion.autoCloseTags'; 11 | 12 | /** 13 | * Commands to revalidate files with an LSP command on the XML Language Server 14 | */ 15 | export const VALIDATE_CURRENT_FILE = ClientCommandConstants.VALIDATE_CURRENT_FILE; 16 | 17 | export const VALIDATE_ALL_FILES = ClientCommandConstants.VALIDATE_ALL_FILES; 18 | 19 | /** 20 | * Command to associate a grammar in a XML document 21 | */ 22 | export const ASSOCIATE_GRAMMAR_INSERT = "xml.associate.grammar.insert"; 23 | 24 | /** 25 | * Command to check if the current XML document is bound to a grammar 26 | */ 27 | export const CHECK_BOUND_GRAMMAR = "xml.check.bound.grammar"; 28 | 29 | /** 30 | * Command to check if a given file pattern matches any file on the workspace 31 | */ 32 | export const CHECK_FILE_PATTERN = "xml.check.file.pattern"; 33 | 34 | /** 35 | * Command to surround with tags, comments, cdata 36 | */ 37 | export const REFACTOR_SURROUND_WITH = "xml.refactor.surround.with"; -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Red Hat, Inc. and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v2.0 5 | * which accompanies this distribution, and is available at 6 | * https://www.eclipse.org/legal/epl-v20.html 7 | * 8 | * Contributors: 9 | * Red Hat Inc. - initial API and implementation 10 | * Microsoft Corporation - Auto Closing Tags 11 | */ 12 | 13 | import * as fs from 'fs-extra'; 14 | import { ConfigurationTarget, ExtensionContext, Uri, commands, extensions, languages, window, workspace } from "vscode"; 15 | import { Executable, LanguageClient } from 'vscode-languageclient/node'; 16 | import { XMLExtensionApi } from './api/xmlExtensionApi'; 17 | import { getXmlExtensionApiImplementation } from './api/xmlExtensionApiImplementation'; 18 | import { cleanUpHeapDumps } from './client/clientErrorHandler'; 19 | import { getIndentationRules } from './client/indentation'; 20 | import { XML_SUPPORTED_LANGUAGE_IDS, startLanguageClient } from './client/xmlClient'; 21 | import { registerClientOnlyCommands } from './commands/registerCommands'; 22 | import { collectXmlJavaExtensions } from './plugin'; 23 | import * as requirements from './server/requirements'; 24 | import { prepareExecutable } from './server/serverStarter'; 25 | import { ExternalXmlSettings } from "./settings/externalXmlSettings"; 26 | import { getXMLConfiguration } from './settings/settings'; 27 | import * as Telemetry from './telemetry'; 28 | 29 | let languageClient: LanguageClient; 30 | 31 | export async function activate(context: ExtensionContext): Promise { 32 | 33 | await Telemetry.startTelemetry(context); 34 | 35 | registerClientOnlyCommands(context); 36 | 37 | // Update indentation rules for all language which are XML. 38 | XML_SUPPORTED_LANGUAGE_IDS.forEach((languageId: string) => { 39 | languages.setLanguageConfiguration(languageId, getIndentationRules()); 40 | }); 41 | 42 | // Register in the context 'xml.supportedLanguageIds' to use it in command when condition in package.json 43 | commands.executeCommand('setContext', 'xml.supportedLanguageIds', XML_SUPPORTED_LANGUAGE_IDS); 44 | 45 | let requirementsData: requirements.RequirementsData; 46 | try { 47 | requirementsData = await requirements.resolveRequirements(context); 48 | } catch (error) { 49 | if (!workspace.getConfiguration('xml').get('server.preferBinary') && error.message !== requirements.NO_JAVA_FOUND) { 50 | const USE_BINARY = 'Always use binary server'; 51 | void window.showWarningMessage(error.message + ' The binary server will be used instead. Please consider downloading and installing a recent Java runtime, or configuring vscode-xml to always use the binary server.', USE_BINARY, error.label) // 52 | .then(button => { 53 | if (button === error.label) { 54 | commands.executeCommand('vscode.open', error.openUrl); 55 | } else if (button === USE_BINARY) { 56 | workspace.getConfiguration('xml').update('server.preferBinary', true, ConfigurationTarget.Global); 57 | } 58 | }); 59 | } 60 | requirementsData = {} as requirements.RequirementsData; 61 | } 62 | 63 | const storageUri = context.storageUri ?? context.globalStorageUri; 64 | const logfile = Uri.joinPath(storageUri, 'lemminx.log').fsPath; 65 | await fs.ensureDir(context.globalStorageUri.fsPath); 66 | await cleanUpHeapDumps(context); 67 | 68 | const externalXmlSettings: ExternalXmlSettings = new ExternalXmlSettings(); 69 | 70 | const serverOptions: Executable = await prepareExecutable( 71 | requirementsData, collectXmlJavaExtensions(extensions.all, getXMLConfiguration().get("extension.jars", [])), context); 72 | 73 | languageClient = await startLanguageClient(context, serverOptions, logfile, externalXmlSettings, requirementsData); 74 | 75 | return getXmlExtensionApiImplementation(languageClient, logfile, externalXmlSettings, requirementsData); 76 | } 77 | 78 | export async function deactivate(): Promise { 79 | if (languageClient) { 80 | await languageClient.stop(); 81 | languageClient = undefined; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/lsp-commands.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022 Red Hat, Inc. and others. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { commands, ConfigurationTarget, Disposable, workspace, window } from 'vscode'; 18 | import { getDirectoryPath, getRelativePath, getWorkspaceUri } from './utils/fileUtils'; 19 | import * as CommandKind from './commands/lspCommandConstants'; 20 | 21 | /** 22 | * Registers the `CommandKind.UPDATE_CONFIGURATION` command 23 | */ 24 | export function registerConfigurationUpdateCommand(): Disposable { 25 | return commands.registerCommand(CommandKind.UPDATE_CONFIGURATION, resolveConfigurationItemEdit); 26 | } 27 | 28 | function resolveConfigurationItemEdit(configurationItemEdit: ConfigurationItemEdit) { 29 | if (configurationItemEdit.valueKind == ConfigurationItemValueKind.file) { 30 | configurationItemEdit.value = resolveFilePath(configurationItemEdit.value); 31 | } 32 | switch (configurationItemEdit.editType) { 33 | case ConfigurationItemEditType.Add: 34 | addToPreferenceArray(configurationItemEdit.section, configurationItemEdit.value); 35 | break; 36 | case ConfigurationItemEditType.Delete: { 37 | removeFromPreferenceArray(configurationItemEdit.section, configurationItemEdit.value); 38 | } 39 | } 40 | } 41 | 42 | function resolveFilePath(filePath: any): any { 43 | const currentWorkspaceUri = getWorkspaceUri(window.activeTextEditor.document).toString(); 44 | return getDirectoryPath(filePath).includes(currentWorkspaceUri) ? getRelativePath(currentWorkspaceUri, filePath) : filePath; 45 | 46 | } 47 | 48 | function addToPreferenceArray(key: string, value: T): void { 49 | const configArray: T[] = workspace.getConfiguration().get(key, []); 50 | if (configArray.includes(value)) { 51 | return; 52 | } 53 | configArray.push(value); 54 | workspace.getConfiguration().update(key, configArray, ConfigurationTarget.Workspace); 55 | } 56 | 57 | function removeFromPreferenceArray(key: string, value: T): void { 58 | const configArray: T[] = workspace.getConfiguration().get(key, []); 59 | if (!configArray.includes(value)) { 60 | return; 61 | } 62 | const resultPref = configArray.filter(i => i != value); 63 | workspace.getConfiguration().update(key, resultPref, ConfigurationTarget.Workspace); 64 | } 65 | 66 | interface ConfigurationItemEdit { 67 | section: string; 68 | value: any; 69 | editType: ConfigurationItemEditType; 70 | valueKind: ConfigurationItemValueKind; 71 | } 72 | 73 | enum ConfigurationItemEditType { 74 | Add = 0, 75 | Delete = 1 76 | } 77 | 78 | enum ConfigurationItemValueKind { 79 | file = 0 80 | } -------------------------------------------------------------------------------- /src/markdownPreviewProvider.ts: -------------------------------------------------------------------------------- 1 | import { Disposable, WebviewPanel, window, ViewColumn, commands, Uri, Webview, ExtensionContext, env } from "vscode"; 2 | import * as fse from 'fs-extra'; 3 | import * as path from 'path'; 4 | import * as ClientCommandConstants from "./commands/clientCommandConstants"; 5 | 6 | class MarkdownPreviewProvider implements Disposable { 7 | private panel: WebviewPanel | undefined; 8 | // a cache maps document path to rendered html 9 | private documentCache: Map = new Map(); 10 | private disposables: Disposable[] = []; 11 | 12 | public async show(markdownFilePath: string, title: string, section: string, context: ExtensionContext): Promise { 13 | if (!this.panel) { 14 | this.panel = window.createWebviewPanel('xml.markdownPreview', title, ViewColumn.Active, { 15 | localResourceRoots: [ 16 | Uri.file(path.join(context.extensionPath, 'webview-resources')), 17 | Uri.file(path.dirname(markdownFilePath)), 18 | ], 19 | retainContextWhenHidden: true, 20 | enableFindWidget: true, 21 | enableScripts: true, 22 | enableCommandUris: true 23 | }); 24 | } 25 | 26 | this.disposables.push(this.panel.onDidDispose(() => { 27 | this.panel = undefined; 28 | })); 29 | 30 | this.panel.iconPath = Uri.file(path.join(context.extensionPath, 'icons', 'icon128.png')); 31 | this.panel.webview.html = await this.getHtmlContent(this.panel.webview, markdownFilePath, section, context); 32 | this.panel.title = title; 33 | this.panel.reveal(this.panel.viewColumn); 34 | } 35 | 36 | public dispose(): void { 37 | if (this.panel) { 38 | this.panel.dispose(); 39 | } 40 | for (const disposable of this.disposables) { 41 | disposable.dispose(); 42 | } 43 | } 44 | 45 | protected async getHtmlContent(webview: Webview, markdownFilePath: string, section: string, context: ExtensionContext): Promise { 46 | const nonce: string = this.getNonce(); 47 | const styles: string = this.getStyles(webview, context); 48 | let body: string | undefined = this.documentCache.get(markdownFilePath); 49 | if (!body) { 50 | let markdownString: string = await fse.readFile(markdownFilePath, 'utf8'); 51 | markdownString = markdownString.replace(/__VSCODE_ENV_APPNAME_PLACEHOLDER__/, env.appName); 52 | // HACK: This will not replace cross-page links if they don't have a section 53 | // i.e. [here](OtherPage#section) gets replaced, but [here](OtherPage) doesn't 54 | // Captures markdown links like this: [$1]($2#$3) 55 | // where $1, $2, $3 are non empty strings that are then passed to the replace function 56 | markdownString = markdownString.replace(/\[([^\]]+)\]\(([^#)]+)#([^)]*)\)/g, 57 | (_match: string, linkText: string, page: string, section: string) => { 58 | const linkedPageAbsPath = path.join(path.dirname(markdownFilePath), page); 59 | // __dirname resolves to the `dist` folder 60 | const linkedPageRelativePath = path.relative(path.join(__dirname, '..', 'docs'), linkedPageAbsPath); 61 | return `${linkText}` 62 | }); 63 | body = await commands.executeCommand(ClientCommandConstants.MARKDOWN_API_RENDER, markdownString); 64 | this.documentCache.set(markdownFilePath, body); 65 | } 66 | return ` 67 | 68 | 69 | 70 | 71 | 72 | 73 | ${styles} 74 | 75 | 76 | 77 | ${body} 78 | 83 | 95 | 96 | 97 | `; 98 | } 99 | 100 | protected getStyles(webview: Webview, context: ExtensionContext): string { 101 | const styles: Uri[] = [ 102 | Uri.file(path.join(context.extensionPath, 'webview-resources', 'highlight.css')), 103 | Uri.file(path.join(context.extensionPath, 'webview-resources', 'markdown.css')), 104 | Uri.file(path.join(context.extensionPath, 'webview-resources', 'document.css')), 105 | ]; 106 | return styles.map((styleUri: Uri) => ``).join('\n'); 107 | } 108 | 109 | private getNonce(): string { 110 | let text = ""; 111 | const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 112 | for (let i = 0; i < 32; i++) { 113 | text += possible.charAt(Math.floor(Math.random() * possible.length)); 114 | } 115 | return text; 116 | } 117 | } 118 | 119 | export const markdownPreviewProvider: MarkdownPreviewProvider = new MarkdownPreviewProvider(); -------------------------------------------------------------------------------- /src/plugin.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as vscode from 'vscode'; 4 | import * as path from 'path'; 5 | import * as ClientCommandConstants from './commands/clientCommandConstants'; 6 | import * as glob from 'glob'; 7 | 8 | let existingExtensions: Array; 9 | 10 | export function collectXmlJavaExtensions(extensions: readonly vscode.Extension[], jars: string[]): string[] { 11 | const result = []; 12 | if (extensions && extensions.length) { 13 | for (const extension of extensions) { 14 | const contributesSection = extension.packageJSON['contributes']; 15 | if (contributesSection) { 16 | const xmlJavaExtensions = contributesSection['xml.javaExtensions']; 17 | if (Array.isArray(xmlJavaExtensions) && xmlJavaExtensions.length) { 18 | for (const xmLJavaExtensionPath of xmlJavaExtensions) { 19 | result.push(...glob.sync(path.resolve(extension.extensionPath, xmLJavaExtensionPath))); 20 | } 21 | } 22 | } 23 | } 24 | } 25 | for (const extension of jars) { 26 | result.push(...glob.sync(extension)); 27 | } 28 | // Make a copy of extensions: 29 | existingExtensions = result.slice(); 30 | return result; 31 | } 32 | 33 | export function onExtensionChange(extensions: readonly vscode.Extension[], jars: string[]) { 34 | if (!existingExtensions) { 35 | return; 36 | } 37 | const oldExtensions = new Set(existingExtensions.slice()); 38 | const newExtensions = collectXmlJavaExtensions(extensions, jars); 39 | let hasChanged = ( oldExtensions.size !== newExtensions.length); 40 | if (!hasChanged) { 41 | for (const newExtension of newExtensions) { 42 | if (!oldExtensions.has(newExtension)) { 43 | hasChanged = true; 44 | break; 45 | } 46 | } 47 | } 48 | 49 | if (hasChanged) { 50 | const msg = `Extensions to the XML Language Server changed, reloading ${vscode.env.appName} is required for the changes to take effect.`; 51 | const action = 'Reload'; 52 | const restartId = ClientCommandConstants.RELOAD_WINDOW; 53 | vscode.window.showWarningMessage(msg, action).then((selection) => { 54 | if (action === selection) { 55 | vscode.commands.executeCommand(restartId); 56 | } 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/server/binary/binaryHashManager.ts: -------------------------------------------------------------------------------- 1 | import { ConfigurationTarget, workspace } from "vscode"; 2 | 3 | const TRUSTED_HASHES_SETTING_ID = 'xml.server.binary.trustedHashes'; 4 | 5 | /** 6 | * Returns the list of user trusted binary hashes 7 | * 8 | * @returns the list of user trusted binary hashes 9 | */ 10 | export function getTrustedHashes(): string[] { 11 | const trustedHashesValue = workspace.getConfiguration().inspect(TRUSTED_HASHES_SETTING_ID).globalValue; 12 | if (!Array.isArray(trustedHashesValue)) { 13 | return []; 14 | } 15 | return trustedHashesValue as string[]; 16 | } 17 | 18 | 19 | /** 20 | * Add a new hash to the list of trusted binary hashes 21 | * 22 | * @param hash The hash to add to the list of trusted binary hashes 23 | */ 24 | export function addTrustedHash(hash: string): void { 25 | const trustedHashes = getTrustedHashes(); 26 | trustedHashes.push(hash); 27 | workspace.getConfiguration().update(TRUSTED_HASHES_SETTING_ID, trustedHashes, ConfigurationTarget.Global); 28 | } -------------------------------------------------------------------------------- /src/server/java/javaServerStarter.ts: -------------------------------------------------------------------------------- 1 | import * as os from 'os'; 2 | import * as path from 'path'; 3 | import { ExtensionContext, window, workspace } from 'vscode'; 4 | import { Executable } from 'vscode-languageclient/node'; 5 | import { getProxySettings, getProxySettingsAsJVMArgs, jvmArgsContainsProxySettings, ProxySettings } from '../../settings/proxySettings'; 6 | import { getJavaagentFlag, getKey, getXMLConfiguration, IS_WORKSPACE_VMARGS_XML_ALLOWED, xmlServerVmargs } from '../../settings/settings'; 7 | import { RequirementsData } from '../requirements'; 8 | import { HEAP_DUMP_LOCATION, CRASH_ON_OOM, HEAP_DUMP } from './jvmArguments'; 9 | import * as glob from 'glob'; 10 | 11 | // eslint-disable-next-line no-var 12 | declare var v8debug; 13 | 14 | export const DEBUG = (typeof v8debug === 'object') || startedInDebugMode(); 15 | 16 | export async function prepareJavaExecutable( 17 | context: ExtensionContext, 18 | requirements: RequirementsData, 19 | xmlJavaExtensions: string[] 20 | ): Promise { 21 | 22 | return { 23 | command: path.resolve(requirements.java_home + '/bin/java'), 24 | args: prepareParams(requirements, xmlJavaExtensions, context) 25 | } as Executable; 26 | } 27 | 28 | function prepareParams(requirements: RequirementsData, xmlJavaExtensions: string[], context: ExtensionContext): string[] { 29 | const params: string[] = []; 30 | if (DEBUG) { 31 | if (process.env['SUSPEND_SERVER'] === 'true') { 32 | params.push('-agentlib:jdwp=transport=dt_socket,server=y,address=1054'); 33 | } else { 34 | params.push('-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1054,quiet=y'); 35 | } 36 | } 37 | let vmargsCheck = workspace.getConfiguration().inspect(xmlServerVmargs).workspaceValue; 38 | if (vmargsCheck !== undefined) { 39 | const agentFlag = getJavaagentFlag(vmargsCheck); 40 | if (agentFlag !== null) { 41 | const keyVmargs = getKey(IS_WORKSPACE_VMARGS_XML_ALLOWED, context.storagePath, vmargsCheck); 42 | const key = context.globalState.get(keyVmargs); 43 | if (key !== true) { 44 | vmargsCheck = workspace.getConfiguration().inspect(xmlServerVmargs).globalValue; 45 | } 46 | } 47 | } else { 48 | vmargsCheck = getXMLConfiguration().get('server.vmargs'); 49 | } 50 | let vmargs: string; 51 | if (vmargsCheck !== undefined) { 52 | vmargs = vmargsCheck + ''; 53 | } else { 54 | vmargs = ''; 55 | } 56 | 57 | const proxySettings: ProxySettings = getProxySettings(); 58 | if (proxySettings && !jvmArgsContainsProxySettings(vmargs)) { 59 | vmargs += getProxySettingsAsJVMArgs(proxySettings); 60 | } 61 | 62 | if (os.platform() == 'win32') { 63 | const watchParentProcess = '-DwatchParentProcess='; 64 | if (vmargs.indexOf(watchParentProcess) < 0) { 65 | params.push(watchParentProcess + 'false'); 66 | } 67 | } 68 | if (vmargs.indexOf(CRASH_ON_OOM) < 0) { 69 | params.push(CRASH_ON_OOM); 70 | } 71 | if (vmargs.indexOf(HEAP_DUMP) < 0) { 72 | params.push(HEAP_DUMP); 73 | } 74 | if (vmargs.indexOf(HEAP_DUMP_LOCATION) < 0) { 75 | params.push(`${HEAP_DUMP_LOCATION}${context.globalStorageUri.fsPath}`); 76 | } else { 77 | window.showWarningMessage('Heap dump location has been modified. ' 78 | + 'vscode-xml won\'t delete the heap dumps. ' 79 | + 'vscode-xml\'s Out Of Memory detection won\'t work properly, ' 80 | + 'unless you manually delete the heap dumps after each Out Of Memory crash.'); 81 | } 82 | 83 | // "OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify 84 | // were deprecated in JDK 13 and will likely be removed in a future release." 85 | // so only add -noverify for older versions 86 | if (params.indexOf('-noverify') < 0 && params.indexOf('-Xverify:none') < 0 && requirements.java_version < 13) { 87 | params.push('-noverify'); 88 | } 89 | parseVMargs(params, vmargs); 90 | const server_home: string = path.resolve(__dirname, '../server'); 91 | const launchersFound: Array = glob.sync('**/org.eclipse.lemminx*-uber.jar', { cwd: server_home }); 92 | if (launchersFound.length) { 93 | let xmlJavaExtensionsClasspath = ''; 94 | if (xmlJavaExtensions.length > 0) { 95 | const pathSeparator = os.platform() == 'win32' ? ';' : ':'; 96 | xmlJavaExtensionsClasspath = pathSeparator + xmlJavaExtensions.join(pathSeparator); 97 | } 98 | params.push('-cp'); params.push(path.resolve(server_home, launchersFound[0]) + xmlJavaExtensionsClasspath); 99 | params.push('org.eclipse.lemminx.XMLServerLauncher'); 100 | } else { 101 | return null; 102 | } 103 | return params; 104 | } 105 | 106 | function startedInDebugMode(): boolean { 107 | const args = (process as any).execArgv as string[]; 108 | return hasDebugFlag(args); 109 | } 110 | 111 | function hasDebugFlag(args: string[]): boolean { 112 | if (args) { 113 | // See https://nodejs.org/en/docs/guides/debugging-getting-started/ 114 | return args.some(arg => /^--inspect/.test(arg) || /^--debug/.test(arg)); 115 | } 116 | return false; 117 | } 118 | 119 | //exported for tests 120 | export function parseVMargs(params: any[], vmargsLine: string) { 121 | if (!vmargsLine) { 122 | return; 123 | } 124 | const vmargs = vmargsLine.match(/(?:[^\s"]+|"[^"]*")+/g); 125 | if (vmargs === null) { 126 | return; 127 | } 128 | vmargs.forEach(arg => { 129 | //remove all standalone double quotes 130 | arg = arg.replace(/(\\)?"/g, function ($0, $1) { return ($1 ? $0 : ''); }); 131 | //unescape all escaped double quotes 132 | arg = arg.replace(/(\\)"/g, '"'); 133 | if (params.indexOf(arg) < 0) { 134 | params.push(arg); 135 | } 136 | }); 137 | } 138 | -------------------------------------------------------------------------------- /src/server/java/jvmArguments.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Red Hat, Inc. and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v2.0 5 | * which accompanies this distribution, and is available at 6 | * https://www.eclipse.org/legal/epl-v20.html 7 | * 8 | * Contributors: 9 | * Red Hat Inc. - initial API and implementation 10 | */ 11 | 12 | /** 13 | * Argument that tells the program where to generate the heap dump that is created when an OutOfMemoryError is raised and `HEAP_DUMP` has been passed 14 | */ 15 | export const HEAP_DUMP_LOCATION = '-XX:HeapDumpPath='; 16 | 17 | /** 18 | * Argument that tells the program to crash when an OutOfMemoryError is raised 19 | */ 20 | export const CRASH_ON_OOM = '-XX:+ExitOnOutOfMemoryError'; 21 | 22 | /** 23 | * Argument that tells the program to generate a heap dump file when an OutOfMemoryError is raised 24 | */ 25 | export const HEAP_DUMP = '-XX:+HeapDumpOnOutOfMemoryError'; 26 | -------------------------------------------------------------------------------- /src/server/serverStarter.ts: -------------------------------------------------------------------------------- 1 | import { commands, ConfigurationTarget, ExtensionContext, window } from "vscode"; 2 | import { Executable } from "vscode-languageclient/node"; 3 | import { getXMLConfiguration } from "../settings/settings"; 4 | import * as Telemetry from "../telemetry"; 5 | import { ABORTED_ERROR, prepareBinaryExecutable } from "./binary/binaryServerStarter"; 6 | import { prepareJavaExecutable } from "./java/javaServerStarter"; 7 | import { getOpenJDKDownloadLink, RequirementsData } from "./requirements"; 8 | 9 | /** 10 | * Returns the executable to use to launch LemMinX (the XML Language Server) 11 | * 12 | * @param requirements the java information, or an empty object if there is no java 13 | * @param xmlJavaExtensions a list of all the java extension jars 14 | * @param context the extensions context 15 | * @throws if neither the binary nor the java version of the extension can be launched 16 | * @returns the executable to launch LemMinX with (the XML language server) 17 | */ 18 | export async function prepareExecutable( 19 | requirements: RequirementsData, 20 | xmlJavaExtensions: string[], 21 | context: ExtensionContext): Promise { 22 | 23 | const hasJava: boolean = requirements.java_home !== undefined; 24 | const hasExtensions: boolean = xmlJavaExtensions.length !== 0; 25 | const preferBinary: boolean = getXMLConfiguration().get("server.preferBinary", false); 26 | const silenceExtensionWarning: boolean = getXMLConfiguration().get("server.silenceExtensionWarning", false); 27 | 28 | const useBinary: boolean = (!hasJava) || (preferBinary && !hasExtensions); 29 | 30 | if (hasExtensions && !hasJava && !silenceExtensionWarning) { 31 | const DOWNLOAD_JAVA = 'Get Java'; 32 | const CONFIGURE_JAVA = 'More Info'; 33 | const DISABLE_WARNING = 'Disable Warning'; 34 | window.showInformationMessage('Extensions to the XML language server were detected, but no Java was found. ' 35 | + 'In order to use these extensions, please install and configure a Java runtime (Java 11 or more recent).', 36 | DOWNLOAD_JAVA, CONFIGURE_JAVA, DISABLE_WARNING) 37 | .then((selection: string) => { 38 | if (selection === DOWNLOAD_JAVA) { 39 | Telemetry.sendTelemetry(Telemetry.OPEN_JAVA_DOWNLOAD_LINK_EVT).then(() => { 40 | commands.executeCommand('vscode.open', getOpenJDKDownloadLink()); 41 | }); 42 | } else if (selection === CONFIGURE_JAVA) { 43 | commands.executeCommand('xml.open.docs', { page: 'Preferences.md', section: 'java-home' }); 44 | } else if (selection === DISABLE_WARNING) { 45 | getXMLConfiguration().update('server.silenceExtensionWarning', true, ConfigurationTarget.Global); 46 | } 47 | }); 48 | } 49 | 50 | if (useBinary) { 51 | return prepareBinaryExecutable(context) 52 | .catch((e) => { 53 | const javaServerMessage = hasJava ? 'Falling back to the Java server.' : 'Cannot start XML language server, since Java is missing.'; 54 | if (e === ABORTED_ERROR) { 55 | window.showWarningMessage(`${e.message}. ${javaServerMessage}`); 56 | } else { 57 | window.showErrorMessage(`${e}. ${javaServerMessage}`); 58 | } 59 | if (!hasJava) { 60 | throw new Error("Failed to launch binary XML language server and no Java is installed"); 61 | } 62 | return prepareJavaExecutable(context, requirements, xmlJavaExtensions); 63 | }); 64 | } 65 | return prepareJavaExecutable(context, requirements, xmlJavaExtensions); 66 | } 67 | -------------------------------------------------------------------------------- /src/settings/externalXmlSettings.ts: -------------------------------------------------------------------------------- 1 | import { XMLFileAssociation } from "../api/xmlExtensionApi"; 2 | 3 | /** 4 | * Represents vscode-xml settings that other vscode extensions can contribute to 5 | */ 6 | export class ExternalXmlSettings { 7 | 8 | private _xmlCatalogs: string[] 9 | private _xmlFileAssociations: XMLFileAssociation[] 10 | 11 | constructor() { 12 | this._xmlCatalogs = []; 13 | this._xmlFileAssociations = []; 14 | } 15 | 16 | get xmlCatalogs(): string[] { 17 | return this._xmlCatalogs; 18 | } 19 | 20 | get xmlFileAssociations(): any[] { 21 | return this._xmlFileAssociations; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/settings/proxySettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 Red Hat, Inc. and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v2.0 5 | * which accompanies this distribution, and is available at 6 | * https://www.eclipse.org/legal/epl-v20.html 7 | * 8 | * Contributors: 9 | * Red Hat Inc. - initial API and implementation 10 | */ 11 | import { workspace } from 'vscode'; 12 | 13 | /** 14 | * Represents the information needed to communicate through a proxy 15 | */ 16 | export class ProxySettings { 17 | 18 | private _host: string; 19 | private _port: string; 20 | private _auth?: ProxyAuthorization; 21 | 22 | constructor(host: string, port: string, auth?: ProxyAuthorization) { 23 | this._host = host; 24 | this._port = port; 25 | this._auth = auth; 26 | } 27 | 28 | get host(): string { 29 | return this._host; 30 | } 31 | 32 | get port(): string { 33 | return this._port; 34 | } 35 | 36 | get auth(): ProxyAuthorization { 37 | return this._auth; 38 | } 39 | 40 | } 41 | 42 | /** 43 | * Represents the information needed to authenticate with the proxy 44 | */ 45 | export class ProxyAuthorization { 46 | 47 | private _username: string; 48 | private _password: string; 49 | 50 | constructor(username: string, password: string) { 51 | this._username = username; 52 | this._password = password; 53 | } 54 | 55 | get username(): string { 56 | return this._username 57 | } 58 | 59 | get password(): string { 60 | return this._password; 61 | } 62 | 63 | } 64 | 65 | 66 | /** 67 | * Returns the proxy settings that are declared in the VS Code settings, or null if no proxy is configured 68 | * 69 | * @throws if the proxy settings aren't in the expected format 70 | * @returns the proxy settings that are declared in the VS Code settings, or null if no proxy is configured 71 | */ 72 | export function getProxySettings(): ProxySettings { 73 | const proxyAddress = getProxyAddress(); 74 | if (!proxyAddress) { 75 | return null; 76 | } 77 | const regexResult = HOST_AND_PORT_EXTRACTOR.exec(proxyAddress); 78 | if (!regexResult || !regexResult[1]) { 79 | return null; 80 | } 81 | const host: string = regexResult[1]; 82 | const port: string = regexResult[2] ? regexResult[2] : "80"; 83 | 84 | const proxyAuthorizationString = getProxyAuthorization(); 85 | if (!proxyAuthorizationString) { 86 | return new ProxySettings(host, port); 87 | } 88 | if (proxyAuthorizationString.indexOf(' ') === -1) { 89 | throw new Error('A space is expected in the Authorization header between the authorization method and encoded username/password'); 90 | } 91 | 92 | const encodedUserAndPass = proxyAuthorizationString.split(' ').pop(); 93 | const decodedUserAndPass: string = Buffer.from(encodedUserAndPass, 'base64').toString('utf8'); 94 | if (decodedUserAndPass.indexOf(':') === -1) { 95 | throw new Error('Authorization header is not in the expected format'); 96 | } 97 | const [uriEncodedUsername, uriEncodedPassword] = decodedUserAndPass.split(':'); 98 | const proxyAuthorization = new ProxyAuthorization(decodeURIComponent(uriEncodedUsername), decodeURIComponent(uriEncodedPassword)); 99 | return new ProxySettings(host, port, proxyAuthorization); 100 | } 101 | 102 | /** 103 | * Returns the proxy settings as arguments for the JVM 104 | * 105 | * eg. -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttp.proxyUser= -Dhttp.proxyPassword= 106 | * 107 | * @param proxySettings the proxy settings to convert into JVM args 108 | */ 109 | export function getProxySettingsAsJVMArgs(proxySettings: ProxySettings): string { 110 | // Java doesn't recognize localhost in the proxy settings 111 | const adaptedHostName = 'localhost'.startsWith(proxySettings.host) ? '127.0.0.1' : proxySettings.host; 112 | let proxyJVMArgs: string = ` -Dhttp.proxyHost=${adaptedHostName} -Dhttp.proxyPort=${proxySettings.port}` 113 | + ` -Dhttps.proxyHost=${adaptedHostName} -Dhttps.proxyPort=${proxySettings.port} `; 114 | if (proxySettings.auth) { 115 | proxyJVMArgs += ` -Dhttp.proxyUser=${proxySettings.auth.username} -Dhttp.proxyPassword=${proxySettings.auth.password}` 116 | + ` -Dhttps.proxyUser=${proxySettings.auth.username} -Dhttps.proxyPassword=${proxySettings.auth.password} `; 117 | } 118 | return proxyJVMArgs; 119 | } 120 | 121 | /** 122 | * Returns the proxy settings as environment variables for LemMinX 123 | * 124 | * @param proxySettings the proxy settings to convert into environment variables 125 | * @returns the proxy settings as environment variables for LemMinX 126 | */ 127 | export function getProxySettingsAsEnvironmentVariables(proxySettings: ProxySettings): Record { 128 | // process.env inherits from Object, so it's okay to do so here as well 129 | const proxyEnv: Record = {}; 130 | 131 | proxyEnv['HTTP_PROXY_HOST'] = proxySettings.host; 132 | proxyEnv['HTTP_PROXY_PORT'] = proxySettings.port; 133 | 134 | if (proxySettings.auth) { 135 | proxyEnv['HTTP_PROXY_USERNAME'] = proxySettings.auth.username; 136 | proxyEnv['HTTP_PROXY_PASSWORD'] = proxySettings.auth.password; 137 | } 138 | 139 | return proxyEnv; 140 | } 141 | 142 | /** 143 | * Checks if the given JVM arguments contain any proxy configuration 144 | * 145 | * @param jvmArgs the arguments being passed to the JVM 146 | */ 147 | export function jvmArgsContainsProxySettings(jvmArgs: string): boolean { 148 | return ( 149 | [JVM_PROXY_HOST, JVM_PROXY_PORT, JVM_PROXY_USER, JVM_PROXY_PASS] // 150 | .map(prop => jvmArgs.indexOf(`-D${prop}`) !== -1) 151 | .reduce((a, b, _index, _array) => a || b, false) 152 | ); 153 | } 154 | 155 | const HOST_AND_PORT_EXTRACTOR = /(?:https?:\/\/)?([^:/]+)(?::([0-9]+))?/; 156 | 157 | const JVM_PROXY_HOST = 'http.proxyHost'; 158 | const JVM_PROXY_PORT = 'http.proxyPort'; 159 | const JVM_PROXY_USER = 'http.proxyUser'; 160 | const JVM_PROXY_PASS = 'http.proxyPassword'; 161 | 162 | /** 163 | * Returns the address of the proxy 164 | * 165 | * @returns the address of the proxy 166 | */ 167 | function getProxyAddress(): string { 168 | const fromSettings = workspace.getConfiguration('http').get('proxy', undefined); 169 | if (fromSettings) { 170 | return fromSettings; 171 | } 172 | // VS Code allows you to set up the proxy using the environment variables http_proxy and https_proxy 173 | // Use this as fallback if the `"http.proxy"` setting isn't set 174 | return process.env['http_proxy']; 175 | } 176 | 177 | /** 178 | * Returns the Proxy-Authorization to use to access the proxy 179 | * 180 | * @returns The Proxy-Authorization to use to access the proxy 181 | */ 182 | function getProxyAuthorization(): string { 183 | return workspace.getConfiguration('http').get('proxyAuthorization', undefined); 184 | } -------------------------------------------------------------------------------- /src/settings/variableSubstitution.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { window } from "vscode"; 3 | import { getFilePath, getWorkspaceUri } from "../utils/fileUtils"; 4 | import { XMLFileAssociation } from "../api/xmlExtensionApi"; 5 | 6 | /** 7 | * Represents a variable that refers to a value that can be resolved 8 | */ 9 | class VariableSubstitution { 10 | 11 | private varName: string; 12 | private varKind: VariableSubstitutionKind; 13 | private getValue: (currentFileUri: string, currentWorkspaceUri: string) => string; 14 | private replaceRegExp: RegExp | undefined; 15 | 16 | /** 17 | * 18 | * @param name the name of this variable 19 | * @param kind the kind of this variable 20 | * @param getValue a function that resolves the value of the variable 21 | */ 22 | constructor(name: string, kind: VariableSubstitutionKind, getValue: (currentFileUri: string, currentWorkspaceUri: string) => string) { 23 | this.varName = name; 24 | this.varKind = kind; 25 | this.getValue = getValue; 26 | } 27 | 28 | public get name(): string { 29 | return this.varName; 30 | } 31 | 32 | public get kind(): VariableSubstitutionKind { 33 | return this.varKind; 34 | } 35 | 36 | /** 37 | * Returns the string with the references to this variable replaced with the value, or the original string if the value cannot be resolved 38 | * 39 | * @param original the string to substitute variable value 40 | * @param currentFileUri the uri of the currently focused file, as a string 41 | * @param currentWorkspaceUri the uri of the root of the currently open workspace, as a string 42 | * @returns the string with the references to this variable replaced with the value, or the original string if the value cannot be resolved 43 | */ 44 | public substituteString(original: string, currentFileUri: string, currentWorkspaceUri: string): string { 45 | const value: string = this.getValue(currentFileUri, currentWorkspaceUri); 46 | return value ? original.replace(this.getReplaceRegExp(), value) : original; 47 | } 48 | 49 | /** 50 | * Returns a regex that matches all references to the variable 51 | * 52 | * Lazily initialized 53 | * 54 | * @returns a regex that matches all references to the variable 55 | */ 56 | public getReplaceRegExp(): RegExp { 57 | if (!this.replaceRegExp) { 58 | this.replaceRegExp = new RegExp('\\$\\{' + `${this.name}` + '\\}', 'g'); 59 | } 60 | return this.replaceRegExp; 61 | } 62 | } 63 | 64 | enum VariableSubstitutionKind { 65 | Workspace, 66 | File 67 | } 68 | 69 | // A list of all variable substitutions. To add a new variable substitution, add an entry to this list 70 | const VARIABLE_SUBSTITUTIONS: VariableSubstitution[] = [ 71 | new VariableSubstitution( 72 | "workspaceFolder", 73 | VariableSubstitutionKind.Workspace, 74 | (currentFileUri: string, currentWorkspaceUri: string): string => { 75 | return currentWorkspaceUri; 76 | } 77 | ), 78 | new VariableSubstitution( 79 | "fileDirname", 80 | VariableSubstitutionKind.File, 81 | (currentFileUri: string, _currentWorkspaceUri: string): string => { 82 | return path.dirname(currentFileUri); 83 | } 84 | ), 85 | new VariableSubstitution( 86 | "fileBasenameNoExtension", 87 | VariableSubstitutionKind.File, 88 | (currentFileUri: string, _currentWorkspaceUri: string): string => { 89 | return path.basename(currentFileUri, path.extname(currentFileUri)); 90 | } 91 | ) 92 | ]; 93 | 94 | /** 95 | * Returns the file associations with as many variable references resolved as possible 96 | * 97 | * @param associations the file associations to resolve the variable references in 98 | * @returns the file associations with as many variable references resolved as possible 99 | */ 100 | export function getVariableSubstitutedAssociations(associations: XMLFileAssociation[]): XMLFileAssociation[] { 101 | 102 | // Collect properties needed to resolve variables 103 | const currentFile = (window.activeTextEditor && window.activeTextEditor.document && window.activeTextEditor.document.languageId === 'xml') ? window.activeTextEditor.document : undefined; 104 | const currentFileUri = getFilePath(currentFile); 105 | const currentWorkspaceUri = getWorkspaceUri(currentFile); 106 | 107 | // Remove variables that can't be resolved 108 | let variablesToSubstitute = VARIABLE_SUBSTITUTIONS; 109 | if (!currentWorkspaceUri) { 110 | variablesToSubstitute = variablesToSubstitute.filter(variable => { return variable.kind !== VariableSubstitutionKind.Workspace }); 111 | } 112 | if (!currentFileUri) { 113 | variablesToSubstitute = variablesToSubstitute.filter(variable => { return variable.kind !== VariableSubstitutionKind.File }); 114 | } 115 | 116 | /** 117 | * Returns the string with the values for all the variables that can be resolved substituted in the string 118 | * 119 | * @param val the value to substitute the variables into 120 | * @return the string with the values for all the variables that can be resolved substituted in the string 121 | */ 122 | const subVars = (val: string): string => { 123 | let newVal = val; 124 | for (const settingVariable of variablesToSubstitute) { 125 | newVal = settingVariable.substituteString(newVal, currentFileUri, currentWorkspaceUri?.toString()); 126 | } 127 | return newVal; 128 | } 129 | 130 | return associations.map((association: XMLFileAssociation) => { 131 | return { 132 | pattern: subVars(association.pattern), 133 | systemId: subVars(association.systemId) 134 | }; 135 | }); 136 | } 137 | 138 | /** 139 | * Returns true if any of the file associations contain references to variables that refer to current file, and false otherwise 140 | * 141 | * @param associations A list of file associations to check 142 | * @returns true if any of the file associations contain references to variables that refer to current file, and false otherwise 143 | */ 144 | export function containsVariableReferenceToCurrentFile(associations: XMLFileAssociation[]): boolean { 145 | const fileVariables: VariableSubstitution[] = VARIABLE_SUBSTITUTIONS.filter(variable => variable.kind === VariableSubstitutionKind.File); 146 | for (const association of associations) { 147 | for (const variable of fileVariables) { 148 | if (variable.getReplaceRegExp().test(association.pattern) || variable.getReplaceRegExp().test(association.systemId)) { 149 | return true; 150 | } 151 | } 152 | } 153 | return false; 154 | } 155 | -------------------------------------------------------------------------------- /src/telemetry.ts: -------------------------------------------------------------------------------- 1 | import { getRedHatService, TelemetryService } from "@redhat-developer/vscode-redhat-telemetry"; 2 | import { ExtensionContext } from "vscode"; 3 | import { getXMLConfiguration } from "./settings/settings"; 4 | 5 | /** 6 | * Wrap vscode-redhat-telemetry to suit vscode-xml 7 | */ 8 | 9 | export const OPEN_JAVA_DOWNLOAD_LINK_EVT = "xml.open.java.download.link"; 10 | export const OPEN_PROXY_CONFIG_DOCS_EVT = "xml.open.proxy.config.docs.link"; 11 | export const OPEN_OOM_DOCS_EVT = "xml.open.oom.docs.link"; 12 | export const SETTINGS_EVT = "xml.settings"; 13 | export const BINARY_DOWNLOAD_EVT = "xml.binary.download"; 14 | export const JAVA_OOM_EVT = "xml.java.oom"; 15 | export const STARTUP_EVT = "startup"; 16 | export const SERVER_INITIALIZED_EVT = "server.initialized"; 17 | 18 | export const BINARY_DOWNLOAD_STATUS_PROP = "status"; 19 | 20 | export const BINARY_DOWNLOAD_SUCCEEDED = "succeeded"; 21 | export const BINARY_DOWNLOAD_FAILED = "failed"; 22 | export const BINARY_DOWNLOAD_ABORTED = "aborted"; 23 | 24 | let _telemetryManager: TelemetryService = null; 25 | let serverInitializedReceived = false; 26 | 27 | /** 28 | * Starts the telemetry service 29 | * 30 | * @returns when the telemetry service has been started 31 | * @throws Error if the telemetry service has already been started 32 | */ 33 | export async function startTelemetry(context: ExtensionContext): Promise { 34 | if (_telemetryManager) { 35 | throw new Error("The telemetry service for vscode-xml has already been started") 36 | } 37 | const redhatService = await getRedHatService(context); 38 | _telemetryManager = await redhatService.getTelemetryService(); 39 | setTimeout(sendEmptyStartUp, 15000); 40 | return; 41 | } 42 | 43 | function sendEmptyStartUp() { 44 | if (!serverInitializedReceived) { 45 | return sendTelemetry(STARTUP_EVT, { 46 | "xml.settings.preferBinary": (getXMLConfiguration()['server']['preferBinary'] as boolean) 47 | }); 48 | } 49 | } 50 | 51 | /** 52 | * Send a telemetry event with the given name and data 53 | * 54 | * @param eventName the name of the telemetry event 55 | * @param data the telemetry data 56 | * @throws Error if the telemetry service has not been started yet 57 | */ 58 | export async function sendTelemetry(eventName: string, data?: any): Promise { 59 | if (!_telemetryManager) { 60 | throw new Error("The telemetry service for vscode-xml has not been started yet"); 61 | } 62 | if (eventName === STARTUP_EVT) { 63 | serverInitializedReceived = true; 64 | } 65 | return _telemetryManager.send({ 66 | name: eventName, 67 | properties: data 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /src/test/smoke.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2025 Red Hat, Inc. and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v2.0 5 | * which accompanies this distribution, and is available at 6 | * https://www.eclipse.org/legal/epl-v20.html 7 | * 8 | * Contributors: 9 | * Red Hat Inc. - initial API and implementation 10 | */ 11 | import * as assert from 'assert'; 12 | import * as vscode from 'vscode'; 13 | import * as fs from 'fs/promises'; 14 | import { tmpdir } from 'os'; 15 | import * as path from 'path'; 16 | 17 | suite('Smoke tests', function () { 18 | 19 | this.timeout(10_000); 20 | 21 | // diagnostics take some time to appear; the language server must be started and respond to file open event 22 | const DIAGNOSTICS_DELAY = 4_000; 23 | 24 | const SCHEMA = ` 25 | 27 | 28 | 29 | 30 | 31 | Size Type documentation 32 | 33 | 34 | 35 | 36 | 37 | Small documentation 38 | 39 | 40 | 41 | 42 | Medium documentation 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | `; 72 | 73 | const SCHEMA_INSTANCE = ` 74 | 75 | purple 76 | `; 77 | 78 | const SCHEMA_FILENAME = "dressSize.xsd"; 79 | const SCHEMA_INSTANCE_NAME = "references-schema.xml"; 80 | 81 | let tempDir: string; 82 | let schemaPath: string; 83 | let schemaInstancePath: string; 84 | 85 | this.beforeAll(async function () { 86 | tempDir = tmpdir(); 87 | schemaPath = path.join(tempDir, SCHEMA_FILENAME); 88 | schemaInstancePath = path.join(tempDir, SCHEMA_INSTANCE_NAME); 89 | await fs.appendFile(schemaPath, SCHEMA); 90 | await fs.appendFile(schemaInstancePath, SCHEMA_INSTANCE); 91 | }); 92 | 93 | this.afterAll(async function () { 94 | await fs.rm(schemaPath); 95 | await fs.rm(schemaInstancePath); 96 | }); 97 | 98 | test("instance has right diagnostics", async function () { 99 | const textDocument = await vscode.workspace.openTextDocument(schemaInstancePath); 100 | await vscode.window.showTextDocument(textDocument); 101 | await new Promise(resolve => setTimeout(resolve, DIAGNOSTICS_DELAY)); 102 | const diagnostics = vscode.languages.getDiagnostics(vscode.Uri.file(schemaInstancePath)); 103 | 104 | assert.strictEqual(diagnostics.length, 2); 105 | assert.strictEqual(diagnostics[0].message, "cvc-datatype-valid.1.2.3: 'purple' is not a valid value of union type 'SizeType'.", ); 106 | assert.strictEqual(diagnostics[1].message, "cvc-type.3.1.3: The value 'purple' of element 'dresssize' is not valid."); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /src/utils/fileUtils.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { TextDocument, Uri, workspace, WorkspaceFolder } from "vscode"; 3 | 4 | /** 5 | * Return the current workspace uri from root 6 | * 7 | * @param document the opened TextDocument 8 | * @returns the path from root of the current workspace 9 | */ 10 | export function getWorkspaceUri(document: TextDocument): Uri | undefined { 11 | const currentWorkspace: WorkspaceFolder = (document && document.uri) ? workspace.getWorkspaceFolder(document.uri) : undefined; 12 | return ((currentWorkspace && currentWorkspace.uri) || (workspace.workspaceFolders && workspace.workspaceFolders.length > 0 && workspace.workspaceFolders[0].uri)); 13 | } 14 | 15 | /** 16 | * Return the uri of the current file 17 | * 18 | * @param document the opened TextDocument 19 | * @returns the uri of the current file 20 | */ 21 | export function getFilePath(document: TextDocument): string { 22 | return (document && document.uri) ? document.uri.fsPath : undefined; 23 | } 24 | 25 | /** 26 | * Uses path to return a basename from a uri 27 | * 28 | * @param filePath the uri of the file 29 | * @return the filename 30 | */ 31 | export function getFileName(filePath: string): string { 32 | return path.basename(filePath); 33 | } 34 | 35 | /** 36 | * Return the relative file path between a start and destination uri 37 | * 38 | * @param startPath the absolute path of the beginning directory 39 | * @param destinationPath the absolute path of destination file 40 | * @returns the path to the destination relative to the start 41 | */ 42 | export function getRelativePath(startPath: string, destinationPath: string): string { 43 | return path.relative(path.normalize(startPath), path.normalize(destinationPath)).replace(/\\/g, '/'); 44 | } 45 | 46 | /** 47 | * Uses path to return the directory name from a uri 48 | * 49 | * @param filePath the uri of the file 50 | * @return the directory path 51 | */ 52 | export function getDirectoryPath(filePath: string): string { 53 | return path.dirname(filePath); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /syntaxes/dtd.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DTD", 3 | "scopeName": "text.xml.dtd", 4 | "fileTypes": [ 5 | "dtd" 6 | ], 7 | "patterns": [ 8 | { 9 | "begin": "()", 19 | "name": "meta.tag.type.dtd", 20 | "patterns": [ 21 | { 22 | "match": "\\s+(CDATA|IDREFS|IDREF|ID|NMTOKENS|NMTOKEN|ENTITY|ENTITIES|NOTATION|SYSTEM|NDATA)", 23 | "name": "keyword.other.data-type.dtd" 24 | }, 25 | { 26 | "match": "(#[A-Z]+)|(ANY)|(EMPTY)", 27 | "name": "constant.language.dtd" 28 | }, 29 | { 30 | "begin": "'|\"", 31 | "end": "'|\"", 32 | "name": "string.quoted.double.dtd" 33 | }, 34 | { 35 | "begin": "(%[a-zA-Z][a-zA-Z0-9_-])", 36 | "end": ";", 37 | "name": "variable.language.dtd" 38 | } 39 | ] 40 | }, 41 | { 42 | "begin": "()", 44 | "name": "comment.block.dtd" 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /syntaxes/rnc.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["rnc"], 3 | "foldingStartMarker": "\\{\\s*$", 4 | "foldingStopMarker": "^\\s*\\}", 5 | "name": "RelaxNG Compact", 6 | "patterns": [ 7 | { 8 | "match": "\\bgrammar\\b", 9 | "name": "keyword.other.grammar.rnc" 10 | }, 11 | { 12 | "match": "\\bstart\\b", 13 | "name": "keyword.other.start.rnc" 14 | }, 15 | { 16 | "match": "\\b(text|empty|xsd\\:(int|integer|double|date(Time)?|time|string|decimal))\\b", 17 | "name": "storage.type.rnc" 18 | }, 19 | { 20 | "captures": 21 | { 22 | "1": 23 | { 24 | "name": "keyword.other.attribute.rnc" 25 | }, 26 | "2": 27 | { 28 | "name": "entity.other.attribute.rnc" 29 | } 30 | }, 31 | "match": "\\b(attribute)\\s+([a-zA-Z][-a-zA-Z_0-9]*)\\s*\\{", 32 | "name": "meta.declaration.attribute.rnc" 33 | }, 34 | { 35 | "captures": 36 | { 37 | "1": 38 | { 39 | "name": "keyword.other.element.rnc" 40 | }, 41 | "2": 42 | { 43 | "name": "entity.other.element.rnc" 44 | } 45 | }, 46 | "match": "\\b(element)\\s+([a-zA-Z][-a-zA-Z_0-9]*)\\s*\\{", 47 | "name": "meta.declaration.element.rnc" 48 | }, 49 | { 50 | "match": "#.*$", 51 | "name": "comment.hash.rnc" 52 | }, 53 | { 54 | "begin": "\"", 55 | "end": "\"", 56 | "name": "string.quoted.double.rnc", 57 | "patterns": [ 58 | { 59 | "match": "\\\\.", 60 | "name": "constant.character.escape.rnc" 61 | }] 62 | }, 63 | { 64 | "begin": "'", 65 | "end": "'", 66 | "name": "string.quoted.single.rnc", 67 | "patterns": [ 68 | { 69 | "match": "\\\\.", 70 | "name": "constant.character.escape.rnc" 71 | }] 72 | }, 73 | { 74 | "captures": 75 | { 76 | "1": 77 | { 78 | "name": "entity.other.grammar_production.rnc" 79 | } 80 | }, 81 | "match": "\\b([a-zA-Z][a-zA-Z_0-9]*)\\s*=", 82 | "name": "meta.grammar_production.rnc" 83 | }], 84 | "scopeName": "source.rnc", 85 | "uuid": "85F32571-780F-4AAC-BA70-C2229E0B1BDA" 86 | } -------------------------------------------------------------------------------- /test-workspace/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "xml.server.preferBinary": true 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "alwaysStrict": true, 7 | "lib": [ 8 | "dom", 9 | "es2019" 10 | ], 11 | "sourceMap": true, 12 | "rootDir": ".", 13 | "plugins": [ 14 | { 15 | "name": "eslint" 16 | } 17 | ] 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | ".vscode-test" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | //@ts-check 5 | 6 | 'use strict'; 7 | 8 | const path = require('path'); 9 | const ESLintPlugin = require('eslint-webpack-plugin'); 10 | 11 | /**@type {import('webpack').Configuration}*/ 12 | const config = { 13 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 14 | node: { 15 | __dirname: false, 16 | __filename: false 17 | }, 18 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 19 | output: { 20 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 21 | path: path.resolve(__dirname, 'dist'), 22 | filename: 'extension.js', 23 | libraryTarget: 'commonjs2', 24 | devtoolModuleFilenameTemplate: '../[resource-path]' 25 | }, 26 | devtool: 'source-map', 27 | externals: { 28 | 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/ 29 | }, 30 | resolve: { 31 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 32 | extensions: ['.ts', '.js'] 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.ts$/, 38 | exclude: /node_modules/, 39 | use: [ 40 | { 41 | loader: 'ts-loader' 42 | } 43 | ] 44 | } 45 | ] 46 | }, 47 | infrastructureLogging: { 48 | level: 'log' 49 | }, 50 | plugins: [ 51 | new ESLintPlugin({ 52 | configType: "flat", 53 | extensions: [ 54 | ".ts", 55 | ".js" 56 | ] 57 | }), 58 | ] 59 | }; 60 | module.exports = config; 61 | -------------------------------------------------------------------------------- /webview-resources/document.css: -------------------------------------------------------------------------------- 1 | .btn { 2 | border: 0; 3 | color: var(--vscode-button-foreground); 4 | background-color: var(--vscode-button-background); 5 | } 6 | 7 | .btn svg { 8 | fill: var(--vscode-button-foreground); 9 | } 10 | 11 | .btn:hover { 12 | background-color: var(--vscode-button-hoverBackground); 13 | } 14 | 15 | .floating-bottom-right { 16 | position: fixed; 17 | bottom: 1rem; 18 | right: 1rem; 19 | } -------------------------------------------------------------------------------- /webview-resources/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs2015.css 3 | */ 4 | /* 5 | * Visual Studio 2015 dark style 6 | * Author: Nicolas LLOBERA 7 | */ 8 | 9 | 10 | .hljs-keyword, 11 | .hljs-literal, 12 | .hljs-symbol, 13 | .hljs-name { 14 | color: #569CD6; 15 | } 16 | .hljs-link { 17 | color: #569CD6; 18 | text-decoration: underline; 19 | } 20 | 21 | .hljs-built_in, 22 | .hljs-type { 23 | color: #4EC9B0; 24 | } 25 | 26 | .hljs-number, 27 | .hljs-class { 28 | color: #B8D7A3; 29 | } 30 | 31 | .hljs-string, 32 | .hljs-meta-string { 33 | color: #D69D85; 34 | } 35 | 36 | .hljs-regexp, 37 | .hljs-template-tag { 38 | color: #9A5334; 39 | } 40 | 41 | .hljs-subst, 42 | .hljs-function, 43 | .hljs-title, 44 | .hljs-params, 45 | .hljs-formula { 46 | color: #DCDCDC; 47 | } 48 | 49 | .hljs-comment, 50 | .hljs-quote { 51 | color: #57A64A; 52 | font-style: italic; 53 | } 54 | 55 | .hljs-doctag { 56 | color: #608B4E; 57 | } 58 | 59 | .hljs-meta, 60 | .hljs-meta-keyword, 61 | .hljs-tag { 62 | color: #9B9B9B; 63 | } 64 | 65 | .hljs-variable, 66 | .hljs-template-variable { 67 | color: #BD63C5; 68 | } 69 | 70 | .hljs-attr, 71 | .hljs-attribute, 72 | .hljs-builtin-name { 73 | color: #9CDCFE; 74 | } 75 | 76 | .hljs-section { 77 | color: gold; 78 | } 79 | 80 | .hljs-emphasis { 81 | font-style: italic; 82 | } 83 | 84 | .hljs-strong { 85 | font-weight: bold; 86 | } 87 | 88 | /*.hljs-code { 89 | font-family:'Monospace'; 90 | }*/ 91 | 92 | .hljs-bullet, 93 | .hljs-selector-tag, 94 | .hljs-selector-id, 95 | .hljs-selector-class, 96 | .hljs-selector-attr, 97 | .hljs-selector-pseudo { 98 | color: #D7BA7D; 99 | } 100 | 101 | .hljs-addition { 102 | background-color: var(--vscode-diffEditor-insertedTextBackground, rgba(155, 185, 85, 0.2)); 103 | color: rgb(155, 185, 85); 104 | display: inline-block; 105 | width: 100%; 106 | } 107 | 108 | .hljs-deletion { 109 | background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 0, 0, 0.2)); 110 | color: rgb(255, 0, 0); 111 | display: inline-block; 112 | width: 100%; 113 | } 114 | 115 | 116 | /* 117 | From https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs.css 118 | */ 119 | /* 120 | 121 | Visual Studio-like style based on original C# coloring by Jason Diamond 122 | 123 | */ 124 | 125 | .vscode-light .hljs-function, 126 | .vscode-light .hljs-params, 127 | .vscode-light .hljs-number, 128 | .vscode-light .hljs-class { 129 | color: inherit; 130 | } 131 | 132 | .vscode-light .hljs-comment, 133 | .vscode-light .hljs-quote, 134 | .vscode-light .hljs-number, 135 | .vscode-light .hljs-class, 136 | .vscode-light .hljs-variable { 137 | color: #008000; 138 | } 139 | 140 | .vscode-light .hljs-keyword, 141 | .vscode-light .hljs-selector-tag, 142 | .vscode-light .hljs-name, 143 | .vscode-light .hljs-tag { 144 | color: #00f; 145 | } 146 | 147 | .vscode-light .hljs-built_in, 148 | .vscode-light .hljs-builtin-name { 149 | color: #007acc; 150 | } 151 | 152 | .vscode-light .hljs-string, 153 | .vscode-light .hljs-section, 154 | .vscode-light .hljs-attribute, 155 | .vscode-light .hljs-literal, 156 | .vscode-light .hljs-template-tag, 157 | .vscode-light .hljs-template-variable, 158 | .vscode-light .hljs-type { 159 | color: #a31515; 160 | } 161 | 162 | .vscode-light .hljs-selector-attr, 163 | .vscode-light .hljs-selector-pseudo, 164 | .vscode-light .hljs-meta, 165 | .vscode-light .hljs-meta-keyword { 166 | color: #2b91af; 167 | } 168 | 169 | .vscode-light .hljs-title, 170 | .vscode-light .hljs-doctag { 171 | color: #808080; 172 | } 173 | 174 | .vscode-light .hljs-attr { 175 | color: #f00; 176 | } 177 | 178 | .vscode-light .hljs-symbol, 179 | .vscode-light .hljs-bullet, 180 | .vscode-light .hljs-link { 181 | color: #00b0e8; 182 | } 183 | 184 | 185 | .vscode-light .hljs-emphasis { 186 | font-style: italic; 187 | } 188 | 189 | .vscode-light .hljs-strong { 190 | font-weight: bold; 191 | } -------------------------------------------------------------------------------- /webview-resources/markdown.css: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | /*https://raw.githubusercontent.com/microsoft/vscode/master/extensions/markdown-language-features/media/markdown.css*/ 6 | 7 | html, body { 8 | font-family: var(--vscode-markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif); 9 | font-size: var(--vscode-markdown-font-size, 14px); 10 | padding: 0 26px; 11 | line-height: var(--vscode-markdown-line-height, 22px); 12 | word-wrap: break-word; 13 | } 14 | 15 | #code-csp-warning { 16 | position: fixed; 17 | top: 0; 18 | right: 0; 19 | color: white; 20 | margin: 16px; 21 | text-align: center; 22 | font-size: 12px; 23 | font-family: sans-serif; 24 | background-color:#444444; 25 | cursor: pointer; 26 | padding: 6px; 27 | box-shadow: 1px 1px 1px rgba(0,0,0,.25); 28 | } 29 | 30 | #code-csp-warning:hover { 31 | text-decoration: none; 32 | background-color:#007acc; 33 | box-shadow: 2px 2px 2px rgba(0,0,0,.25); 34 | } 35 | 36 | body.scrollBeyondLastLine { 37 | margin-bottom: calc(100vh - 22px); 38 | } 39 | 40 | body.showEditorSelection .code-line { 41 | position: relative; 42 | } 43 | 44 | body.showEditorSelection .code-active-line:before, 45 | body.showEditorSelection .code-line:hover:before { 46 | content: ""; 47 | display: block; 48 | position: absolute; 49 | top: 0; 50 | left: -12px; 51 | height: 100%; 52 | } 53 | 54 | body.showEditorSelection li.code-active-line:before, 55 | body.showEditorSelection li.code-line:hover:before { 56 | left: -30px; 57 | } 58 | 59 | .vscode-light.showEditorSelection .code-active-line:before { 60 | border-left: 3px solid rgba(0, 0, 0, 0.15); 61 | } 62 | 63 | .vscode-light.showEditorSelection .code-line:hover:before { 64 | border-left: 3px solid rgba(0, 0, 0, 0.40); 65 | } 66 | 67 | .vscode-light.showEditorSelection .code-line .code-line:hover:before { 68 | border-left: none; 69 | } 70 | 71 | .vscode-dark.showEditorSelection .code-active-line:before { 72 | border-left: 3px solid rgba(255, 255, 255, 0.4); 73 | } 74 | 75 | .vscode-dark.showEditorSelection .code-line:hover:before { 76 | border-left: 3px solid rgba(255, 255, 255, 0.60); 77 | } 78 | 79 | .vscode-dark.showEditorSelection .code-line .code-line:hover:before { 80 | border-left: none; 81 | } 82 | 83 | .vscode-high-contrast.showEditorSelection .code-active-line:before { 84 | border-left: 3px solid rgba(255, 160, 0, 0.7); 85 | } 86 | 87 | .vscode-high-contrast.showEditorSelection .code-line:hover:before { 88 | border-left: 3px solid rgba(255, 160, 0, 1); 89 | } 90 | 91 | .vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before { 92 | border-left: none; 93 | } 94 | 95 | img { 96 | max-width: 100%; 97 | max-height: 100%; 98 | } 99 | 100 | a { 101 | text-decoration: none; 102 | } 103 | 104 | a:hover { 105 | text-decoration: underline; 106 | } 107 | 108 | a:focus, 109 | input:focus, 110 | select:focus, 111 | textarea:focus { 112 | outline: 1px solid -webkit-focus-ring-color; 113 | outline-offset: -1px; 114 | } 115 | 116 | hr { 117 | border: 0; 118 | height: 2px; 119 | border-bottom: 2px solid; 120 | } 121 | 122 | h1 { 123 | padding-bottom: 0.3em; 124 | line-height: 1.2; 125 | border-bottom-width: 1px; 126 | border-bottom-style: solid; 127 | } 128 | 129 | h1, h2, h3 { 130 | font-weight: normal; 131 | } 132 | 133 | table { 134 | border-collapse: collapse; 135 | } 136 | 137 | table > thead > tr > th { 138 | text-align: left; 139 | border-bottom: 1px solid; 140 | } 141 | 142 | table > thead > tr > th, 143 | table > thead > tr > td, 144 | table > tbody > tr > th, 145 | table > tbody > tr > td { 146 | padding: 5px 10px; 147 | } 148 | 149 | table > tbody > tr + tr > td { 150 | border-top: 1px solid; 151 | } 152 | 153 | blockquote { 154 | margin: 0 7px 0 5px; 155 | padding: 0 16px 0 10px; 156 | border-left-width: 5px; 157 | border-left-style: solid; 158 | } 159 | 160 | code { 161 | font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"; 162 | font-size: 1em; 163 | line-height: 1.357em; 164 | } 165 | 166 | body.wordWrap pre { 167 | white-space: pre-wrap; 168 | } 169 | 170 | pre:not(.hljs), 171 | pre.hljs code > div { 172 | padding: 16px; 173 | border-radius: 3px; 174 | overflow: auto; 175 | } 176 | 177 | pre code { 178 | color: var(--vscode-editor-foreground); 179 | tab-size: 4; 180 | } 181 | 182 | /** Theming */ 183 | 184 | .vscode-light pre { 185 | background-color: rgba(220, 220, 220, 0.4); 186 | } 187 | 188 | .vscode-dark pre { 189 | background-color: rgba(10, 10, 10, 0.4); 190 | } 191 | 192 | .vscode-high-contrast pre { 193 | background-color: rgb(0, 0, 0); 194 | } 195 | 196 | .vscode-high-contrast h1 { 197 | border-color: rgb(0, 0, 0); 198 | } 199 | 200 | .vscode-light table > thead > tr > th { 201 | border-color: rgba(0, 0, 0, 0.69); 202 | } 203 | 204 | .vscode-dark table > thead > tr > th { 205 | border-color: rgba(255, 255, 255, 0.69); 206 | } 207 | 208 | .vscode-light h1, 209 | .vscode-light hr, 210 | .vscode-light table > tbody > tr + tr > td { 211 | border-color: rgba(0, 0, 0, 0.18); 212 | } 213 | 214 | .vscode-dark h1, 215 | .vscode-dark hr, 216 | .vscode-dark table > tbody > tr + tr > td { 217 | border-color: rgba(255, 255, 255, 0.18); 218 | } --------------------------------------------------------------------------------