├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── bb.yml │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .vscode ├── launch.json └── tasks.json ├── .vscodeignore ├── changelog.md ├── icon.png ├── license ├── package.json ├── package.schema.json ├── readme.md ├── src └── extension.js ├── test.mjs ├── test └── index.test.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.png binary diff=image 2 | -------------------------------------------------------------------------------- /.github/workflows/bb.yml: -------------------------------------------------------------------------------- 1 | name: bb 2 | on: 3 | issues: 4 | types: [opened, reopened, edited, closed, labeled, unlabeled] 5 | pull_request_target: 6 | types: [opened, reopened, edited, closed, labeled, unlabeled] 7 | jobs: 8 | main: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: unifiedjs/beep-boop-beta@main 12 | with: 13 | repo-token: ${{secrets.GITHUB_TOKEN}} 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: main 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | os: [macos-latest, ubuntu-latest, windows-latest] 10 | runs-on: ${{matrix.os}} 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 20 16 | - run: npm install 17 | - run: npm test 18 | if: ${{matrix.os!='ubuntu-latest'}} 19 | - run: xvfb-run npm test 20 | if: ${{matrix.os=='ubuntu-latest'}} 21 | 22 | package: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 20 29 | - run: npm install 30 | - run: npx vsce package 31 | - uses: actions/upload-artifact@v4 32 | with: 33 | name: vscode-remark.vsix 34 | path: '*.vsix' 35 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 20 15 | - run: npm install 16 | - run: npx vsce package 17 | - run: npx vsce publish --packagePath *.vsix 18 | env: 19 | VSCE_PAT: ${{secrets.VSCE_TOKEN}} 20 | - run: npx ovsx publish --packagePath *.vsix 21 | env: 22 | OVSX_PAT: ${{secrets.OPEN_VSX_TOKEN}} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | node_modules/ 3 | out/ 4 | *.log 5 | *.vsix 6 | .DS_Store 7 | .vscode* 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md 2 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "runtimeExecutable": "${execPath}", 9 | "autoAttachChildProcesses": true, 10 | "args": [ 11 | "--disable-updates", 12 | "--disable-workspace-trust", 13 | "--profile-temp", 14 | "--skip-release-notes", 15 | "--skip-welcome", 16 | "${workspaceFolder}/readme.md", 17 | "--extensionDevelopmentPath=${workspaceFolder}" 18 | ], 19 | "skipFiles": ["/**", "**/node_modules/vscode-*/**"], 20 | "preLaunchTask": "build" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "shell", 6 | "command": "npm", 7 | "args": ["run", "build", "--", "--sourcemap"], 8 | "label": "build", 9 | "group": { 10 | "kind": "build", 11 | "isDefault": true 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .*/ 2 | src/ 3 | test/ 4 | .* 5 | test.mjs 6 | tsconfig.json 7 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | See [GitHub Releases][releases] for the changelog. 4 | 5 | [releases]: https://github.com/remarkjs/vscode-remark/releases 6 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remarkjs/vscode-remark/492560938ffcfaa1c7adb49ca5d95bc5738dc0a3/icon.png -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016 Denis Malinochkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-remark", 3 | "version": "3.0.0", 4 | "description": "Lint and format markdown code with remark", 5 | "license": "MIT", 6 | "private": true, 7 | "keywords": [ 8 | "markdown", 9 | "remark", 10 | "format", 11 | "lint", 12 | "validate" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/remarkjs/vscode-remark" 17 | }, 18 | "bugs": "https://github.com/remarkjs/vscode-remark/issues", 19 | "funding": { 20 | "type": "opencollective", 21 | "url": "https://opencollective.com/unified" 22 | }, 23 | "author": "Denis Malinochkin ", 24 | "contributors": [ 25 | "Denis Malinochkin ", 26 | "Titus Wormer (https://wooorm.com)", 27 | "Remco Haszing ", 28 | "Asbjørn Ulsberg ", 29 | "Christian Murphy " 30 | ], 31 | "main": "out/extension.js", 32 | "engines": { 33 | "vscode": "^1.67.0" 34 | }, 35 | "devDependencies": { 36 | "@types/node": "^20.0.0", 37 | "@types/vscode": "^1.0.0", 38 | "@vscode/test-electron": "^2.0.0", 39 | "@vscode/vsce": "^2.0.0", 40 | "esbuild": "^0.20.0", 41 | "ovsx": "^0.9.0", 42 | "prettier": "^3.0.0", 43 | "remark-cli": "^12.0.0", 44 | "remark-language-server": "^3.0.0", 45 | "remark-preset-wooorm": "^10.0.0", 46 | "typescript": "^5.0.0", 47 | "vscode-languageclient": "^9.0.0", 48 | "xo": "^0.58.0" 49 | }, 50 | "scripts": { 51 | "vscode:prepublish": "npm run build", 52 | "build": "esbuild extension=src/extension.js remark-language-server --bundle --platform=node --target=node16 --format=cjs --external:vscode --outdir=out --minify", 53 | "format": "remark . -qfo && prettier . -w --log-level warn && xo --fix", 54 | "test-api": "node --conditions development test.mjs", 55 | "test": "npm run build && npm run format && npm run test-api" 56 | }, 57 | "prettier": { 58 | "tabWidth": 2, 59 | "useTabs": false, 60 | "singleQuote": true, 61 | "bracketSpacing": false, 62 | "semi": false, 63 | "trailingComma": "none" 64 | }, 65 | "xo": { 66 | "prettier": true, 67 | "rules": { 68 | "unicorn/prefer-module": "off" 69 | } 70 | }, 71 | "remarkConfig": { 72 | "plugins": [ 73 | "preset-wooorm", 74 | [ 75 | "remark-lint-no-html", 76 | false 77 | ] 78 | ] 79 | }, 80 | "displayName": "remark", 81 | "publisher": "unifiedjs", 82 | "icon": "icon.png", 83 | "categories": [ 84 | "Formatters", 85 | "Linters" 86 | ], 87 | "activationEvents": [ 88 | "onLanguage:markdown" 89 | ], 90 | "qna": "https://github.com/orgs/remarkjs/discussions", 91 | "sponsor": { 92 | "url": "https://github.com/sponsors/unifiedjs" 93 | }, 94 | "capabilities": { 95 | "virtualWorkspaces": { 96 | "supported": false, 97 | "description": "This extension relies on the file system to load remark and plugins." 98 | }, 99 | "untrustedWorkspaces": { 100 | "supported": false, 101 | "description": "This extension loads configuration files and plugins from workspace and executes them." 102 | } 103 | }, 104 | "contributes": { 105 | "configuration": { 106 | "title": "remark", 107 | "properties": { 108 | "remark.requireConfig": { 109 | "type": "boolean", 110 | "default": false, 111 | "markdownDescription": "If true, only perform actions if a [configuration file](https://github.com/remarkjs/vscode-remark#configuration-file) is found." 112 | } 113 | } 114 | }, 115 | "jsonValidation": [ 116 | { 117 | "fileMatch": [ 118 | ".remarkrc", 119 | ".remarkrc.json" 120 | ], 121 | "url": "https://json.schemastore.org/remarkrc" 122 | }, 123 | { 124 | "fileMatch": "package.json", 125 | "url": "./package.schema.json" 126 | } 127 | ], 128 | "languages": [ 129 | { 130 | "id": "ignore", 131 | "filenames": [ 132 | ".remarkignore" 133 | ] 134 | }, 135 | { 136 | "id": "json", 137 | "filenames": [ 138 | ".remarkrc" 139 | ] 140 | } 141 | ] 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /package.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "remarkConfig": { 4 | "description": "remark configuration", 5 | "$ref": "https://json.schemastore.org/remarkrc" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # remark for Visual Studio Code 2 | 3 | [![Build][build-badge]][build] 4 | [![Downloads][downloads-badge]][marketplace] 5 | [![Sponsors][sponsors-badge]][collective] 6 | [![Backers][backers-badge]][collective] 7 | [![Chat][chat-badge]][chat] 8 | 9 | Visual Studio Code extension to format and lint markdown files with remark. 10 | 11 | ## Contents 12 | 13 | * [What is this?](#what-is-this) 14 | * [When should I use this?](#when-should-i-use-this) 15 | * [Install](#install) 16 | * [Use](#use) 17 | * [Configuration file](#configuration-file) 18 | * [Settings](#settings) 19 | * [Formatting](#formatting) 20 | * [Plugins](#plugins) 21 | * [Compatibility](#compatibility) 22 | * [Security](#security) 23 | * [Contribute](#contribute) 24 | * [License](#license) 25 | 26 | ## What is this? 27 | 28 | This project is a Visual Studio Code (VS Code) extension that you can use in 29 | your editor to inspect and change markdown files. 30 | This extension is built around remark, which is a very popular ecosystem of 31 | plugins that work with markdown. 32 | You can choose from the 150+ plugins that already exist or make your own. 33 | 34 | See [remark][] for info on what the remark ecosystem is. 35 | 36 | ## When should I use this? 37 | 38 | You can use this extension if you want to check (lint) and format markdown 39 | files from within your editor. 40 | 41 | To configure this extension, you define your preferred markdown style in a 42 | configuration file (`.remarkrc`, `.remarkrc.js`, etc. or in `package.json`). 43 | This file is picked up by `vscode-remark` and other tools (useful for 44 | contributors that don’t use VS Code). 45 | 46 | The configuration file is also used by [`remark-cli`][remark-cli], which is 47 | recommended to be used alongside `vscode-remark`, as an npm script and/or in 48 | CI, to enforce the markdown style. 49 | 50 | ## Install 51 | 52 | [Get it on the VS Code Marketplace][marketplace] or install it by using Quick 53 | Open (Ctrl + P) and running the following: 54 | 55 | ```txt 56 | ext install unifiedjs.vscode-remark 57 | ``` 58 | 59 | ## Use 60 | 61 | To use this extension, set up [`remark-cli`][remark-cli] like you normally would 62 | in your project with a configuration file. 63 | The extension will find the configuration in your workspace just like running 64 | `remark-cli` in your terminal would. 65 | You will be able to see your linter work as you type and you can format your 66 | code if you want it to. 67 | 68 | Now, you can open markdown files in your project, and you’ll see squiggly lines 69 | and warnings in the `Problems` pane if the code doesn’t adhere to the coding 70 | standards. 71 | Here’s an example that should produce problems you can use to verify: 72 | 73 | ```markdown 74 | 1) Hello, _Jupiter_ and *Neptune*! 75 | ``` 76 | 77 | ## Configuration file 78 | 79 | `remark-language-server` uses the same configuration files as 80 | [`remark-cli`][remark-cli]. 81 | These files are: 82 | 83 | * `.remarkrc` 84 | * `.remarkrc.cjs` 85 | * `.remarkrc.js` 86 | * `.remarkrc.json` 87 | * `.remarkrc.mjs` 88 | * `.remarkrc.yaml` 89 | * `.remarkrc.yml` 90 | * `package.json` 91 | 92 | Language clients should notify the language server if these files change. 93 | They are looked up starting at the folder where the checked markdown file 94 | exists. 95 | 96 | ## Settings 97 | 98 | This extension supports the following settings: 99 | 100 | * `remark.requireConfig` (`boolean`, default: `false`) — If true, only perform 101 | actions if a [configuration file][configuration-file] is found. 102 | 103 | ## Formatting 104 | 105 | This extension can format markdown files. 106 | 107 | To format a file, pull up the command pallete (Ctrl + Shift + P), choose `Format Document With…`, and select 108 | `remark`. 109 | 110 | To make `vscode-remark` the default formatter for markdown, add the following to 111 | your `settings.json` (which you can open with Ctrl + ,): 112 | 113 | ```json 114 | { 115 | "[markdown]": { 116 | "editor.defaultFormatter": "unifiedjs.vscode-remark" 117 | } 118 | } 119 | ``` 120 | 121 | Now markdown documents can be formatted using Ctrl + Shift + I. 122 | 123 | You can optionally choose to automatically format when saving with 124 | `editor.formatOnSave`: 125 | 126 | ```json 127 | { 128 | "[markdown]": { 129 | "editor.defaultFormatter": "unifiedjs.vscode-remark", 130 | "editor.formatOnSave": true 131 | } 132 | } 133 | ``` 134 | 135 | ## Plugins 136 | 137 | The **remark** ecosystem has a variety of plugins available. 138 | Most notably you’ll want to check out [`remark-lint`][remark-lint]. 139 | See this curated [list of plugins][list-of-plugins] for more remark plugins. 140 | 141 | ## Compatibility 142 | 143 | This extension is compatible with Visual Studio Code versions 1.67.0 and 144 | greater. 145 | 146 | ## Security 147 | 148 | This plugin loads configuration files, plugins, and presets from your workspace. 149 | Only use this plugin in workspaces you trust. 150 | 151 | ## Contribute 152 | 153 | See [`contributing.md`][contributing] in [`remarkjs/.github`][health] for ways 154 | to get started. 155 | See [`support.md`][support] for ways to get help. 156 | Join us in [Discussions][chat] to chat with the community and contributors. 157 | 158 | This project has a [code of conduct][coc]. 159 | By interacting with this repository, organization, or community you agree to 160 | abide by its terms. 161 | 162 | ## License 163 | 164 | [MIT][license] © Denis Malinochkin 165 | 166 | 167 | 168 | [build-badge]: https://github.com/remarkjs/vscode-remark/workflows/main/badge.svg 169 | 170 | [build]: https://github.com/remarkjs/vscode-remark/actions 171 | 172 | [configuration-file]: #configuration-file 173 | 174 | [downloads-badge]: https://img.shields.io/visual-studio-marketplace/d/unifiedjs.vscode-remark 175 | 176 | [chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg 177 | 178 | [chat]: https://github.com/remarkjs/remark/discussions 179 | 180 | [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg 181 | 182 | [backers-badge]: https://opencollective.com/unified/backers/badge.svg 183 | 184 | [health]: https://github.com/remarkjs/.github 185 | 186 | [contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md 187 | 188 | [support]: https://github.com/remarkjs/.github/blob/main/support.md 189 | 190 | [coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md 191 | 192 | [collective]: https://opencollective.com/unified 193 | 194 | [license]: license 195 | 196 | [marketplace]: https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-remark 197 | 198 | [remark-lint]: https://github.com/remarkjs/remark-lint 199 | 200 | [remark]: https://github.com/remarkjs/remark 201 | 202 | [remark-cli]: https://github.com/remarkjs/remark/tree/main/packages/remark-cli 203 | 204 | [list-of-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md 205 | -------------------------------------------------------------------------------- /src/extension.js: -------------------------------------------------------------------------------- 1 | import {workspace} from 'vscode' 2 | import {LanguageClient, TransportKind} from 'vscode-languageclient/node.js' 3 | 4 | /** 5 | * @type {LanguageClient} 6 | */ 7 | let client 8 | 9 | /** 10 | * @param {import('vscode').ExtensionContext} context 11 | */ 12 | export async function activate(context) { 13 | client = new LanguageClient( 14 | 'remark', 15 | { 16 | module: context.asAbsolutePath('out/remark-language-server.js'), 17 | transport: TransportKind.ipc 18 | }, 19 | { 20 | documentSelector: [{scheme: 'file', language: 'markdown'}], 21 | synchronize: { 22 | fileEvents: [ 23 | workspace.createFileSystemWatcher( 24 | '**/.remark{ignore,rc,rc.cjs,rc.js,rc.json,rc.mjs,rc.yaml,rc.yml}' 25 | ), 26 | workspace.createFileSystemWatcher('**/package.json') 27 | ] 28 | } 29 | } 30 | ) 31 | 32 | await client.start() 33 | } 34 | 35 | export async function deactivate() { 36 | if (client) { 37 | await client.stop() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import {runTests} from '@vscode/test-electron' 3 | 4 | await runTests({ 5 | extensionDevelopmentPath: new URL('.', import.meta.url).pathname, 6 | extensionTestsPath: new URL('test/index.test.js', import.meta.url).pathname 7 | }) 8 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('node:assert/strict') 2 | const fs = require('node:fs/promises') 3 | const path = require('node:path') 4 | const {test} = require('node:test') 5 | const {commands, extensions, window, workspace} = require('vscode') 6 | 7 | module.exports.run = async () => { 8 | const filePath = path.join(__dirname, 'test.md') 9 | 10 | const extension = extensions.getExtension('unifiedjs.vscode-remark') 11 | await extension?.activate() 12 | 13 | await test('use the language server', async () => { 14 | await fs.writeFile(filePath, '- remark\n- lsp\n- vscode\n') 15 | const document = await workspace.openTextDocument(filePath) 16 | await window.showTextDocument(document) 17 | await commands.executeCommand('editor.action.formatDocument') 18 | 19 | assert.equal(document.getText(), '* remark\n* lsp\n* vscode\n') 20 | }) 21 | 22 | await fs.rm(filePath, {force: true}) 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["out"], 3 | "compilerOptions": { 4 | "checkJs": true, 5 | "module": "node16", 6 | "target": "es2021", 7 | "lib": ["es2021"], 8 | "noEmit": true, 9 | "strict": true 10 | } 11 | } 12 | --------------------------------------------------------------------------------