From 4de4c0dc85e8e40b27abc183649a01b1a68ee836 Mon Sep 17 00:00:00 2001 From: Tianyi Shi Date: Mon, 13 Apr 2020 14:12:23 +0800 Subject: [PATCH] adapt md exts --- CHANGELOG.md | 10 +- LICENSE | 21 + package-lock.json | 23 +- package.json | 96 +- src/Rmarkdown.ts | 9 +- src/decorations.ts | 175 ++ src/extension.ts | 14 +- src/formatting.ts | 457 +++++ src/listEditing.ts | 475 +++++ src/utils.ts | 53 + syntaxes/rmarkdown.tmLanguage.json | 2622 ++++++++++++++++++++++++++++ tsconfig.json | 33 +- 12 files changed, 3958 insertions(+), 30 deletions(-) create mode 100644 LICENSE create mode 100644 src/decorations.ts create mode 100644 src/formatting.ts create mode 100644 src/listEditing.ts create mode 100644 src/utils.ts create mode 100644 syntaxes/rmarkdown.tmLanguage.json diff --git a/CHANGELOG.md b/CHANGELOG.md index cc01cc6..1315dbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ All notable changes to the "rmarkdown" extension will be documented in this file - Initial release ## [0.0.2] - 2020-04-12 + ### Added + - aliases for `\ref`, `\refsec`, `\reffig`, `reftab`, whichs are `\@ref`, `\@sec`, `\@fig`, `\@tab`, respectively -- `Knit` command with keyboard shortcut `Cmd+Shift+K` or `Ctrl+Shift+K` \ No newline at end of file +- `Knit` command with keyboard shortcut `Cmd+Shift+K` or `Ctrl+Shift+K` + +## [0.0.3] - 2020-04-13 + +### Added + +- Syntax highlighting (adapted from [microsoft/vscode](https://github.com/microsoft/vscode/tree/master/extensions/markdown-language-features) and [yzhang-gh/vscode-markdown](https://github.com/yzhang-gh/vscode-markdown)). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5fe3820 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 石天熠 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3d3bc02..5ab3e6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "helloworld", - "version": "0.0.1", + "name": "rmarkdown_vscode", + "version": "0.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1097,6 +1097,11 @@ "has-symbols": "^1.0.1" } }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1478,6 +1483,11 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "r-helper": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/r-helper/-/r-helper-0.0.3.tgz", + "integrity": "sha512-/Q+Tl+uPF+HclHS1fiDDkWM6Czw94HglTqcXOZdBgxJ/MwqFr3Eb15tPLDFppOrTzNjStRjcHXPRZuG6DyLzfw==" + }, "readdirp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", @@ -1530,6 +1540,15 @@ "glob": "^7.1.3" } }, + "rmarkdown": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/rmarkdown/-/rmarkdown-0.0.2.tgz", + "integrity": "sha512-HL9W8rhyumnjXIfhW449fiSAW1nwcILDi04uQBAoUGyhnhFV+dR09xz6asAzUdNKsSOPVHCuVJJzvUgJ0XSlrg==", + "requires": { + "isarray": "^2.0.5", + "r-helper": "0.0.3" + } + }, "run-async": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", diff --git a/package.json b/package.json index 5437ef2..d552261 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "rmarkdown", + "name": "rmarkdown_vscode", "publisher": "TianyiShi", "author": { "name": "Tianyi Shi" @@ -54,17 +54,104 @@ } }, { - "command": "rmarkdown.knit", + "command": "rmarkdown_vscode.knit", "key": "ctrl+shift+k", "mac": "cmd+shift+k", "when": "editorTextFocus" + }, + { + "command": "rmarkdown_vscode.editing.toggleBold", + "key": "ctrl+b", + "mac": "cmd+b", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown" + }, + { + "command": "rmarkdown_vscode.editing.toggleItalic", + "key": "ctrl+i", + "mac": "cmd+i", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown" + }, + { + "command": "rmarkdown_vscode.editing.toggleStrikethrough", + "key": "alt+s", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown && !isMac" + }, + { + "command": "rmarkdown_vscode.editing.toggleHeadingUp", + "key": "ctrl+shift+]", + "mac": "ctrl+shift+]", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown" + }, + { + "command": "rmarkdown_vscode.editing.toggleHeadingDown", + "key": "ctrl+shift+[", + "mac": "ctrl+shift+[", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown" + }, + { + "command": "rmarkdown_vscode.editing.toggleMath", + "key": "ctrl+m", + "mac": "cmd+m", + "when": "editorTextFocus && !editorReadonly && editorLangId == rmarkdown" } ], "commands": [ { - "command": "rmarkdown.knit", + "command": "rmarkdown_vscode.knit", "title": "Knit" } + ], + "grammars": [ + { + "language": "rmarkdown", + "scopeName": "text.html.rmarkdown", + "path": "./syntaxes/rmarkdown.tmLanguage.json", + "embeddedLanguages": { + "meta.embedded.block.html": "html", + "source.js": "javascript", + "source.css": "css", + "meta.embedded.block.frontmatter": "yaml", + "meta.embedded.block.css": "css", + "meta.embedded.block.ini": "ini", + "meta.embedded.block.java": "java", + "meta.embedded.block.lua": "lua", + "meta.embedded.block.makefile": "makefile", + "meta.embedded.block.perl": "perl", + "meta.embedded.block.r": "r", + "meta.embedded.block.ruby": "ruby", + "meta.embedded.block.php": "php", + "meta.embedded.block.sql": "sql", + "meta.embedded.block.vs_net": "vs_net", + "meta.embedded.block.xml": "xml", + "meta.embedded.block.xsl": "xsl", + "meta.embedded.block.yaml": "yaml", + "meta.embedded.block.dosbatch": "dosbatch", + "meta.embedded.block.clojure": "clojure", + "meta.embedded.block.coffee": "coffee", + "meta.embedded.block.c": "c", + "meta.embedded.block.cpp": "cpp", + "meta.embedded.block.diff": "diff", + "meta.embedded.block.dockerfile": "dockerfile", + "meta.embedded.block.go": "go", + "meta.embedded.block.groovy": "groovy", + "meta.embedded.block.pug": "jade", + "meta.embedded.block.javascript": "javascript", + "meta.embedded.block.json": "json", + "meta.embedded.block.less": "less", + "meta.embedded.block.objc": "objc", + "meta.embedded.block.scss": "scss", + "meta.embedded.block.perl6": "perl6", + "meta.embedded.block.powershell": "powershell", + "meta.embedded.block.python": "python", + "meta.embedded.block.rust": "rust", + "meta.embedded.block.scala": "scala", + "meta.embedded.block.shellscript": "shellscript", + "meta.embedded.block.typescript": "typescript", + "meta.embedded.block.typescriptreact": "typescriptreact", + "meta.embedded.block.csharp": "csharp", + "meta.embedded.block.fsharp": "fsharp" + } + } ] }, "scripts": { @@ -87,5 +174,8 @@ "mocha": "^7.1.1", "typescript": "^3.8.3", "vscode-test": "^1.3.0" + }, + "dependencies": { + "rmarkdown": "0.0.2" } } diff --git a/src/Rmarkdown.ts b/src/Rmarkdown.ts index 0d6670a..4da0042 100644 --- a/src/Rmarkdown.ts +++ b/src/Rmarkdown.ts @@ -1,10 +1,11 @@ import { basename, dirname } from "path"; import * as vscode from "vscode"; import { spawn } from "child_process"; +//import { render, renderSync } from "rmarkdown"; export class Rmarkdown { private _outputChannel: vscode.OutputChannel; - // private _fullpath?: string; + private _fullpath?: string; private _filename?: string; private _dirname?: string; constructor() { @@ -24,8 +25,8 @@ export class Rmarkdown { }); } private _initialize(): void { - const currentFile = vscode.window.activeTextEditor!.document.fileName; - this._filename = basename(currentFile); - this._dirname = dirname(currentFile); + this._fullpath = vscode.window.activeTextEditor!.document.fileName; + this._filename = basename(this._fullpath); + this._dirname = dirname(this._fullpath); } } diff --git a/src/decorations.ts b/src/decorations.ts new file mode 100644 index 0000000..8d72fa6 --- /dev/null +++ b/src/decorations.ts @@ -0,0 +1,175 @@ +import { isFileTooLarge, isInFencedCodeBlock, isRmarkdownEditor, mathEnvCheck } from "./utils"; +import { ExtensionContext, Position, Range, TextEditor, window, workspace, TextEditorDecorationType } from "vscode"; + +let decorTypes: { [decorTypeName: string]: TextEditorDecorationType } = { + baseColor: window.createTextEditorDecorationType({ + dark: { color: "#EEFFFF" }, + light: { color: "000000" }, + }), + gray: window.createTextEditorDecorationType({ + rangeBehavior: 1, + dark: { color: "#636363" }, + light: { color: "#CCC" }, + }), + lightBlue: window.createTextEditorDecorationType({ + color: "#4080D0", + }), + orange: window.createTextEditorDecorationType({ + color: "#D2B640", + }), + strikethrough: window.createTextEditorDecorationType({ + rangeBehavior: 1, + textDecoration: "line-through", + }), + codeSpan: window.createTextEditorDecorationType({ + rangeBehavior: 1, + border: "1px solid #454D51", + borderRadius: "3px", + }), +}; + +let decors: { [decorTypeName: string]: Array } = {}; + +for (const decorTypeName of Object.keys(decorTypes)) { + decors[decorTypeName] = []; +} + +type RegexDecorTypeMapping = { [reText: string]: string[] }; + +let regexDecorTypeMapping: RegexDecorTypeMapping = { + "(~~.+?~~)": ["strikethrough"], + "(?\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(\\*)": ["gray", "baseColor", "gray"], + // _italic_ + "(_)([^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(_)": ["gray", "baseColor", "gray"], + // **bold** + "(\\*\\*)([^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s].*?[^\\*\\`\\!\\@\\#\\%\\^\\&\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s])(\\*\\*)": ["gray", "baseColor", "gray"], +}; + +export function activate(context: ExtensionContext) { + // workspace.onDidChangeConfiguration((event) => { + // if (event.affectsConfiguration("rmarkdown_vscode.syntax.decorations")) { + // window.showInformationMessage("Please reload VSCode to make setting `syntax.decorations` take effect."); + // } + // }); + + // if (!workspace.getConfiguration("rmarkdown.syntax").get("decorations")) return; + + window.onDidChangeActiveTextEditor(updateDecorations, null, context.subscriptions); + + workspace.onDidChangeTextDocument( + (event) => { + let editor = window.activeTextEditor; + if (editor !== undefined && event.document === editor.document) { + triggerUpdateDecorations(editor); + } + }, + null, + context.subscriptions + ); + + var timeout: NodeJS.Timeout | null = null; + function triggerUpdateDecorations(editor: TextEditor) { + if (timeout) { + clearTimeout(timeout); + } + timeout = setTimeout(() => updateDecorations(editor), 200); + } + + // fisrt time + let editor = window.activeTextEditor; + if (editor) { + updateDecorations(editor); + } +} + +function updateDecorations(editor?: TextEditor) { + if (editor === undefined) { + editor = window.activeTextEditor!; + } + + // if (!isRmarkdownEditor(editor)) { + // return; + // } + + const doc = editor.document; + + // if (isFileTooLarge(doc)) { + // return; + // } + + // Clean decorations + for (const decorTypeName of Object.keys(decorTypes)) { + decors[decorTypeName] = []; + } + + // e.g. { "(~~.+?~~)": ["strikethrough"] } + let appliedMappings: RegexDecorTypeMapping = { ...regexDecorTypeMappingPlainTheme, ...regexDecorTypeMapping }; + // workspace.getConfiguration("rmarkdown.syntax").get("plainTheme") ? { ...regexDecorTypeMappingPlainTheme, ...regexDecorTypeMapping } : regexDecorTypeMapping; + + doc + .getText() + .split(/\r?\n/g) + .forEach((lineText, lineNum) => { + // For each line + + // if (isInFencedCodeBlock(doc, lineNum)) { + // return; + // } + + // Issue #412 + // Trick. Match `[alt](link)` and `![alt](link)` first and remember those greyed out ranges + let noDecorRanges: [number, number][] = []; + + for (const reText of Object.keys(appliedMappings)) { + const decorTypeNames: string[] = appliedMappings[reText]; // e.g. ["strikethrough"] or ["gray", "baseColor", "gray"] + const regex = new RegExp(reText, "g"); // e.g. "(~~.+?~~)" + + let match: RegExpExecArray | null; + while ((match = regex.exec(lineText)) !== null) { + let startIndex = match.index; + + if (noDecorRanges.some((r) => (startIndex > r[0] && startIndex < r[1]) || (startIndex + match![0].length > r[0] && startIndex + match![0].length < r[1]))) { + continue; + } + + for (let i = 0; i < decorTypeNames.length; i++) { + // Skip if in math environment (See `completion.ts`) + // if (mathEnvCheck(doc, new Position(lineNum, startIndex)) !== "") { + // break; + // } + + const decorTypeName = decorTypeNames[i]; + const caughtGroup = decorTypeName === "codeSpan" ? match[0] : match[i + 1]; + + if (decorTypeName === "gray" && caughtGroup.length > 2) { + noDecorRanges.push([startIndex, startIndex + caughtGroup.length]); + } + + const range = new Range(lineNum, startIndex, lineNum, startIndex + caughtGroup.length); + startIndex += caughtGroup.length; + + //// Needed for `[alt](link)` rule. And must appear after `startIndex += caughtGroup.length;` + if (decorTypeName.length === 0) { + continue; + } + decors[decorTypeName].push(range); + } + } + } + }); + + for (const decorTypeName of Object.keys(decors)) { + editor.setDecorations(decorTypes[decorTypeName], decors[decorTypeName]); + } +} diff --git a/src/extension.ts b/src/extension.ts index 0f1920e..52088c9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,16 +2,28 @@ // Import the module and reference it with the alias vscode in your code below import * as vscode from "vscode"; import { Rmarkdown } from "./rmarkdown"; +import * as decorations from "./decorations"; +import * as listEditing from "./listEditing"; +import * as formatting from "./formatting"; // this method is called when your extension is activated // your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { + console.log("rmarkdown extension activated"); + + decorations.activate(context); + listEditing.activate(context); + formatting.activate(context); + let rmd = new Rmarkdown(); context.subscriptions.push( - vscode.commands.registerCommand("rmarkdown.knit", () => { + vscode.commands.registerCommand("rmarkdown_vscode.knit", () => { rmd.knit(); }) ); + vscode.languages.setLanguageConfiguration("rmarkdown", { + wordPattern: /(-?\d*\.\d\w*)|([^\!\@\#\%\^\&\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\,\。\《\》\?\;\:\‘\“\’\”\(\)\【\】\、]+)/g, + }); } // this method is called when your extension is deactivated diff --git a/src/formatting.ts b/src/formatting.ts new file mode 100644 index 0000000..40fa3ca --- /dev/null +++ b/src/formatting.ts @@ -0,0 +1,457 @@ +"use strict"; + +import { commands, env, ExtensionContext, Position, Range, Selection, SnippetString, TextDocument, TextEditor, window, workspace, WorkspaceEdit } from "vscode"; +import { fixMarker } from "./listEditing"; + +export function activate(context: ExtensionContext) { + context.subscriptions.push( + commands.registerCommand("rmarkdown_vscode.editing.toggleBold", toggleBold), + commands.registerCommand("rmarkdown_vscode.editing.toggleItalic", toggleItalic), + commands.registerCommand("rmarkdown_vscode.editing.toggleCodeSpan", toggleCodeSpan), + commands.registerCommand("rmarkdown_vscode.editing.toggleStrikethrough", toggleStrikethrough), + commands.registerCommand("rmarkdown_vscode.editing.toggleMath", () => toggleMath(transTable)), + commands.registerCommand("rmarkdown_vscode.editing.toggleMathReverse", () => toggleMath(reverseTransTable)), + commands.registerCommand("rmarkdown_vscode.editing.toggleHeadingUp", toggleHeadingUp), + commands.registerCommand("rmarkdown_vscode.editing.toggleHeadingDown", toggleHeadingDown), + commands.registerCommand("rmarkdown_vscode.editing.toggleList", toggleList), + commands.registerCommand("rmarkdown_vscode.editing.toggleCodeBlock", toggleCodeBlock), + commands.registerCommand("rmarkdown_vscode.editing.paste", paste) + ); +} + +/** + * Here we store Regexp to check if the text is the single link. + */ +const singleLinkRegex: RegExp = createLinkRegex(); + +// Return Promise because need to chain operations in unit tests + +function toggleBold() { + return styleByWrapping("**"); +} + +function toggleItalic() { + let indicator = workspace.getConfiguration("rmarkdown_vscode.italic").get("indicator"); + return styleByWrapping(indicator); +} + +function toggleCodeSpan() { + return styleByWrapping("`"); +} + +function toggleCodeBlock() { + let editor = window.activeTextEditor; + return editor.insertSnippet(new SnippetString("```$0\n$TM_SELECTED_TEXT\n```")); +} + +function toggleStrikethrough() { + return styleByWrapping("~~"); +} + +async function toggleHeadingUp() { + let editor = window.activeTextEditor; + let lineIndex = editor.selection.active.line; + let lineText = editor.document.lineAt(lineIndex).text; + + return await editor.edit((editBuilder) => { + if (!lineText.startsWith("#")) { + // Not a heading + editBuilder.insert(new Position(lineIndex, 0), "# "); + } else if (!lineText.startsWith("######")) { + // Already a heading (but not level 6) + editBuilder.insert(new Position(lineIndex, 0), "#"); + } + }); +} + +function toggleHeadingDown() { + let editor = window.activeTextEditor; + let lineIndex = editor.selection.active.line; + let lineText = editor.document.lineAt(lineIndex).text; + + editor.edit((editBuilder) => { + if (lineText.startsWith("# ")) { + // Heading level 1 + editBuilder.delete(new Range(new Position(lineIndex, 0), new Position(lineIndex, 2))); + } else if (lineText.startsWith("#")) { + // Heading (but not level 1) + editBuilder.delete(new Range(new Position(lineIndex, 0), new Position(lineIndex, 1))); + } + }); +} + +enum MathBlockState { + // State 1: not in any others states + NONE, + // State 2: $|$ + INLINE, + // State 3: $$ | $$ + SINGLE_DISPLAYED, + // State 4: + // $$ + // | + // $$ + MULTI_DISPLAYED, +} + +function getMathState(editor: TextEditor, cursor: Position): MathBlockState { + if (getContext(editor, cursor, "$") === "$|$") { + return MathBlockState.INLINE; + } else if (getContext(editor, cursor, "$$ ", " $$") === "$$ | $$") { + return MathBlockState.SINGLE_DISPLAYED; + } else if (editor.document.lineAt(cursor.line).text === "" && cursor.line > 0 && editor.document.lineAt(cursor.line - 1).text === "$$" && cursor.line < editor.document.lineCount - 1 && editor.document.lineAt(cursor.line + 1).text === "$$") { + return MathBlockState.MULTI_DISPLAYED; + } else { + return MathBlockState.NONE; + } +} + +/** + * Modify the document, change from `oldMathBlockState` to `newMathBlockState`. + * @param editor + * @param cursor + * @param oldMathBlockState + * @param newMathBlockState + */ +function setMathState(editor: TextEditor, cursor: Position, oldMathBlockState: MathBlockState, newMathBlockState: MathBlockState) { + // Step 1: Delete old math block. + editor + .edit((editBuilder) => { + let rangeToBeDeleted: Range; + switch (oldMathBlockState) { + case MathBlockState.NONE: + rangeToBeDeleted = new Range(cursor, cursor); + break; + case MathBlockState.INLINE: + rangeToBeDeleted = new Range(new Position(cursor.line, cursor.character - 1), new Position(cursor.line, cursor.character + 1)); + break; + case MathBlockState.SINGLE_DISPLAYED: + rangeToBeDeleted = new Range(new Position(cursor.line, cursor.character - 3), new Position(cursor.line, cursor.character + 3)); + break; + case MathBlockState.MULTI_DISPLAYED: + rangeToBeDeleted = new Range(new Position(cursor.line - 1, 0), new Position(cursor.line + 1, 2)); + break; + } + editBuilder.delete(rangeToBeDeleted); + }) + .then(() => { + // Step 2: Insert new math block. + editor + .edit((editBuilder) => { + let newCursor = editor.selection.active; + let stringToBeInserted: string; + switch (newMathBlockState) { + case MathBlockState.NONE: + stringToBeInserted = ""; + break; + case MathBlockState.INLINE: + stringToBeInserted = "$$"; + break; + case MathBlockState.SINGLE_DISPLAYED: + stringToBeInserted = "$$ $$"; + break; + case MathBlockState.MULTI_DISPLAYED: + stringToBeInserted = "$$\n\n$$"; + break; + } + editBuilder.insert(newCursor, stringToBeInserted); + }) + .then(() => { + // Step 3: Move cursor to the middle. + let newCursor = editor.selection.active; + let newPosition: Position; + switch (newMathBlockState) { + case MathBlockState.NONE: + newPosition = newCursor; + break; + case MathBlockState.INLINE: + newPosition = newCursor.with(newCursor.line, newCursor.character - 1); + break; + case MathBlockState.SINGLE_DISPLAYED: + newPosition = newCursor.with(newCursor.line, newCursor.character - 3); + break; + case MathBlockState.MULTI_DISPLAYED: + newPosition = newCursor.with(newCursor.line - 1, 0); + break; + } + editor.selection = new Selection(newPosition, newPosition); + }); + }); +} + +const transTable = [MathBlockState.NONE, MathBlockState.INLINE, MathBlockState.MULTI_DISPLAYED, MathBlockState.SINGLE_DISPLAYED]; +const reverseTransTable = new Array(...transTable).reverse(); + +function toggleMath(transTable) { + let editor = window.activeTextEditor; + if (!editor.selection.isEmpty) return; + let cursor = editor.selection.active; + + let oldMathBlockState = getMathState(editor, cursor); + let currentStateIndex = transTable.indexOf(oldMathBlockState); + setMathState(editor, cursor, oldMathBlockState, transTable[(currentStateIndex + 1) % transTable.length]); +} + +function toggleList() { + const editor = window.activeTextEditor; + const doc = editor.document; + let batchEdit = new WorkspaceEdit(); + + editor.selections.forEach((selection) => { + if (selection.isEmpty) { + toggleListSingleLine(doc, selection.active.line, batchEdit); + } else { + for (let i = selection.start.line; i <= selection.end.line; i++) { + toggleListSingleLine(doc, i, batchEdit); + } + } + }); + + return workspace.applyEdit(batchEdit).then(() => fixMarker()); +} + +function toggleListSingleLine(doc: TextDocument, line: number, wsEdit: WorkspaceEdit) { + const lineText = doc.lineAt(line).text; + const indentation = lineText.trim().length === 0 ? lineText.length : lineText.indexOf(lineText.trim()); + const lineTextContent = lineText.substr(indentation); + + if (lineTextContent.startsWith("- ")) { + wsEdit.replace(doc.uri, new Range(line, indentation, line, indentation + 2), "* "); + } else if (lineTextContent.startsWith("* ")) { + wsEdit.replace(doc.uri, new Range(line, indentation, line, indentation + 2), "+ "); + } else if (lineTextContent.startsWith("+ ")) { + wsEdit.replace(doc.uri, new Range(line, indentation, line, indentation + 2), "1. "); + } else if (/^\d\. /.test(lineTextContent)) { + wsEdit.replace(doc.uri, new Range(line, indentation + 1, line, indentation + 2), ")"); + } else if (/^\d\) /.test(lineTextContent)) { + wsEdit.delete(doc.uri, new Range(line, indentation, line, indentation + 3)); + } else { + wsEdit.insert(doc.uri, new Position(line, indentation), "- "); + } +} + +async function paste() { + const editor = window.activeTextEditor; + const selection = editor.selection; + if (selection.isSingleLine && !isSingleLink(editor.document.getText(selection))) { + const text = await env.clipboard.readText(); + if (isSingleLink(text)) { + return commands.executeCommand("editor.action.insertSnippet", { snippet: `[$TM_SELECTED_TEXT$0](${text})` }); + } + } + return commands.executeCommand("editor.action.clipboardPasteAction"); +} + +/** + * Creates Regexp to check if the text is a link (further detailes in the isSingleLink() documentation). + * + * @return Regexp + */ +function createLinkRegex(): RegExp { + // unicode letters range(must not be a raw string) + const ul = "\\u00a1-\\uffff"; + // IP patterns + const ipv4_re = "(?:25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}"; + const ipv6_re = "\\[[0-9a-f:\\.]+\\]"; // simple regex (in django it is validated additionally) + + // Host patterns + const hostname_re = "[a-z" + ul + "0-9](?:[a-z" + ul + "0-9-]{0,61}[a-z" + ul + "0-9])?"; + // Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1 + const domain_re = "(?:\\.(?!-)[a-z" + ul + "0-9-]{1,63}(? { + let cursorPos = selection.active; + const shift = shifts.map(([pos, s]) => (selection.start.line == pos.line && selection.start.character >= pos.character ? s : 0)).reduce((a, b) => a + b, 0); + + if (selection.isEmpty) { + // No selected text + if (startPattern !== "~~" && getContext(editor, cursorPos, startPattern) === `${startPattern}text|${endPattern}`) { + // `**text|**` to `**text**|` + let newCursorPos = cursorPos.with({ character: cursorPos.character + shift + endPattern.length }); + newSelections[i] = new Selection(newCursorPos, newCursorPos); + return; + } else if (getContext(editor, cursorPos, startPattern) === `${startPattern}|${endPattern}`) { + // `**|**` to `|` + let start = cursorPos.with({ character: cursorPos.character - startPattern.length }); + let end = cursorPos.with({ character: cursorPos.character + endPattern.length }); + wrapRange(editor, batchEdit, shifts, newSelections, i, shift, cursorPos, new Range(start, end), false, startPattern); + } else { + // Select word under cursor + let wordRange = editor.document.getWordRangeAtPosition(cursorPos); + if (wordRange == undefined) { + wordRange = selection; + } + // One special case: toggle strikethrough in task list + const currentTextLine = editor.document.lineAt(cursorPos.line); + if (startPattern === "~~" && /^\s*[\*\+\-] (\[[ x]\] )? */g.test(currentTextLine.text)) { + wordRange = currentTextLine.range.with(new Position(cursorPos.line, currentTextLine.text.match(/^\s*[\*\+\-] (\[[ x]\] )? */g)[0].length)); + } + wrapRange(editor, batchEdit, shifts, newSelections, i, shift, cursorPos, wordRange, false, startPattern); + } + } else { + // Text selected + wrapRange(editor, batchEdit, shifts, newSelections, i, shift, cursorPos, selection, true, startPattern, endPattern); + } + }); + + return workspace.applyEdit(batchEdit).then(() => { + editor.selections = newSelections; + }); +} + +/** + * Add or remove `startPattern`/`endPattern` according to the context + * @param editor + * @param options The undo/redo behavior + * @param cursor cursor position + * @param range range to be replaced + * @param isSelected is this range selected + * @param startPtn + * @param endPtn + */ +function wrapRange(editor: TextEditor, wsEdit: WorkspaceEdit, shifts: [Position, number][], newSelections: Selection[], i: number, shift: number, cursor: Position, range: Range, isSelected: boolean, startPtn: string, endPtn?: string) { + if (endPtn == undefined) { + endPtn = startPtn; + } + + let text = editor.document.getText(range); + const prevSelection = newSelections[i]; + const ptnLength = (startPtn + endPtn).length; + + let newCursorPos = cursor.with({ character: cursor.character + shift }); + let newSelection: Selection; + if (isWrapped(text, startPtn, endPtn)) { + // remove start/end patterns from range + wsEdit.replace(editor.document.uri, range, text.substr(startPtn.length, text.length - ptnLength)); + + shifts.push([range.end, -ptnLength]); + + // Fix cursor position + if (!isSelected) { + if (!range.isEmpty) { + // means quick styling + if (cursor.character == range.end.character) { + newCursorPos = cursor.with({ character: cursor.character + shift - ptnLength }); + } else { + newCursorPos = cursor.with({ character: cursor.character + shift - startPtn.length }); + } + } else { + // means `**|**` -> `|` + newCursorPos = cursor.with({ character: cursor.character + shift + startPtn.length }); + } + newSelection = new Selection(newCursorPos, newCursorPos); + } else { + newSelection = new Selection(prevSelection.start.with({ character: prevSelection.start.character + shift }), prevSelection.end.with({ character: prevSelection.end.character + shift - ptnLength })); + } + } else { + // add start/end patterns around range + wsEdit.replace(editor.document.uri, range, startPtn + text + endPtn); + + shifts.push([range.end, ptnLength]); + + // Fix cursor position + if (!isSelected) { + if (!range.isEmpty) { + // means quick styling + if (cursor.character == range.end.character) { + newCursorPos = cursor.with({ character: cursor.character + shift + ptnLength }); + } else { + newCursorPos = cursor.with({ character: cursor.character + shift + startPtn.length }); + } + } else { + // means `|` -> `**|**` + newCursorPos = cursor.with({ character: cursor.character + shift + startPtn.length }); + } + newSelection = new Selection(newCursorPos, newCursorPos); + } else { + newSelection = new Selection(prevSelection.start.with({ character: prevSelection.start.character + shift }), prevSelection.end.with({ character: prevSelection.end.character + shift + ptnLength })); + } + } + + newSelections[i] = newSelection; +} + +function isWrapped(text, startPattern, endPattern?): boolean { + if (endPattern == undefined) { + endPattern = startPattern; + } + return text.startsWith(startPattern) && text.endsWith(endPattern); +} + +function getContext(editor, cursorPos, startPattern, endPattern?): string { + if (endPattern == undefined) { + endPattern = startPattern; + } + + let startPositionCharacter = cursorPos.character - startPattern.length; + let endPositionCharacter = cursorPos.character + endPattern.length; + + if (startPositionCharacter < 0) { + startPositionCharacter = 0; + } + + let leftText = editor.document.getText(new Range(cursorPos.line, startPositionCharacter, cursorPos.line, cursorPos.character)); + let rightText = editor.document.getText(new Range(cursorPos.line, cursorPos.character, cursorPos.line, endPositionCharacter)); + + if (rightText == endPattern) { + if (leftText == startPattern) { + return `${startPattern}|${endPattern}`; + } else { + return `${startPattern}text|${endPattern}`; + } + } + return "|"; +} diff --git a/src/listEditing.ts b/src/listEditing.ts new file mode 100644 index 0000000..0394979 --- /dev/null +++ b/src/listEditing.ts @@ -0,0 +1,475 @@ +"use strict"; + +import { commands, ExtensionContext, Position, Range, Selection, TextEditor, window, workspace, WorkspaceEdit } from "vscode"; +import { isInFencedCodeBlock, mathEnvCheck } from "./utils"; + +export function activate(context: ExtensionContext) { + context.subscriptions.push( + commands.registerCommand("rmarkdown_vscode.onEnterKey", onEnterKey), + commands.registerCommand("rmarkdown_vscode.onCtrlEnterKey", () => { + return onEnterKey("ctrl"); + }), + commands.registerCommand("rmarkdown_vscode.onShiftEnterKey", () => { + return onEnterKey("shift"); + }), + commands.registerCommand("rmarkdown_vscode.onTabKey", onTabKey), + commands.registerCommand("rmarkdown_vscode.onShiftTabKey", () => { + return onTabKey("shift"); + }), + commands.registerCommand("rmarkdown_vscode.onBackspaceKey", onBackspaceKey), + commands.registerCommand("rmarkdown_vscode.checkTaskList", checkTaskList), + commands.registerCommand("rmarkdown_vscode.onMoveLineDown", onMoveLineDown), + commands.registerCommand("rmarkdown_vscode.onMoveLineUp", onMoveLineUp), + commands.registerCommand("rmarkdown_vscode.onCopyLineDown", onCopyLineDown), + commands.registerCommand("rmarkdown_vscode.onCopyLineUp", onCopyLineUp), + commands.registerCommand("rmarkdown_vscode.onIndentLines", onIndentLines), + commands.registerCommand("rmarkdown_vscode.onOutdentLines", onOutdentLines) + ); +} + +function onEnterKey(modifiers?: string) { + let editor = window.activeTextEditor; + let cursorPos: Position = editor.selection.active; + let line = editor.document.lineAt(cursorPos.line); + let textBeforeCursor = line.text.substr(0, cursorPos.character); + let textAfterCursor = line.text.substr(cursorPos.character); + + let lineBreakPos = cursorPos; + if (modifiers == "ctrl") { + lineBreakPos = line.range.end; + } + + if (modifiers == "shift" || isInFencedCodeBlock(editor.document, cursorPos.line) || mathEnvCheck(editor.document, cursorPos)) { + return asNormal("enter", modifiers); + } + + // If it's an empty list item, remove it + if (/^(>|([-+*]|[0-9]+[.)])( +\[[ x]\])?)$/.test(textBeforeCursor.trim()) && textAfterCursor.trim().length == 0) { + return editor + .edit((editBuilder) => { + editBuilder.delete(line.range); + editBuilder.insert(line.range.end, "\n"); + }) + .then(() => { + editor.revealRange(editor.selection); + }) + .then(() => fixMarker(findNextMarkerLineNumber())); + } + + let matches; + if (/^> /.test(textBeforeCursor)) { + // Quote block + return editor + .edit((editBuilder) => { + editBuilder.insert(lineBreakPos, `\n> `); + }) + .then(() => { + // Fix cursor position + if (modifiers == "ctrl" && !cursorPos.isEqual(lineBreakPos)) { + let newCursorPos = cursorPos.with(line.lineNumber + 1, 2); + editor.selection = new Selection(newCursorPos, newCursorPos); + } + }) + .then(() => { + editor.revealRange(editor.selection); + }); + } else if ((matches = /^(\s*[-+*] +(\[[ x]\] +)?)/.exec(textBeforeCursor)) !== null) { + // Unordered list + return editor + .edit((editBuilder) => { + editBuilder.insert(lineBreakPos, `\n${matches[1].replace("[x]", "[ ]")}`); + }) + .then(() => { + // Fix cursor position + if (modifiers == "ctrl" && !cursorPos.isEqual(lineBreakPos)) { + let newCursorPos = cursorPos.with(line.lineNumber + 1, matches[1].length); + editor.selection = new Selection(newCursorPos, newCursorPos); + } + }) + .then(() => { + editor.revealRange(editor.selection); + }); + } else if ((matches = /^(\s*)([0-9]+)([.)])( +)((\[[ x]\] +)?)/.exec(textBeforeCursor)) !== null) { + // Ordered list + let config = workspace.getConfiguration("rmarkdown_vscode.orderedList").get("marker"); + let marker = "1"; + let leadingSpace = matches[1]; + let previousMarker = matches[2]; + let delimiter = matches[3]; + let trailingSpace = matches[4]; + let gfmCheckbox = matches[5].replace("[x]", "[ ]"); + let textIndent = (previousMarker + delimiter + trailingSpace).length; + if (config == "ordered") { + marker = String(Number(previousMarker) + 1); + } + // Add enough trailing spaces so that the text is aligned with the previous list item, but always keep at least one space + trailingSpace = " ".repeat(Math.max(1, textIndent - (marker + delimiter).length)); + + const toBeAdded = leadingSpace + marker + delimiter + trailingSpace + gfmCheckbox; + return editor + .edit( + (editBuilder) => { + editBuilder.insert(lineBreakPos, `\n${toBeAdded}`); + }, + { undoStopBefore: true, undoStopAfter: false } + ) + .then(() => { + // Fix cursor position + if (modifiers == "ctrl" && !cursorPos.isEqual(lineBreakPos)) { + let newCursorPos = cursorPos.with(line.lineNumber + 1, toBeAdded.length); + editor.selection = new Selection(newCursorPos, newCursorPos); + } + }) + .then(() => fixMarker()) + .then(() => { + editor.revealRange(editor.selection); + }); + } else { + return asNormal("enter", modifiers); + } +} + +function onTabKey(modifiers?: string) { + let editor = window.activeTextEditor; + let cursorPos = editor.selection.start; + let lineText = editor.document.lineAt(cursorPos.line).text; + + if (isInFencedCodeBlock(editor.document, cursorPos.line) || mathEnvCheck(editor.document, cursorPos)) { + return asNormal("tab", modifiers); + } + + let match = /^\s*([-+*]|[0-9]+[.)]) +(\[[ x]\] +)?/.exec(lineText); + if (match && (modifiers === "shift" || !editor.selection.isEmpty || (editor.selection.isEmpty && cursorPos.character <= match[0].length))) { + if (modifiers === "shift") { + return outdent(editor).then(() => fixMarker()); + } else { + return indent(editor).then(() => fixMarker()); + } + } else { + return asNormal("tab", modifiers); + } +} + +function onBackspaceKey() { + let editor = window.activeTextEditor; + let cursor = editor.selection.active; + let document = editor.document; + let textBeforeCursor = document.lineAt(cursor.line).text.substr(0, cursor.character); + + if (isInFencedCodeBlock(document, cursor.line) || mathEnvCheck(editor.document, cursor)) { + return asNormal("backspace"); + } + + if (!editor.selection.isEmpty) { + return asNormal("backspace").then(() => fixMarker(findNextMarkerLineNumber())); + } else if (/^\s+([-+*]|[0-9]+[.)]) $/.test(textBeforeCursor)) { + // e.g. textBeforeCursor === ` - `, ` 1. ` + return outdent(editor).then(() => fixMarker()); + } else if (/^([-+*]|[0-9]+[.)]) $/.test(textBeforeCursor)) { + // e.g. textBeforeCursor === `- `, `1. ` + return editor + .edit((editBuilder) => { + editBuilder.replace(new Range(cursor.with({ character: 0 }), cursor), " ".repeat(textBeforeCursor.length)); + }) + .then(() => fixMarker(findNextMarkerLineNumber())); + } else if (/^\s*([-+*]|[0-9]+[.)]) +(\[[ x]\] )$/.test(textBeforeCursor)) { + // e.g. textBeforeCursor === `- [ ]`, `1. [x]`, ` - [x]` + return deleteRange(editor, new Range(cursor.with({ character: textBeforeCursor.length - 4 }), cursor)).then(() => fixMarker(findNextMarkerLineNumber())); + } else { + return asNormal("backspace"); + } +} + +function asNormal(key: string, modifiers?: string) { + switch (key) { + case "enter": + if (modifiers === "ctrl") { + return commands.executeCommand("editor.action.insertLineAfter"); + } else { + return commands.executeCommand("type", { source: "keyboard", text: "\n" }); + } + case "tab": + if (modifiers === "shift") { + return commands.executeCommand("editor.action.outdentLines"); + } else if (window.activeTextEditor.selection.isEmpty && workspace.getConfiguration("emmet").get("triggerExpansionOnTab")) { + return commands.executeCommand("editor.emmet.action.expandAbbreviation"); + } else { + return commands.executeCommand("tab"); + } + case "backspace": + return commands.executeCommand("deleteLeft"); + } +} + +/** + * If + * + * 1. it is not the first line + * 2. there is a Markdown list item before this line + * + * then indent the current line to align with the previous list item. + */ +function indent(editor?: TextEditor) { + if (!editor) { + editor = window.activeTextEditor; + } + + if (workspace.getConfiguration("rmarkdown_vscode.list", editor.document.uri).get("indentationSize") === "adaptive") { + try { + const selection = editor.selection; + const indentationSize = tryDetermineIndentationSize(editor, selection.start.line, editor.document.lineAt(selection.start.line).firstNonWhitespaceCharacterIndex); + let edit = new WorkspaceEdit(); + for (let i = selection.start.line; i <= selection.end.line; i++) { + if (i === selection.end.line && !selection.isEmpty && selection.end.character === 0) { + break; + } + if (editor.document.lineAt(i).text.length !== 0) { + edit.insert(editor.document.uri, new Position(i, 0), " ".repeat(indentationSize)); + } + } + return workspace.applyEdit(edit); + } catch (error) {} + } + + return commands.executeCommand("editor.action.indentLines"); +} + +/** + * Similar to `indent`-function + */ +function outdent(editor?: TextEditor) { + if (!editor) { + editor = window.activeTextEditor; + } + + if (workspace.getConfiguration("rmarkdown_vscode.list", editor.document.uri).get("indentationSize") === "adaptive") { + try { + const selection = editor.selection; + const indentationSize = tryDetermineIndentationSize(editor, selection.start.line, editor.document.lineAt(selection.start.line).firstNonWhitespaceCharacterIndex); + let edit = new WorkspaceEdit(); + for (let i = selection.start.line; i <= selection.end.line; i++) { + if (i === selection.end.line && !selection.isEmpty && selection.end.character === 0) { + break; + } + const lineText = editor.document.lineAt(i).text; + let maxOutdentSize: number; + if (lineText.trim().length === 0) { + maxOutdentSize = lineText.length; + } else { + maxOutdentSize = editor.document.lineAt(i).firstNonWhitespaceCharacterIndex; + } + if (maxOutdentSize > 0) { + edit.delete(editor.document.uri, new Range(i, 0, i, Math.min(indentationSize, maxOutdentSize))); + } + } + return workspace.applyEdit(edit); + } catch (error) {} + } + + return commands.executeCommand("editor.action.outdentLines"); +} + +function tryDetermineIndentationSize(editor: TextEditor, line: number, currentIndentation: number) { + while (--line >= 0) { + const lineText = editor.document.lineAt(line).text; + let matches; + if ((matches = /^(\s*)(([-+*]|[0-9]+[.)]) +)(\[[ x]\] +)?/.exec(lineText)) !== null) { + if (matches[1].length <= currentIndentation) { + return matches[2].length; + } + } + } + throw "No previous Markdown list item"; +} + +/** + * Returns the line number of the next ordered list item starting either from + * the specified line or the beginning of the current selection. + */ +function findNextMarkerLineNumber(line?: number): number { + let editor = window.activeTextEditor; + if (line === undefined) { + // Use start.line instead of active.line so that we can find the first + // marker following either the cursor or the entire selected range + line = editor.selection.start.line; + } + while (line < editor.document.lineCount) { + const lineText = editor.document.lineAt(line).text; + + if (lineText.startsWith("#")) { + // Don't go searching past any headings + return -1; + } + + if (/^\s*[0-9]+[.)] +/.exec(lineText) !== null) { + return line; + } + line++; + } + return undefined; +} + +/** + * Looks for the previous ordered list marker at the same indentation level + * and returns the marker number that should follow it. + * + * @returns the fixed marker number + */ +function lookUpwardForMarker(editor: TextEditor, line: number, currentIndentation: number): number { + while (--line >= 0) { + const lineText = editor.document.lineAt(line).text; + let matches; + if ((matches = /^(\s*)(([0-9]+)[.)] +)/.exec(lineText)) !== null) { + let leadingSpace: string = matches[1]; + let marker = matches[3]; + if (leadingSpace.length === currentIndentation) { + return Number(marker) + 1; + } else if ((!leadingSpace.includes("\t") && leadingSpace.length + matches[2].length <= currentIndentation) || (leadingSpace.includes("\t") && leadingSpace.length + 1 <= currentIndentation)) { + return 1; + } + } else if ((matches = /^(\s*)\S/.exec(lineText)) !== null) { + if (matches[1].length <= currentIndentation) { + break; + } + } + } + return 1; +} + +/** + * Fix ordered list marker *iteratively* starting from current line + */ +export function fixMarker(line?: number) { + if (!workspace.getConfiguration("rmarkdown_vscode.orderedList").get("autoRenumber")) return; + if (workspace.getConfiguration("rmarkdown_vscode.orderedList").get("marker") == "one") return; + + let editor = window.activeTextEditor; + if (line === undefined) { + // Use either the first line containing an ordered list marker within the selection or the active line + line = findNextMarkerLineNumber(); + if (line === undefined || line > editor.selection.end.line) { + line = editor.selection.active.line; + } + } + if (line < 0 || editor.document.lineCount <= line) { + return; + } + + let currentLineText = editor.document.lineAt(line).text; + let matches; + if ((matches = /^(\s*)([0-9]+)([.)])( +)/.exec(currentLineText)) !== null) { + // ordered list + let leadingSpace = matches[1]; + let marker = matches[2]; + let delimiter = matches[3]; + let trailingSpace = matches[4]; + let fixedMarker = lookUpwardForMarker(editor, line, leadingSpace.length); + let listIndent = marker.length + delimiter.length + trailingSpace.length; + let fixedMarkerString = String(fixedMarker); + + return editor + .edit( + (editBuilder) => { + if (marker === fixedMarkerString) { + return; + } + // Add enough trailing spaces so that the text is still aligned at the same indentation level as it was previously, but always keep at least one space + fixedMarkerString += delimiter + " ".repeat(Math.max(1, listIndent - (fixedMarkerString + delimiter).length)); + + editBuilder.replace(new Range(line, leadingSpace.length, line, leadingSpace.length + listIndent), fixedMarkerString); + }, + { undoStopBefore: false, undoStopAfter: false } + ) + .then(() => { + let nextLine = line + 1; + let indentString = " ".repeat(listIndent); + while (editor.document.lineCount > nextLine) { + const nextLineText = editor.document.lineAt(nextLine).text; + if (/^\s*[0-9]+[.)] +/.test(nextLineText)) { + return fixMarker(nextLine); + } else if (/^\s*$/.test(nextLineText)) { + nextLine++; + } else if (listIndent <= 4 && !nextLineText.startsWith(indentString)) { + return; + } else { + nextLine++; + } + } + }); + } +} + +function deleteRange(editor: TextEditor, range: Range): Thenable { + return editor.edit( + (editBuilder) => { + editBuilder.delete(range); + }, + // We will enable undoStop after fixing markers + { undoStopBefore: true, undoStopAfter: false } + ); +} + +function checkTaskList() { + // - Look into selections for lines that could be checked/unchecked. + // - The first matching line dictates the new state for all further lines. + // - I.e. if the first line is unchecked, only other unchecked lines will + // be considered, and vice versa. + let editor = window.activeTextEditor; + const uncheckedRegex = /^(\s*([-+*]|[0-9]+[.)]) +\[) \]/; + const checkedRegex = /^(\s*([-+*]|[0-9]+[.)]) +\[)x\]/; + var toBeToggled: Position[] = []; // all spots that have an "[x]" resp. "[ ]" which should be toggled + var newState: boolean | undefined = undefined; // true = "x", false = " ", undefined = no matching lines + + // go through all touched lines of all selections. + for (const selection of editor.selections) { + for (let i = selection.start.line; i <= selection.end.line; i++) { + let line = editor.document.lineAt(i); + let lineStart = line.range.start; + + let matches: RegExpExecArray; + if ((matches = uncheckedRegex.exec(line.text)) && newState !== false) { + toBeToggled.push(lineStart.with({ character: matches[1].length })); + newState = true; + } else if ((matches = checkedRegex.exec(line.text)) && newState !== true) { + toBeToggled.push(lineStart.with({ character: matches[1].length })); + newState = false; + } + } + } + + if (newState !== undefined) { + const newChar = newState ? "x" : " "; + return editor.edit((editBuilder) => { + for (const pos of toBeToggled) { + var range = new Range(pos, pos.with({ character: pos.character + 1 })); + editBuilder.replace(range, newChar); + } + }); + } +} + +function onMoveLineUp() { + return commands.executeCommand("editor.action.moveLinesUpAction").then(() => fixMarker()); +} + +function onMoveLineDown() { + return commands.executeCommand("editor.action.moveLinesDownAction").then(() => fixMarker(findNextMarkerLineNumber(window.activeTextEditor.selection.start.line - 1))); +} + +function onCopyLineUp() { + return commands.executeCommand("editor.action.copyLinesUpAction").then(() => fixMarker()); +} + +function onCopyLineDown() { + return commands.executeCommand("editor.action.copyLinesDownAction").then(() => fixMarker()); +} + +function onIndentLines() { + return indent().then(() => fixMarker()); +} + +function onOutdentLines() { + return outdent().then(() => fixMarker()); +} + +export function deactivate() {} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..4bee04d --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,53 @@ +import * as fs from "fs"; +import { commands, Position, Range, TextDocument, TextEditor, Uri, workspace } from "vscode"; + +export function isRmarkdownEditor(editor: TextEditor) { + return editor && editor.document && editor.document.languageId === "rmarkdown"; +} + +const sizeLimit = 50000; // ~50 KB +let fileSizesCache: { [filepath: string]: [number, boolean] } = {}; +export function isFileTooLarge(document: TextDocument): boolean { + const filePath = document.uri.fsPath; + if (!filePath || !fs.existsSync(filePath)) { + return false; + } + const version = document.version; + if (fileSizesCache.hasOwnProperty(filePath) && fileSizesCache[filePath][0] === version) { + return fileSizesCache[filePath][1]; + } else { + const isTooLarge = fs.statSync(filePath)["size"] > sizeLimit; + fileSizesCache[filePath] = [version, isTooLarge]; + return isTooLarge; + } +} + +export function isInFencedCodeBlock(doc: TextDocument, lineNum: number): boolean { + let textBefore = doc.getText(new Range(new Position(0, 0), new Position(lineNum, 0))); + let matches = textBefore.match(/^```[\w \+]*$/gm); + if (matches === null) { + return false; + } else { + return matches!.length % 2 !== 0; + } +} + +export function mathEnvCheck(doc: TextDocument, pos: Position): string { + const lineTextBefore = doc.lineAt(pos.line).text.substring(0, pos.character); + const lineTextAfter = doc.lineAt(pos.line).text.substring(pos.character); + + if (/(^|[^\$])\$(|[^ \$].*)\\\w*$/.test(lineTextBefore) && lineTextAfter.includes("$")) { + // Inline math + return "inline"; + } else { + const textBefore = doc.getText(new Range(new Position(0, 0), pos)); + const textAfter = doc.getText().substr(doc.offsetAt(pos)); + let matches; + if ((matches = textBefore.match(/\$\$/g)) !== null && matches.length % 2 !== 0 && textAfter.includes("$$")) { + // $$ ... $$ + return "display"; + } else { + return ""; + } + } +} diff --git a/syntaxes/rmarkdown.tmLanguage.json b/syntaxes/rmarkdown.tmLanguage.json new file mode 100644 index 0000000..5fa042b --- /dev/null +++ b/syntaxes/rmarkdown.tmLanguage.json @@ -0,0 +1,2622 @@ +{ + "information_for_contributors": ["This file has been converted from https://github.com/microsoft/vscode-markdown-tm-grammar/blob/master/syntaxes/markdown.tmLanguage", "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request."], + "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/7cf9aa7bb76c55428063383610edc0a631230d58", + "name": "R Markdown", + "scopeName": "text.html.rmarkdown", + "patterns": [ + { + "include": "#frontMatter" + }, + { + "include": "#block" + } + ], + "repository": { + "block": { + "patterns": [ + { + "include": "#separator" + }, + { + "include": "#heading" + }, + { + "include": "#blockquote" + }, + { + "include": "#lists" + }, + { + "include": "#fenced_code_block" + }, + { + "include": "#raw_block" + }, + { + "include": "#link-def" + }, + { + "include": "#html" + }, + { + "include": "#paragraph" + } + ] + }, + "blockquote": { + "begin": "(^|\\G)[ ]{0,3}(>) ?", + "captures": { + "2": { + "name": "punctuation.definition.quote.begin.markdown" + } + }, + "name": "markup.quote.markdown", + "patterns": [ + { + "include": "#block" + } + ], + "while": "(^|\\G)\\s*(>) ?" + }, + "fenced_code_block_css": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.css", + "patterns": [ + { + "include": "source.css" + } + ] + } + ] + }, + "fenced_code_block_basic": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.html", + "patterns": [ + { + "include": "text.html.basic" + } + ] + } + ] + }, + "fenced_code_block_ini": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ini", + "patterns": [ + { + "include": "source.ini" + } + ] + } + ] + }, + "fenced_code_block_java": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.java", + "patterns": [ + { + "include": "source.java" + } + ] + } + ] + }, + "fenced_code_block_lua": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.lua", + "patterns": [ + { + "include": "source.lua" + } + ] + } + ] + }, + "fenced_code_block_makefile": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.makefile", + "patterns": [ + { + "include": "source.makefile" + } + ] + } + ] + }, + "fenced_code_block_perl": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.perl", + "patterns": [ + { + "include": "source.perl" + } + ] + } + ] + }, + "fenced_code_block_r": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.r", + "patterns": [ + { + "include": "source.r" + } + ] + } + ] + }, + "fenced_code_block_ruby": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.ruby", + "patterns": [ + { + "include": "source.ruby" + } + ] + } + ] + }, + "fenced_code_block_php": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.php", + "patterns": [ + { + "include": "text.html.basic" + }, + { + "include": "source.php" + } + ] + } + ] + }, + "fenced_code_block_sql": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.sql", + "patterns": [ + { + "include": "source.sql" + } + ] + } + ] + }, + "fenced_code_block_vs_net": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.vs_net", + "patterns": [ + { + "include": "source.asp.vb.net" + } + ] + } + ] + }, + "fenced_code_block_xml": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.xml", + "patterns": [ + { + "include": "text.xml" + } + ] + } + ] + }, + "fenced_code_block_xsl": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.xsl", + "patterns": [ + { + "include": "text.xml.xsl" + } + ] + } + ] + }, + "fenced_code_block_yaml": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.yaml", + "patterns": [ + { + "include": "source.yaml" + } + ] + } + ] + }, + "fenced_code_block_dosbatch": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.dosbatch", + "patterns": [ + { + "include": "source.batchfile" + } + ] + } + ] + }, + "fenced_code_block_clojure": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.clojure", + "patterns": [ + { + "include": "source.clojure" + } + ] + } + ] + }, + "fenced_code_block_coffee": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.coffee", + "patterns": [ + { + "include": "source.coffee" + } + ] + } + ] + }, + "fenced_code_block_c": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.c", + "patterns": [ + { + "include": "source.c" + } + ] + } + ] + }, + "fenced_code_block_cpp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.cpp source.cpp", + "patterns": [ + { + "include": "source.cpp" + } + ] + } + ] + }, + "fenced_code_block_diff": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.diff", + "patterns": [ + { + "include": "source.diff" + } + ] + } + ] + }, + "fenced_code_block_dockerfile": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.dockerfile", + "patterns": [ + { + "include": "source.dockerfile" + } + ] + } + ] + }, + "fenced_code_block_git_commit": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.git_commit", + "patterns": [ + { + "include": "text.git-commit" + } + ] + } + ] + }, + "fenced_code_block_git_rebase": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.git_rebase", + "patterns": [ + { + "include": "text.git-rebase" + } + ] + } + ] + }, + "fenced_code_block_go": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.go", + "patterns": [ + { + "include": "source.go" + } + ] + } + ] + }, + "fenced_code_block_groovy": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.groovy", + "patterns": [ + { + "include": "source.groovy" + } + ] + } + ] + }, + "fenced_code_block_pug": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.pug", + "patterns": [ + { + "include": "text.pug" + } + ] + } + ] + }, + "fenced_code_block_js": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|cjs|\\{\\.js.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.javascript", + "patterns": [ + { + "include": "source.js" + } + ] + } + ] + }, + "fenced_code_block_js_regexp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.js_regexp", + "patterns": [ + { + "include": "source.js.regexp" + } + ] + } + ] + }, + "fenced_code_block_json": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|json5|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.json", + "patterns": [ + { + "include": "source.json" + } + ] + } + ] + }, + "fenced_code_block_jsonc": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jsonc)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.jsonc", + "patterns": [ + { + "include": "source.json.comments" + } + ] + } + ] + }, + "fenced_code_block_less": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.less", + "patterns": [ + { + "include": "source.css.less" + } + ] + } + ] + }, + "fenced_code_block_objc": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.objc", + "patterns": [ + { + "include": "source.objc" + } + ] + } + ] + }, + "fenced_code_block_swift": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(swift)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.swift", + "patterns": [ + { + "include": "source.swift" + } + ] + } + ] + }, + "fenced_code_block_scss": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.scss", + "patterns": [ + { + "include": "source.css.scss" + } + ] + } + ] + }, + "fenced_code_block_perl6": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.perl6", + "patterns": [ + { + "include": "source.perl.6" + } + ] + } + ] + }, + "fenced_code_block_powershell": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.powershell", + "patterns": [ + { + "include": "source.powershell" + } + ] + } + ] + }, + "fenced_code_block_python": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.python", + "patterns": [ + { + "include": "source.python" + } + ] + } + ] + }, + "fenced_code_block_regexp_python": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.regexp_python", + "patterns": [ + { + "include": "source.regexp.python" + } + ] + } + ] + }, + "fenced_code_block_rust": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.rust", + "patterns": [ + { + "include": "source.rust" + } + ] + } + ] + }, + "fenced_code_block_scala": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.scala", + "patterns": [ + { + "include": "source.scala" + } + ] + } + ] + }, + "fenced_code_block_shell": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.shellscript", + "patterns": [ + { + "include": "source.shell" + } + ] + } + ] + }, + "fenced_code_block_ts": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typescript", + "patterns": [ + { + "include": "source.ts" + } + ] + } + ] + }, + "fenced_code_block_tsx": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.typescriptreact", + "patterns": [ + { + "include": "source.tsx" + } + ] + } + ] + }, + "fenced_code_block_csharp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.csharp", + "patterns": [ + { + "include": "source.cs" + } + ] + } + ] + }, + "fenced_code_block_fsharp": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.fsharp", + "patterns": [ + { + "include": "source.fsharp" + } + ] + } + ] + }, + "fenced_code_block_dart": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dart)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.dart", + "patterns": [ + { + "include": "source.dart" + } + ] + } + ] + }, + "fenced_code_block_handlebars": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(handlebars|hbs)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.handlebars", + "patterns": [ + { + "include": "text.html.handlebars" + } + ] + } + ] + }, + "fenced_code_block_markdown": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(markdown|md)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.markdown", + "patterns": [ + { + "include": "text.html.markdown" + } + ] + } + ] + }, + "fenced_code_block_log": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(log)((\\s+|:|\\{)[^`~]*)?$)", + "name": "markup.fenced_code.block.markdown", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language.markdown" + }, + "5": { + "name": "fenced_code.block.language.attributes.markdown" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.log", + "patterns": [ + { + "include": "text.log" + } + ] + } + ] + }, + "fenced_code_block": { + "patterns": [ + { + "include": "#fenced_code_block_css" + }, + { + "include": "#fenced_code_block_basic" + }, + { + "include": "#fenced_code_block_ini" + }, + { + "include": "#fenced_code_block_java" + }, + { + "include": "#fenced_code_block_lua" + }, + { + "include": "#fenced_code_block_makefile" + }, + { + "include": "#fenced_code_block_perl" + }, + { + "include": "#fenced_code_block_r" + }, + { + "include": "#fenced_code_block_ruby" + }, + { + "include": "#fenced_code_block_php" + }, + { + "include": "#fenced_code_block_sql" + }, + { + "include": "#fenced_code_block_vs_net" + }, + { + "include": "#fenced_code_block_xml" + }, + { + "include": "#fenced_code_block_xsl" + }, + { + "include": "#fenced_code_block_yaml" + }, + { + "include": "#fenced_code_block_dosbatch" + }, + { + "include": "#fenced_code_block_clojure" + }, + { + "include": "#fenced_code_block_coffee" + }, + { + "include": "#fenced_code_block_c" + }, + { + "include": "#fenced_code_block_cpp" + }, + { + "include": "#fenced_code_block_diff" + }, + { + "include": "#fenced_code_block_dockerfile" + }, + { + "include": "#fenced_code_block_git_commit" + }, + { + "include": "#fenced_code_block_git_rebase" + }, + { + "include": "#fenced_code_block_go" + }, + { + "include": "#fenced_code_block_groovy" + }, + { + "include": "#fenced_code_block_pug" + }, + { + "include": "#fenced_code_block_js" + }, + { + "include": "#fenced_code_block_js_regexp" + }, + { + "include": "#fenced_code_block_json" + }, + { + "include": "#fenced_code_block_jsonc" + }, + { + "include": "#fenced_code_block_less" + }, + { + "include": "#fenced_code_block_objc" + }, + { + "include": "#fenced_code_block_swift" + }, + { + "include": "#fenced_code_block_scss" + }, + { + "include": "#fenced_code_block_perl6" + }, + { + "include": "#fenced_code_block_powershell" + }, + { + "include": "#fenced_code_block_python" + }, + { + "include": "#fenced_code_block_regexp_python" + }, + { + "include": "#fenced_code_block_rust" + }, + { + "include": "#fenced_code_block_scala" + }, + { + "include": "#fenced_code_block_shell" + }, + { + "include": "#fenced_code_block_ts" + }, + { + "include": "#fenced_code_block_tsx" + }, + { + "include": "#fenced_code_block_csharp" + }, + { + "include": "#fenced_code_block_fsharp" + }, + { + "include": "#fenced_code_block_dart" + }, + { + "include": "#fenced_code_block_handlebars" + }, + { + "include": "#fenced_code_block_markdown" + }, + { + "include": "#fenced_code_block_log" + }, + { + "include": "#fenced_code_block_unknown" + } + ] + }, + "fenced_code_block_unknown": { + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?=([^`~]*)?$)", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "4": { + "name": "fenced_code.block.language" + } + }, + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "name": "markup.fenced_code.block.markdown" + }, + "heading": { + "match": "(?:^|\\G)[ ]{0,3}((#{1,6})\\s+(?=[\\S[^#]]).*?\\s*(#{1,6})?)$\\n?", + "captures": { + "1": { + "patterns": [ + { + "match": "(#{6})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.6.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + }, + { + "match": "(#{5})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.5.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + }, + { + "match": "(#{4})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.4.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + }, + { + "match": "(#{3})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.3.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + }, + { + "match": "(#{2})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.2.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + }, + { + "match": "(#{1})\\s+(?=[\\S[^#]])(.*?)\\s*(\\s+#+)?$\\n?", + "name": "heading.1.markdown", + "captures": { + "1": { + "name": "punctuation.definition.heading.markdown" + }, + "2": { + "name": "entity.name.section.markdown" + }, + "3": { + "name": "punctuation.definition.heading.markdown" + } + } + } + ] + } + }, + "name": "markup.heading.markdown", + "patterns": [ + { + "include": "#inline" + } + ] + }, + "heading-setext": { + "patterns": [ + { + "match": "^(={3,})(?=[ \\t]*$\\n?)", + "name": "markup.heading.setext.1.markdown" + }, + { + "match": "^(-{3,})(?=[ \\t]*$\\n?)", + "name": "markup.heading.setext.2.markdown" + } + ] + }, + "html": { + "patterns": [ + { + "begin": "(^|\\G)\\s*()", + "name": "comment.block.html" + }, + { + "begin": "(?i)(^|\\G)\\s*(?=<(script|style|pre)(\\s|$|>)(?!.*?))", + "end": "(?i)(.*)(())", + "endCaptures": { + "1": { + "patterns": [ + { + "include": "text.html.derivative" + } + ] + }, + "2": { + "name": "meta.tag.structure.$4.end.html" + }, + "3": { + "name": "punctuation.definition.tag.begin.html" + }, + "4": { + "name": "entity.name.tag.html" + }, + "5": { + "name": "punctuation.definition.tag.end.html" + } + }, + "patterns": [ + { + "begin": "(\\s*|$)", + "patterns": [ + { + "include": "text.html.derivative" + } + ], + "while": "(?i)^(?!.*)" + } + ] + }, + { + "begin": "(?i)(^|\\G)\\s*(?=))", + "patterns": [ + { + "include": "text.html.derivative" + } + ], + "while": "^(?!\\s*$)" + }, + { + "begin": "(^|\\G)\\s*(?=(<[a-zA-Z0-9\\-](/?>|\\s.*?>)|)\\s*$)", + "patterns": [ + { + "include": "text.html.derivative" + } + ], + "while": "^(?!\\s*$)" + } + ] + }, + "link-def": { + "captures": { + "1": { + "name": "punctuation.definition.constant.markdown" + }, + "2": { + "name": "constant.other.reference.link.markdown" + }, + "3": { + "name": "punctuation.definition.constant.markdown" + }, + "4": { + "name": "punctuation.separator.key-value.markdown" + }, + "5": { + "name": "punctuation.definition.link.markdown" + }, + "6": { + "name": "markup.underline.link.markdown" + }, + "7": { + "name": "punctuation.definition.link.markdown" + }, + "8": { + "name": "string.other.link.description.title.markdown" + }, + "9": { + "name": "punctuation.definition.string.begin.markdown" + }, + "10": { + "name": "punctuation.definition.string.end.markdown" + }, + "11": { + "name": "string.other.link.description.title.markdown" + }, + "12": { + "name": "punctuation.definition.string.begin.markdown" + }, + "13": { + "name": "punctuation.definition.string.end.markdown" + } + }, + "match": "(?x)\n \\s* # Leading whitespace\n (\\[)([^]]+?)(\\])(:) # Reference name\n [ \\t]* # Optional whitespace\n (?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in quotes…\n | ((\").+?(\")) # or in parens.\n )? # Title is optional\n \\s* # Optional whitespace\n $\n", + "name": "meta.link.reference.def.markdown" + }, + "list_paragraph": { + "begin": "(^|\\G)(?=\\S)(?![*+->]\\s|[0-9]+\\.\\s)", + "name": "meta.paragraph.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + }, + { + "include": "#heading-setext" + } + ], + "while": "(^|\\G)(?!\\s*$|#|[ ]{0,3}([-*_>][ ]{2,}){3,}[ \\t]*$\\n?|[ ]{0,3}[*+->]|[ ]{0,3}[0-9]+\\.)" + }, + "lists": { + "patterns": [ + { + "begin": "(^|\\G)([ ]{0,3})([*+-])([ \\t])", + "beginCaptures": { + "3": { + "name": "punctuation.definition.list.begin.markdown" + } + }, + "comment": "Currently does not support un-indented second lines.", + "name": "markup.list.unnumbered.markdown", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#list_paragraph" + } + ], + "while": "((^|\\G)([ ]{2,4}|\\t))|(^[ \\t]*$)" + }, + { + "begin": "(^|\\G)([ ]{0,3})([0-9]+\\.)([ \\t])", + "beginCaptures": { + "3": { + "name": "punctuation.definition.list.begin.markdown" + } + }, + "name": "markup.list.numbered.markdown", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#list_paragraph" + } + ], + "while": "((^|\\G)([ ]{2,4}|\\t))|(^[ \\t]*$)" + } + ] + }, + "paragraph": { + "begin": "(^|\\G)[ ]{0,3}(?=\\S)", + "name": "meta.paragraph.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + }, + { + "include": "#heading-setext" + } + ], + "while": "(^|\\G)((?=\\s*[-=]{3,}\\s*$)|[ ]{4,}(?=\\S))" + }, + "raw_block": { + "begin": "(^|\\G)([ ]{4}|\\t)", + "name": "markup.raw.block.markdown", + "while": "(^|\\G)([ ]{4}|\\t)" + }, + "separator": { + "match": "(^|\\G)[ ]{0,3}([\\*\\-\\_])([ ]{0,2}\\2){2,}[ \\t]*$\\n?", + "name": "meta.separator.markdown" + }, + "frontMatter": { + "begin": "\\A-{3}\\s*$", + "contentName": "meta.embedded.block.frontmatter", + "patterns": [ + { + "include": "source.yaml" + } + ], + "end": "(^|\\G)-{3}|\\.{3}\\s*$" + }, + "inline": { + "patterns": [ + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#bold" + }, + { + "include": "#italic" + }, + { + "include": "#raw" + }, + { + "include": "#escape" + }, + { + "include": "#image-inline" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-email" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-ref" + }, + { + "include": "#link-ref-literal" + }, + { + "include": "#link-ref-shortcut" + } + ] + }, + "ampersand": { + "comment": "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.", + "match": "&(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)", + "name": "meta.other.valid-ampersand.markdown" + }, + "bold": { + "begin": "(?x) (?(\\*\\*(?=\\w)|(?]*+> # HTML tags\n | (?`+)([^`]|(?!(?(?!`))`)*+\\k\n # Raw\n | \\\\[\\\\`*_{}\\[\\]()#.!+\\->]?+ # Escapes\n | \\[\n (\n (? # Named group\n [^\\[\\]\\\\] # Match most chars\n | \\\\. # Escaped chars\n | \\[ \\g*+ \\] # Nested brackets\n )*+\n \\]\n (\n ( # Reference Link\n [ ]? # Optional space\n \\[[^\\]]*+\\] # Ref name\n )\n | ( # Inline Link\n \\( # Opening paren\n [ \\t]*+ # Optional whitespace\n ? # URL\n [ \\t]*+ # Optional whitespace\n ( # Optional Title\n (?['\"])\n (.*?)\n \\k<title>\n )?\n \\)\n )\n )\n )\n | (?!(?<=\\S)\\k<open>). # Everything besides\n # style closer\n )++\n (?<=\\S)(?=__\\b|\\*\\*)\\k<open> # Close\n)\n", + "captures": { + "1": { + "name": "punctuation.definition.bold.markdown" + } + }, + "end": "(?<=\\S)(\\1)", + "name": "markup.bold.markdown", + "patterns": [ + { + "applyEndPatternLast": 1, + "begin": "(?=<[^>]*?>)", + "end": "(?<=>)", + "patterns": [ + { + "include": "text.html.derivative" + } + ] + }, + { + "include": "#escape" + }, + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#raw" + }, + { + "include": "#bold" + }, + { + "include": "#italic" + }, + { + "include": "#image-inline" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-email" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-ref-literal" + }, + { + "include": "#link-ref" + }, + { + "include": "#link-ref-shortcut" + } + ] + }, + "bracket": { + "comment": "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.", + "match": "<(?![a-zA-Z/?\\$!])", + "name": "meta.other.valid-bracket.markdown" + }, + "escape": { + "match": "\\\\[-`*_#+.!(){}\\[\\]\\\\>]", + "name": "constant.character.escape.markdown" + }, + "image-inline": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.description.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.metadata.markdown" + }, + "6": { + "name": "punctuation.definition.link.markdown" + }, + "7": { + "name": "markup.underline.link.image.markdown" + }, + "8": { + "name": "punctuation.definition.link.markdown" + }, + "9": { + "name": "string.other.link.description.title.markdown" + }, + "10": { + "name": "punctuation.definition.string.markdown" + }, + "11": { + "name": "punctuation.definition.string.markdown" + }, + "12": { + "name": "string.other.link.description.title.markdown" + }, + "13": { + "name": "punctuation.definition.string.markdown" + }, + "14": { + "name": "punctuation.definition.string.markdown" + }, + "15": { + "name": "punctuation.definition.metadata.markdown" + } + }, + "match": "(?x)\n (\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)(\\S+?)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", + "name": "meta.image.inline.markdown" + }, + "image-ref": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.description.markdown" + }, + "4": { + "name": "punctuation.definition.string.begin.markdown" + }, + "5": { + "name": "punctuation.definition.constant.markdown" + }, + "6": { + "name": "constant.other.reference.link.markdown" + }, + "7": { + "name": "punctuation.definition.constant.markdown" + } + }, + "match": "(\\!\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])[ ]?(\\[)(.*?)(\\])", + "name": "meta.image.reference.markdown" + }, + "italic": { + "begin": "(?x) (?<open>(\\*(?=\\w)|(?<!\\w)\\*|(?<!\\w)\\b_))(?=\\S) # Open\n (?=\n (\n <[^>]*+> # HTML tags\n | (?<raw>`+)([^`]|(?!(?<!`)\\k<raw>(?!`))`)*+\\k<raw>\n # Raw\n | \\\\[\\\\`*_{}\\[\\]()#.!+\\->]?+ # Escapes\n | \\[\n (\n (?<square> # Named group\n [^\\[\\]\\\\] # Match most chars\n | \\\\. # Escaped chars\n | \\[ \\g<square>*+ \\] # Nested brackets\n )*+\n \\]\n (\n ( # Reference Link\n [ ]? # Optional space\n \\[[^\\]]*+\\] # Ref name\n )\n | ( # Inline Link\n \\( # Opening paren\n [ \\t]*+ # Optional whtiespace\n <?(.*?)>? # URL\n [ \\t]*+ # Optional whtiespace\n ( # Optional Title\n (?<title>['\"])\n (.*?)\n \\k<title>\n )?\n \\)\n )\n )\n )\n | \\k<open>\\k<open> # Must be bold closer\n | (?!(?<=\\S)\\k<open>). # Everything besides\n # style closer\n )++\n (?<=\\S)(?=_\\b|\\*)\\k<open> # Close\n )\n", + "captures": { + "1": { + "name": "punctuation.definition.italic.markdown" + } + }, + "end": "(?<=\\S)(\\1)((?!\\1)|(?=\\1\\1))", + "name": "markup.italic.markdown", + "patterns": [ + { + "applyEndPatternLast": 1, + "begin": "(?=<[^>]*?>)", + "end": "(?<=>)", + "patterns": [ + { + "include": "text.html.derivative" + } + ] + }, + { + "include": "#escape" + }, + { + "include": "#ampersand" + }, + { + "include": "#bracket" + }, + { + "include": "#raw" + }, + { + "include": "#bold" + }, + { + "include": "#image-inline" + }, + { + "include": "#link-inline" + }, + { + "include": "#link-inet" + }, + { + "include": "#link-email" + }, + { + "include": "#image-ref" + }, + { + "include": "#link-ref-literal" + }, + { + "include": "#link-ref" + }, + { + "include": "#link-ref-shortcut" + } + ] + }, + "link-email": { + "captures": { + "1": { + "name": "punctuation.definition.link.markdown" + }, + "2": { + "name": "markup.underline.link.markdown" + }, + "4": { + "name": "punctuation.definition.link.markdown" + } + }, + "match": "(<)((?:mailto:)?[-.\\w]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)(>)", + "name": "meta.link.email.lt-gt.markdown" + }, + "link-inet": { + "captures": { + "1": { + "name": "punctuation.definition.link.markdown" + }, + "2": { + "name": "markup.underline.link.markdown" + }, + "3": { + "name": "punctuation.definition.link.markdown" + } + }, + "match": "(<)((?:https?|ftp)://.*?)(>)", + "name": "meta.link.inet.markdown" + }, + "link-inline": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.metadata.markdown" + }, + "6": { + "name": "punctuation.definition.link.markdown" + }, + "7": { + "name": "markup.underline.link.markdown" + }, + "9": { + "name": "punctuation.definition.link.markdown" + }, + "10": { + "name": "string.other.link.description.title.markdown" + }, + "11": { + "name": "punctuation.definition.string.begin.markdown" + }, + "12": { + "name": "punctuation.definition.string.end.markdown" + }, + "13": { + "name": "string.other.link.description.title.markdown" + }, + "14": { + "name": "punctuation.definition.string.begin.markdown" + }, + "15": { + "name": "punctuation.definition.string.end.markdown" + }, + "16": { + "name": "punctuation.definition.metadata.markdown" + } + }, + "match": "(?x)\n (\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])\n # Match the link text.\n (\\() # Opening paren for url\n (<?)((?<url>(?>[^\\s()]+)|\\(\\g<url>*\\))*)(>?) # The url\n [ \\t]* # Optional whitespace\n (?:\n ((\\().+?(\\))) # Match title in parens…\n | ((\").+?(\")) # or in quotes.\n )? # Title is optional\n \\s* # Optional whitespace\n (\\))\n", + "name": "meta.link.inline.markdown" + }, + "link-ref": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.constant.begin.markdown" + }, + "6": { + "name": "constant.other.reference.link.markdown" + }, + "7": { + "name": "punctuation.definition.constant.end.markdown" + } + }, + "match": "(\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])(\\[)([^\\]]*+)(\\])", + "name": "meta.link.reference.markdown" + }, + "link-ref-literal": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "4": { + "name": "punctuation.definition.string.end.markdown" + }, + "5": { + "name": "punctuation.definition.constant.begin.markdown" + }, + "6": { + "name": "punctuation.definition.constant.end.markdown" + } + }, + "match": "(\\[)((?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])*+)(\\])[ ]?(\\[)(\\])", + "name": "meta.link.reference.literal.markdown" + }, + "link-ref-shortcut": { + "captures": { + "1": { + "name": "punctuation.definition.string.begin.markdown" + }, + "2": { + "name": "string.other.link.title.markdown" + }, + "3": { + "name": "punctuation.definition.string.end.markdown" + } + }, + "match": "(\\[)(\\S+?)(\\])", + "name": "meta.link.reference.markdown" + }, + "raw": { + "captures": { + "1": { + "name": "punctuation.definition.raw.markdown" + }, + "3": { + "name": "punctuation.definition.raw.markdown" + } + }, + "match": "(`+)([^`]|(?!(?<!`)\\1(?!`))`)*+(\\1)", + "name": "markup.inline.raw.string.markdown" + } + } +} diff --git a/tsconfig.json b/tsconfig.json index b65c745..b9534e2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,16 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "lib": [ - "es6" - ], - "sourceMap": true, - "rootDir": "src", - "strict": true /* enable all strict type-checking options */ - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - }, - "exclude": [ - "node_modules", - ".vscode-test" - ] + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "out", + "lib": ["es6"], + "sourceMap": true, + "rootDir": "src", + "strict": true /* enable all strict type-checking options */ + /* Additional Checks */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + }, + "exclude": ["node_modules", ".vscode-test"] }