Archived
Refresh master with initial release/0.24 snapshot (#332)
* Initial port of release/0.24 source code * Fix additional headers * Fix a typo in launch.json
This commit is contained in:
@@ -18,5 +18,11 @@
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""]
|
||||
]
|
||||
}
|
||||
],
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*(::\\s*|REM\\s+)#region",
|
||||
"end": "^\\s*(::\\s*|REM\\s+)#endregion"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,19 +33,11 @@
|
||||
},
|
||||
{
|
||||
"fileMatch": "vscode://defaultsettings/settings.json",
|
||||
"url": "vscode://schemas/settings"
|
||||
},
|
||||
{
|
||||
"fileMatch": "vscode://defaultsettings/resourceSettings.json",
|
||||
"url": "vscode://schemas/settings/resource"
|
||||
},
|
||||
{
|
||||
"fileMatch": "vscode://settings/workspaceSettings.json",
|
||||
"url": "vscode://schemas/settings"
|
||||
"url": "vscode://schemas/settings/default"
|
||||
},
|
||||
{
|
||||
"fileMatch": "%APP_SETTINGS_HOME%/settings.json",
|
||||
"url": "vscode://schemas/settings"
|
||||
"url": "vscode://schemas/settings/user"
|
||||
},
|
||||
{
|
||||
"fileMatch": "%APP_WORKSPACES_HOME%/*/workspace.json",
|
||||
@@ -60,15 +52,15 @@
|
||||
"url": "vscode://schemas/locale"
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.sqlops/settings.json",
|
||||
"url": "vscode://schemas/settings"
|
||||
"fileMatch": "/.vscode/settings.json",
|
||||
"url": "vscode://schemas/settings/folder"
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.sqlops/launch.json",
|
||||
"fileMatch": "/.vscode/launch.json",
|
||||
"url": "vscode://schemas/launch"
|
||||
},
|
||||
{
|
||||
"fileMatch": "/.sqlops/tasks.json",
|
||||
"fileMatch": "/.vscode/tasks.json",
|
||||
"url": "vscode://schemas/tasks"
|
||||
},
|
||||
{
|
||||
@@ -82,6 +74,6 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.4"
|
||||
"@types/node": "7.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ export function activate(context): void {
|
||||
//settings.json suggestions
|
||||
context.subscriptions.push(registerSettingsCompletions());
|
||||
|
||||
//extensions.json suggestions
|
||||
context.subscriptions.push(registerExtensionsCompletions());
|
||||
//extensions suggestions
|
||||
context.subscriptions.push(...registerExtensionsCompletions());
|
||||
|
||||
// launch.json decorations
|
||||
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => updateLaunchJsonDecorations(editor), null, context.subscriptions));
|
||||
@@ -67,43 +67,69 @@ function registerSettingsCompletions(): vscode.Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
function registerExtensionsCompletions(): vscode.Disposable {
|
||||
interface IExtensionsContent {
|
||||
recommendations: string[];
|
||||
}
|
||||
|
||||
function registerExtensionsCompletions(): vscode.Disposable[] {
|
||||
return [registerExtensionsCompletionsInExtensionsDocument(), registerExtensionsCompletionsInWorkspaceConfigurationDocument()];
|
||||
}
|
||||
|
||||
function registerExtensionsCompletionsInExtensionsDocument(): vscode.Disposable {
|
||||
return vscode.languages.registerCompletionItemProvider({ pattern: '**/extensions.json' }, {
|
||||
provideCompletionItems(document, position, token) {
|
||||
const location = getLocation(document.getText(), document.offsetAt(position));
|
||||
const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||
if (location.path[0] === 'recommendations') {
|
||||
const config = parse(document.getText());
|
||||
const alreadyEnteredExtensions = config && config.recommendations || [];
|
||||
if (Array.isArray(alreadyEnteredExtensions)) {
|
||||
const knownExtensionProposals = vscode.extensions.all.filter(e =>
|
||||
!(e.id.startsWith('vscode.')
|
||||
|| e.id === 'Microsoft.vscode-markdown'
|
||||
|| alreadyEnteredExtensions.indexOf(e.id) > -1));
|
||||
if (knownExtensionProposals.length) {
|
||||
return knownExtensionProposals.map(e => {
|
||||
const item = new vscode.CompletionItem(e.id);
|
||||
const insertText = `"${e.id}"`;
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = insertText;
|
||||
item.range = range;
|
||||
item.filterText = insertText;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
const example = new vscode.CompletionItem(localize('exampleExtension', "Example"));
|
||||
example.insertText = '"vscode.csharp"';
|
||||
example.kind = vscode.CompletionItemKind.Value;
|
||||
example.range = range;
|
||||
return [example];
|
||||
}
|
||||
}
|
||||
const extensionsContent = <IExtensionsContent>parse(document.getText());
|
||||
return provideInstalledExtensionProposals(extensionsContent, range);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function registerExtensionsCompletionsInWorkspaceConfigurationDocument(): vscode.Disposable {
|
||||
return vscode.languages.registerCompletionItemProvider({ pattern: '**/*.code-workspace' }, {
|
||||
provideCompletionItems(document, position, token) {
|
||||
const location = getLocation(document.getText(), document.offsetAt(position));
|
||||
const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
|
||||
if (location.path[0] === 'extensions' && location.path[1] === 'recommendations') {
|
||||
const extensionsContent = <IExtensionsContent>parse(document.getText())['extensions'];
|
||||
return provideInstalledExtensionProposals(extensionsContent, range);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function provideInstalledExtensionProposals(extensionsContent: IExtensionsContent, range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
const alreadyEnteredExtensions = extensionsContent && extensionsContent.recommendations || [];
|
||||
if (Array.isArray(alreadyEnteredExtensions)) {
|
||||
const knownExtensionProposals = vscode.extensions.all.filter(e =>
|
||||
!(e.id.startsWith('vscode.')
|
||||
|| e.id === 'Microsoft.vscode-markdown'
|
||||
|| alreadyEnteredExtensions.indexOf(e.id) > -1));
|
||||
if (knownExtensionProposals.length) {
|
||||
return knownExtensionProposals.map(e => {
|
||||
const item = new vscode.CompletionItem(e.id);
|
||||
const insertText = `"${e.id}"`;
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = insertText;
|
||||
item.range = range;
|
||||
item.filterText = insertText;
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
const example = new vscode.CompletionItem(localize('exampleExtension', "Example"));
|
||||
example.insertText = '"vscode.csharp"';
|
||||
example.kind = vscode.CompletionItemKind.Value;
|
||||
example.range = range;
|
||||
return [example];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function newSimpleCompletionItem(label: string, range: vscode.Range, description?: string, insertText?: string): vscode.CompletionItem {
|
||||
const item = new vscode.CompletionItem(label);
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
|
||||
@@ -43,13 +43,13 @@ export class SettingsDocument {
|
||||
private provideWindowTitleCompletionItems(location: Location, range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[]> {
|
||||
const completions: vscode.CompletionItem[] = [];
|
||||
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "e.g. myFile.txt")));
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "e.g. myFolder/myFile.txt")));
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "e.g. /Users/Development/myProject/myFolder/myFile.txt")));
|
||||
completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "e.g. myFolder1, myFolder2, myFolder3")));
|
||||
completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "e.g. /Users/Development/myProject")));
|
||||
completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "e.g. myFolder")));
|
||||
completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "e.g. /Users/Development/myFolder")));
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorShort}', range, localize('activeEditorShort', "the file name (e.g. myFile.txt)")));
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorMedium}', range, localize('activeEditorMedium', "the path of the file relative to the workspace folder (e.g. myFolder/myFile.txt)")));
|
||||
completions.push(this.newSimpleCompletionItem('${activeEditorLong}', range, localize('activeEditorLong', "the full path of the file (e.g. /Users/Development/myProject/myFolder/myFile.txt)")));
|
||||
completions.push(this.newSimpleCompletionItem('${rootName}', range, localize('rootName', "name of the workspace (e.g. myFolder or myWorkspace)")));
|
||||
completions.push(this.newSimpleCompletionItem('${rootPath}', range, localize('rootPath', "file path of the workspace (e.g. /Users/Development/myWorkspace)")));
|
||||
completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)")));
|
||||
completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)")));
|
||||
completions.push(this.newSimpleCompletionItem('${appName}', range, localize('appName', "e.g. VS Code")));
|
||||
completions.push(this.newSimpleCompletionItem('${dirty}', range, localize('dirty', "a dirty indicator if the active editor is dirty")));
|
||||
completions.push(this.newSimpleCompletionItem('${separator}', range, localize('separator', "a conditional separator (' - ') that only shows when surrounded by variables with values")));
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@
|
||||
"@types/node": {
|
||||
"version": "6.0.78",
|
||||
"from": "@types/node@>=6.0.46 <7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.78.tgz"
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.78.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.9",
|
||||
|
||||
@@ -47,6 +47,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/markdown-it": "0.0.2",
|
||||
"@types/node": "^7.0.4"
|
||||
"@types/node": "7.0.43"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ const _linkProvider = new class implements vscode.DocumentLinkProvider {
|
||||
|
||||
const offset = lookUp(match[1]);
|
||||
if (offset === -1) {
|
||||
console.warn(match[1]);
|
||||
console.warn(`Could not find symbol for link ${match[1]}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ import * as path from 'path';
|
||||
|
||||
import { parseTree, findNodeAtLocation, Node as JsonNode } from 'jsonc-parser';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as MarkdownIt from 'markdown-it';
|
||||
import * as parse5 from 'parse5';
|
||||
import * as MarkdownItType from 'markdown-it';
|
||||
|
||||
import { languages, workspace, Disposable, ExtensionContext, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position } from 'vscode';
|
||||
|
||||
@@ -33,7 +32,7 @@ enum Context {
|
||||
}
|
||||
|
||||
interface TokenAndPosition {
|
||||
token: MarkdownIt.Token;
|
||||
token: MarkdownItType.Token;
|
||||
begin: number;
|
||||
end: number;
|
||||
}
|
||||
@@ -53,7 +52,7 @@ export class ExtensionLinter {
|
||||
private packageJsonQ = new Set<TextDocument>();
|
||||
private readmeQ = new Set<TextDocument>();
|
||||
private timer: NodeJS.Timer;
|
||||
private markdownIt = new MarkdownIt();
|
||||
private markdownIt: MarkdownItType.MarkdownIt;
|
||||
|
||||
constructor(private context: ExtensionContext) {
|
||||
this.disposables.push(
|
||||
@@ -148,8 +147,11 @@ export class ExtensionLinter {
|
||||
}
|
||||
|
||||
const text = document.getText();
|
||||
if (!this.markdownIt) {
|
||||
this.markdownIt = new (await import('markdown-it'));
|
||||
}
|
||||
const tokens = this.markdownIt.parse(text, {});
|
||||
const tokensAndPositions = (function toTokensAndPositions(this: ExtensionLinter, tokens: MarkdownIt.Token[], begin = 0, end = text.length): TokenAndPosition[] {
|
||||
const tokensAndPositions = (function toTokensAndPositions(this: ExtensionLinter, tokens: MarkdownItType.Token[], begin = 0, end = text.length): TokenAndPosition[] {
|
||||
const tokensAndPositions = tokens.map<TokenAndPosition>(token => {
|
||||
if (token.map) {
|
||||
const tokenBegin = document.offsetAt(new Position(token.map[0], 0));
|
||||
@@ -192,8 +194,9 @@ export class ExtensionLinter {
|
||||
});
|
||||
|
||||
let svgStart: Diagnostic;
|
||||
tokensAndPositions.filter(tnp => tnp.token.type === 'text' && tnp.token.content)
|
||||
.map(tnp => {
|
||||
for (const tnp of tokensAndPositions) {
|
||||
if (tnp.token.type === 'text' && tnp.token.content) {
|
||||
const parse5 = await import('parse5');
|
||||
const parser = new parse5.SAXParser({ locationInfo: true });
|
||||
parser.on('startTag', (name, attrs, selfClosing, location) => {
|
||||
if (name === 'img') {
|
||||
@@ -220,13 +223,14 @@ export class ExtensionLinter {
|
||||
});
|
||||
parser.write(tnp.token.content);
|
||||
parser.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.diagnosticsCollection.set(document.uri, diagnostics);
|
||||
};
|
||||
}
|
||||
|
||||
private locateToken(text: string, begin: number, end: number, token: MarkdownIt.Token, content: string) {
|
||||
private locateToken(text: string, begin: number, end: number, token: MarkdownItType.Token, content: string) {
|
||||
if (content) {
|
||||
const tokenBegin = text.indexOf(content, begin);
|
||||
if (tokenBegin !== -1) {
|
||||
|
||||
Generated
+6
-1
@@ -7,13 +7,18 @@
|
||||
"from": "applicationinsights@0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz"
|
||||
},
|
||||
"byline": {
|
||||
"version": "5.0.0",
|
||||
"from": "byline@latest",
|
||||
"resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz"
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.15",
|
||||
"from": "iconv-lite@0.4.15",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz"
|
||||
},
|
||||
"vscode-extension-telemetry": {
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"from": "vscode-extension-telemetry@>=0.0.8 <0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz"
|
||||
},
|
||||
|
||||
+110
-4
@@ -36,6 +36,11 @@
|
||||
"dark": "resources/icons/dark/git.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.close",
|
||||
"title": "%command.close%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.refresh",
|
||||
"title": "%command.refresh%",
|
||||
@@ -96,6 +101,24 @@
|
||||
"title": "%command.revertSelectedRanges%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.stageChange",
|
||||
"title": "%command.stageChange%",
|
||||
"category": "Git",
|
||||
"icon": {
|
||||
"light": "resources/icons/light/stage.svg",
|
||||
"dark": "resources/icons/dark/stage.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.revertChange",
|
||||
"title": "%command.revertChange%",
|
||||
"category": "Git",
|
||||
"icon": {
|
||||
"light": "resources/icons/light/clean.svg",
|
||||
"dark": "resources/icons/dark/clean.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"title": "%command.unstage%",
|
||||
@@ -310,10 +333,18 @@
|
||||
"command": "git.stageSelectedRanges",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.stageChange",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.revertSelectedRanges",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.revertChange",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
@@ -529,6 +560,11 @@
|
||||
"group": "3_commit",
|
||||
"when": "config.git.enabled && scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"group": "4_stage",
|
||||
"when": "config.git.enabled && scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"group": "4_stage",
|
||||
@@ -560,6 +596,13 @@
|
||||
"when": "config.git.enabled && scmProvider == git"
|
||||
}
|
||||
],
|
||||
"scm/sourceControl": [
|
||||
{
|
||||
"command": "git.close",
|
||||
"group": "navigation",
|
||||
"when": "config.git.enabled && scmProvider == git"
|
||||
}
|
||||
],
|
||||
"scm/resourceGroup/context": [
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
@@ -688,7 +731,7 @@
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"group": "navigation",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme != extension"
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file"
|
||||
},
|
||||
{
|
||||
"command": "git.stageSelectedRanges",
|
||||
@@ -705,6 +748,16 @@
|
||||
"group": "2_git@3",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0 && isInDiffEditor && resourceScheme != merge-conflict.conflict-diff"
|
||||
}
|
||||
],
|
||||
"scm/change/title": [
|
||||
{
|
||||
"command": "git.stageChange",
|
||||
"when": "config.git.enabled && originalResourceScheme == git"
|
||||
},
|
||||
{
|
||||
"command": "git.revertChange",
|
||||
"when": "config.git.enabled && originalResourceScheme == git"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
@@ -784,18 +837,71 @@
|
||||
"type": "boolean",
|
||||
"description": "%config.enableCommitSigning%",
|
||||
"default": false
|
||||
},
|
||||
"git.decorations.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%config.decorations.enabled%"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"colors": [
|
||||
{
|
||||
"id": "gitDecoration.modifiedResourceForeground",
|
||||
"description": "%colors.modified%",
|
||||
"defaults": {
|
||||
"light": "#a76e12",
|
||||
"dark": "#E2C08D",
|
||||
"highContrast": "#E2C08D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.deletedResourceForeground",
|
||||
"description": "%colors.deleted%",
|
||||
"defaults": {
|
||||
"light": "#ad0707",
|
||||
"dark": "#c74e39",
|
||||
"highContrast": "#c74e39"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.untrackedResourceForeground",
|
||||
"description": "%colors.untracked%",
|
||||
"defaults": {
|
||||
"light": "#019001",
|
||||
"dark": "#73C991",
|
||||
"highContrast": "#73C991"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.ignoredResourceForeground",
|
||||
"description": "%colors.ignored%",
|
||||
"defaults": {
|
||||
"light": "#8E8E90",
|
||||
"dark": "#A7A8A9",
|
||||
"highContrast": "#A7A8A9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.conflictingResourceForeground",
|
||||
"description": "%colors.conflict%",
|
||||
"defaults": {
|
||||
"light": "#6c6cc4",
|
||||
"dark": "#6c6cc4",
|
||||
"highContrast": "#6c6cc4"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"byline": "^5.0.0",
|
||||
"iconv-lite": "0.4.15",
|
||||
"vscode-extension-telemetry": "0.0.8",
|
||||
"vscode-nls": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^2.2.41",
|
||||
"@types/node": "^7.0.4",
|
||||
"@types/mocha": "2.2.43",
|
||||
"@types/node": "7.0.43",
|
||||
"mocha": "^3.2.0"
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
"command.stageAll": "Stage All Changes",
|
||||
"command.stageSelectedRanges": "Stage Selected Ranges",
|
||||
"command.revertSelectedRanges": "Revert Selected Ranges",
|
||||
"command.stageChange": "Stage Change",
|
||||
"command.revertChange": "Revert Change",
|
||||
"command.unstage": "Unstage Changes",
|
||||
"command.unstageAll": "Unstage All Changes",
|
||||
"command.unstageSelectedRanges": "Unstage Selected Ranges",
|
||||
@@ -54,5 +56,11 @@
|
||||
"config.defaultCloneDirectory": "The default location where to clone a git repository",
|
||||
"config.enableSmartCommit": "Commit all changes when there are no staged changes.",
|
||||
"config.enableCommitSigning": "Enables commit signing with GPG.",
|
||||
"config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run."
|
||||
}
|
||||
"config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.",
|
||||
"config.decorations.enabled": "Controls if Git contributes colors and badges to the explorer and the open editors view.",
|
||||
"colors.modified": "Color for modified resources.",
|
||||
"colors.deleted": "Color for deleted resources.",
|
||||
"colors.untracked": "Color for untracked resources.",
|
||||
"colors.ignored": "Color for ignored resources.",
|
||||
"colors.conflict": "Color for resources with conflicts."
|
||||
}
|
||||
|
||||
@@ -5,16 +5,23 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { workspace, Disposable } from 'vscode';
|
||||
import { workspace, Disposable, EventEmitter } from 'vscode';
|
||||
import { GitErrorCodes } from './git';
|
||||
import { Repository } from './repository';
|
||||
import { throttle } from './decorators';
|
||||
import { eventToPromise, filterEvent } from './util';
|
||||
|
||||
export class AutoFetcher {
|
||||
|
||||
private static Period = 3 * 60 * 1000 /* three minutes */;
|
||||
|
||||
private _onDidChange = new EventEmitter<boolean>();
|
||||
private onDidChange = this._onDidChange.event;
|
||||
|
||||
private _enabled: boolean = false;
|
||||
get enabled(): boolean { return this._enabled; }
|
||||
set enabled(enabled: boolean) { this._enabled = enabled; this._onDidChange.fire(enabled); }
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
private timer: NodeJS.Timer;
|
||||
|
||||
constructor(private repository: Repository) {
|
||||
workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables);
|
||||
@@ -32,26 +39,41 @@ export class AutoFetcher {
|
||||
}
|
||||
|
||||
enable(): void {
|
||||
if (this.timer) {
|
||||
if (this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetch();
|
||||
this.timer = setInterval(() => this.fetch(), AutoFetcher.Period);
|
||||
this.enabled = true;
|
||||
this.run();
|
||||
}
|
||||
|
||||
disable(): void {
|
||||
clearInterval(this.timer);
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
@throttle
|
||||
private async fetch(): Promise<void> {
|
||||
try {
|
||||
await this.repository.fetch();
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) {
|
||||
this.disable();
|
||||
private async run(): Promise<void> {
|
||||
while (this.enabled) {
|
||||
await this.repository.whenIdleAndFocused();
|
||||
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.repository.fetch();
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) {
|
||||
this.disable();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = new Promise(c => setTimeout(c, AutoFetcher.Period));
|
||||
const whenDisabled = eventToPromise(filterEvent(this.onDidChange, enabled => !enabled));
|
||||
await Promise.race([timeout, whenDisabled]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+183
-69
@@ -5,11 +5,12 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation } from 'vscode';
|
||||
import { Uri, commands, Disposable, window, workspace, QuickPickItem, OutputChannel, Range, WorkspaceEdit, Position, LineChange, SourceControlResourceState, TextDocumentShowOptions, ViewColumn, ProgressLocation, TextEditor } from 'vscode';
|
||||
import { Ref, RefType, Git, GitErrorCodes, Branch } from './git';
|
||||
import { Repository, Resource, Status, CommitOptions, ResourceGroupType } from './repository';
|
||||
import { Model } from './model';
|
||||
import { toGitUri, fromGitUri } from './uri';
|
||||
import { grep } from './util';
|
||||
import { applyLineChanges, intersectDiffWithRange, toLineRanges, invertLineChange } from './staging';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
@@ -92,11 +93,13 @@ class MergeItem implements QuickPickItem {
|
||||
|
||||
class CreateBranchItem implements QuickPickItem {
|
||||
|
||||
constructor(private cc: CommandCenter) { }
|
||||
|
||||
get label(): string { return localize('create branch', '$(plus) Create new branch'); }
|
||||
get description(): string { return ''; }
|
||||
|
||||
async run(repository: Repository): Promise<void> {
|
||||
await commands.executeCommand('git.branch');
|
||||
await this.cc.branch(repository);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,12 +172,14 @@ export class CommandCenter {
|
||||
const opts: TextDocumentShowOptions = {
|
||||
preserveFocus,
|
||||
preview,
|
||||
viewColumn: window.activeTextEditor && window.activeTextEditor.viewColumn || ViewColumn.One
|
||||
viewColumn: ViewColumn.Active
|
||||
};
|
||||
|
||||
const activeTextEditor = window.activeTextEditor;
|
||||
|
||||
if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.fsPath === right.fsPath) {
|
||||
// Check if active text editor has same path as other editor. we cannot compare via
|
||||
// URI.toString() here because the schemas can be different. Instead we just go by path.
|
||||
if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.path === right.path) {
|
||||
opts.selection = activeTextEditor.selection;
|
||||
}
|
||||
|
||||
@@ -257,13 +262,20 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
@command('git.clone')
|
||||
async clone(): Promise<void> {
|
||||
const url = await window.showInputBox({
|
||||
prompt: localize('repourl', "Repository URL"),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
async clone(url?: string): Promise<void> {
|
||||
if (!url) {
|
||||
url = await window.showInputBox({
|
||||
prompt: localize('repourl', "Repository URL"),
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_URL' });
|
||||
return;
|
||||
}
|
||||
@@ -278,6 +290,11 @@ export class CommandCenter {
|
||||
});
|
||||
|
||||
if (!parentPath) {
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'no_directory' });
|
||||
return;
|
||||
}
|
||||
@@ -295,14 +312,30 @@ export class CommandCenter {
|
||||
const result = await window.showInformationMessage(localize('proposeopen', "Would you like to open the cloned repository?"), open);
|
||||
|
||||
const openFolder = result === open;
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"openFolder": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'success' }, { openFolder: openFolder ? 1 : 0 });
|
||||
if (openFolder) {
|
||||
commands.executeCommand('vscode.openFolder', Uri.file(repositoryPath));
|
||||
}
|
||||
} catch (err) {
|
||||
if (/already exists and is not an empty directory/.test(err && err.stderr || '')) {
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'directory_not_empty' });
|
||||
} else {
|
||||
/* __GDPR__
|
||||
"clone" : {
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('clone', { outcome: 'error' });
|
||||
}
|
||||
throw err;
|
||||
@@ -311,25 +344,44 @@ export class CommandCenter {
|
||||
|
||||
@command('git.init')
|
||||
async init(): Promise<void> {
|
||||
const value = workspace.workspaceFolders && workspace.workspaceFolders.length > 0
|
||||
? workspace.workspaceFolders[0].uri.fsPath
|
||||
: os.homedir();
|
||||
const homeUri = Uri.file(os.homedir());
|
||||
const defaultUri = workspace.workspaceFolders && workspace.workspaceFolders.length > 0
|
||||
? Uri.file(workspace.workspaceFolders[0].uri.fsPath)
|
||||
: homeUri;
|
||||
|
||||
const path = await window.showInputBox({
|
||||
placeHolder: localize('path to init', "Folder path"),
|
||||
prompt: localize('provide path', "Please provide a folder path to initialize a Git repository"),
|
||||
value,
|
||||
ignoreFocusOut: true
|
||||
const result = await window.showOpenDialog({
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
defaultUri,
|
||||
openLabel: localize('init repo', "Initialize Repository")
|
||||
});
|
||||
|
||||
if (!path) {
|
||||
if (!result || result.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uri = result[0];
|
||||
|
||||
if (homeUri.toString().startsWith(uri.toString())) {
|
||||
const yes = localize('create repo', "Initialize Repository");
|
||||
const answer = await window.showWarningMessage(localize('are you sure', "This will create a Git repository in '{0}'. Are you sure you want to continue?", uri.fsPath), yes);
|
||||
|
||||
if (answer !== yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const path = uri.fsPath;
|
||||
await this.git.init(path);
|
||||
await this.model.tryOpenRepository(path);
|
||||
}
|
||||
|
||||
@command('git.close', { repository: true })
|
||||
async close(repository: Repository): Promise<void> {
|
||||
this.model.close(repository);
|
||||
}
|
||||
|
||||
@command('git.openFile')
|
||||
async openFile(arg?: Resource | Uri, ...resourceStates: SourceControlResourceState[]): Promise<void> {
|
||||
const preserveFocus = arg instanceof Resource;
|
||||
@@ -364,11 +416,13 @@ export class CommandCenter {
|
||||
for (const uri of uris) {
|
||||
const opts: TextDocumentShowOptions = {
|
||||
preserveFocus,
|
||||
preview: preview,
|
||||
viewColumn: activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One
|
||||
preview,
|
||||
viewColumn: ViewColumn.Active
|
||||
};
|
||||
|
||||
if (activeTextEditor && activeTextEditor.document.uri.fsPath === uri.fsPath) {
|
||||
// Check if active text editor has same path as other editor. we cannot compare via
|
||||
// URI.toString() here because the schemas can be different. Instead we just go by path.
|
||||
if (activeTextEditor && activeTextEditor.document.uri.path === uri.path) {
|
||||
opts.selection = activeTextEditor.selection;
|
||||
}
|
||||
|
||||
@@ -451,12 +505,20 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
const selection = resourceStates.filter(s => s instanceof Resource) as Resource[];
|
||||
const mergeConflicts = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge);
|
||||
const merge = selection.filter(s => s.resourceGroupType === ResourceGroupType.Merge);
|
||||
const bothModified = merge.filter(s => s.type === Status.BOTH_MODIFIED);
|
||||
const promises = bothModified.map(s => grep(s.resourceUri.fsPath, /^<{7}|^={7}|^>{7}/));
|
||||
const unresolvedBothModified = await Promise.all<boolean>(promises);
|
||||
const resolvedConflicts = bothModified.filter((s, i) => !unresolvedBothModified[i]);
|
||||
const unresolvedConflicts = [
|
||||
...merge.filter(s => s.type !== Status.BOTH_MODIFIED),
|
||||
...bothModified.filter((s, i) => unresolvedBothModified[i])
|
||||
];
|
||||
|
||||
if (mergeConflicts.length > 0) {
|
||||
const message = mergeConflicts.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", mergeConflicts.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(mergeConflicts[0].resourceUri.fsPath));
|
||||
if (unresolvedConflicts.length > 0) {
|
||||
const message = unresolvedConflicts.length > 1
|
||||
? localize('confirm stage files with merge conflicts', "Are you sure you want to stage {0} files with merge conflicts?", unresolvedConflicts.length)
|
||||
: localize('confirm stage file with merge conflicts', "Are you sure you want to stage {0} with merge conflicts?", path.basename(unresolvedConflicts[0].resourceUri.fsPath));
|
||||
|
||||
const yes = localize('yes', "Yes");
|
||||
const pick = await window.showWarningMessage(message, { modal: true }, yes);
|
||||
@@ -466,10 +528,8 @@ export class CommandCenter {
|
||||
}
|
||||
}
|
||||
|
||||
const workingTree = selection
|
||||
.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree);
|
||||
|
||||
const scmResources = [...workingTree, ...mergeConflicts];
|
||||
const workingTree = selection.filter(s => s.resourceGroupType === ResourceGroupType.WorkingTree);
|
||||
const scmResources = [...workingTree, ...resolvedConflicts, ...unresolvedConflicts];
|
||||
|
||||
if (!scmResources.length) {
|
||||
return;
|
||||
@@ -500,14 +560,39 @@ export class CommandCenter {
|
||||
await repository.add([]);
|
||||
}
|
||||
|
||||
@command('git.stageChange')
|
||||
async stageChange(uri: Uri, changes: LineChange[], index: number): Promise<void> {
|
||||
const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0];
|
||||
|
||||
if (!textEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._stageChanges(textEditor, [changes[index]]);
|
||||
}
|
||||
|
||||
@command('git.stageSelectedRanges', { diff: true })
|
||||
async stageSelectedRanges(diffs: LineChange[]): Promise<void> {
|
||||
async stageSelectedChanges(changes: LineChange[]): Promise<void> {
|
||||
const textEditor = window.activeTextEditor;
|
||||
|
||||
if (!textEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modifiedDocument = textEditor.document;
|
||||
const selectedLines = toLineRanges(textEditor.selections, modifiedDocument);
|
||||
const selectedChanges = changes
|
||||
.map(diff => selectedLines.reduce<LineChange | null>((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null))
|
||||
.filter(d => !!d) as LineChange[];
|
||||
|
||||
if (!selectedChanges.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._stageChanges(textEditor, selectedChanges);
|
||||
}
|
||||
|
||||
private async _stageChanges(textEditor: TextEditor, changes: LineChange[]): Promise<void> {
|
||||
const modifiedDocument = textEditor.document;
|
||||
const modifiedUri = modifiedDocument.uri;
|
||||
|
||||
@@ -517,28 +602,48 @@ export class CommandCenter {
|
||||
|
||||
const originalUri = toGitUri(modifiedUri, '~');
|
||||
const originalDocument = await workspace.openTextDocument(originalUri);
|
||||
const selectedLines = toLineRanges(textEditor.selections, modifiedDocument);
|
||||
const selectedDiffs = diffs
|
||||
.map(diff => selectedLines.reduce<LineChange | null>((result, range) => result || intersectDiffWithRange(modifiedDocument, diff, range), null))
|
||||
.filter(d => !!d) as LineChange[];
|
||||
|
||||
if (!selectedDiffs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs);
|
||||
const result = applyLineChanges(originalDocument, modifiedDocument, changes);
|
||||
|
||||
await this.runByRepository(modifiedUri, async (repository, resource) => await repository.stage(resource, result));
|
||||
}
|
||||
|
||||
@command('git.revertChange')
|
||||
async revertChange(uri: Uri, changes: LineChange[], index: number): Promise<void> {
|
||||
const textEditor = window.visibleTextEditors.filter(e => e.document.uri.toString() === uri.toString())[0];
|
||||
|
||||
if (!textEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._revertChanges(textEditor, [...changes.slice(0, index), ...changes.slice(index + 1)]);
|
||||
}
|
||||
|
||||
@command('git.revertSelectedRanges', { diff: true })
|
||||
async revertSelectedRanges(diffs: LineChange[]): Promise<void> {
|
||||
async revertSelectedRanges(changes: LineChange[]): Promise<void> {
|
||||
const textEditor = window.activeTextEditor;
|
||||
|
||||
if (!textEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modifiedDocument = textEditor.document;
|
||||
const selections = textEditor.selections;
|
||||
const selectedChanges = changes.filter(change => {
|
||||
const modifiedRange = change.modifiedEndLineNumber === 0
|
||||
? new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(change.modifiedStartLineNumber).range.start)
|
||||
: new Range(modifiedDocument.lineAt(change.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(change.modifiedEndLineNumber - 1).range.end);
|
||||
|
||||
return selections.every(selection => !selection.intersection(modifiedRange));
|
||||
});
|
||||
|
||||
if (selectedChanges.length === changes.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._revertChanges(textEditor, selectedChanges);
|
||||
}
|
||||
|
||||
private async _revertChanges(textEditor: TextEditor, changes: LineChange[]): Promise<void> {
|
||||
const modifiedDocument = textEditor.document;
|
||||
const modifiedUri = modifiedDocument.uri;
|
||||
|
||||
@@ -548,19 +653,6 @@ export class CommandCenter {
|
||||
|
||||
const originalUri = toGitUri(modifiedUri, '~');
|
||||
const originalDocument = await workspace.openTextDocument(originalUri);
|
||||
const selections = textEditor.selections;
|
||||
const selectedDiffs = diffs.filter(diff => {
|
||||
const modifiedRange = diff.modifiedEndLineNumber === 0
|
||||
? new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.end, modifiedDocument.lineAt(diff.modifiedStartLineNumber).range.start)
|
||||
: new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end);
|
||||
|
||||
return selections.every(selection => !selection.intersection(modifiedRange));
|
||||
});
|
||||
|
||||
if (selectedDiffs.length === diffs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const basename = path.basename(modifiedUri.fsPath);
|
||||
const message = localize('confirm revert', "Are you sure you want to revert the selected changes in {0}?", basename);
|
||||
const yes = localize('revert', "Revert Changes");
|
||||
@@ -570,10 +662,11 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = applyLineChanges(originalDocument, modifiedDocument, selectedDiffs);
|
||||
const result = applyLineChanges(originalDocument, modifiedDocument, changes);
|
||||
const edit = new WorkspaceEdit();
|
||||
edit.replace(modifiedUri, new Range(new Position(0, 0), modifiedDocument.lineAt(modifiedDocument.lineCount - 1).range.end), result);
|
||||
workspace.applyEdit(edit);
|
||||
await modifiedDocument.save();
|
||||
}
|
||||
|
||||
@command('git.unstage')
|
||||
@@ -909,7 +1002,7 @@ export class CommandCenter {
|
||||
const includeTags = checkoutType === 'all' || checkoutType === 'tags';
|
||||
const includeRemotes = checkoutType === 'all' || checkoutType === 'remote';
|
||||
|
||||
const createBranch = new CreateBranchItem();
|
||||
const createBranch = new CreateBranchItem(this);
|
||||
|
||||
const heads = repository.refs.filter(ref => ref.type === RefType.Head)
|
||||
.map(ref => new CheckoutItem(ref));
|
||||
@@ -1174,6 +1267,19 @@ export class CommandCenter {
|
||||
await repository.sync();
|
||||
}
|
||||
|
||||
@command('git._syncAll')
|
||||
async syncAll(): Promise<void> {
|
||||
await Promise.all(this.model.repositories.map(async repository => {
|
||||
const HEAD = repository.HEAD;
|
||||
|
||||
if (!HEAD || !HEAD.upstream) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.sync();
|
||||
}));
|
||||
}
|
||||
|
||||
@command('git.publish', { repository: true })
|
||||
async publish(repository: Repository): Promise<void> {
|
||||
const remotes = repository.remotes;
|
||||
@@ -1184,9 +1290,12 @@ export class CommandCenter {
|
||||
}
|
||||
|
||||
const branchName = repository.HEAD && repository.HEAD.name || '';
|
||||
const picks = repository.remotes.map(r => r.name);
|
||||
const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName);
|
||||
const choice = await window.showQuickPick(picks, { placeHolder });
|
||||
const selectRemote = async () => {
|
||||
const picks = repository.remotes.map(r => r.name);
|
||||
const placeHolder = localize('pick remote', "Pick a remote to publish the branch '{0}' to:", branchName);
|
||||
return await window.showQuickPick(picks, { placeHolder });
|
||||
};
|
||||
const choice = remotes.length === 1 ? remotes[0].name : await selectRemote();
|
||||
|
||||
if (!choice) {
|
||||
return;
|
||||
@@ -1200,27 +1309,27 @@ export class CommandCenter {
|
||||
this.outputChannel.show();
|
||||
}
|
||||
|
||||
@command('git.ignore', { repository: true })
|
||||
async ignore(repository: Repository, ...resourceStates: SourceControlResourceState[]): Promise<void> {
|
||||
@command('git.ignore')
|
||||
async ignore(...resourceStates: SourceControlResourceState[]): Promise<void> {
|
||||
if (resourceStates.length === 0 || !(resourceStates[0].resourceUri instanceof Uri)) {
|
||||
const uri = window.activeTextEditor && window.activeTextEditor.document.uri;
|
||||
const resource = this.getSCMResource();
|
||||
|
||||
if (!uri) {
|
||||
if (!resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
return await repository.ignore([uri]);
|
||||
resourceStates = [resource];
|
||||
}
|
||||
|
||||
const uris = resourceStates
|
||||
const resources = resourceStates
|
||||
.filter(s => s instanceof Resource)
|
||||
.map(r => r.resourceUri);
|
||||
|
||||
if (!uris.length) {
|
||||
if (!resources.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.ignore(uris);
|
||||
await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources));
|
||||
}
|
||||
|
||||
@command('git.stash', { repository: true })
|
||||
@@ -1302,6 +1411,11 @@ export class CommandCenter {
|
||||
});
|
||||
}
|
||||
|
||||
/* __GDPR__
|
||||
"git.command" : {
|
||||
"command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('git.command', { command: id });
|
||||
|
||||
return result.catch(async err => {
|
||||
@@ -1389,7 +1503,7 @@ export class CommandCenter {
|
||||
return result;
|
||||
}
|
||||
|
||||
const tuple = result.filter(p => p[0] === repository)[0];
|
||||
const tuple = result.filter(p => p.repository === repository)[0];
|
||||
|
||||
if (tuple) {
|
||||
tuple.resources.push(resource);
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
'use strict';
|
||||
|
||||
import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode';
|
||||
import { debounce } from './decorators';
|
||||
import { fromGitUri } from './uri';
|
||||
import { Model, ModelChangeEvent } from './model';
|
||||
import { debounce, throttle } from './decorators';
|
||||
import { fromGitUri, toGitUri } from './uri';
|
||||
import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model';
|
||||
import { filterEvent, eventToPromise } from './util';
|
||||
|
||||
interface CacheRow {
|
||||
uri: Uri;
|
||||
@@ -24,8 +25,8 @@ const FIVE_MINUTES = 1000 * 60 * 5;
|
||||
|
||||
export class GitContentProvider {
|
||||
|
||||
private onDidChangeEmitter = new EventEmitter<Uri>();
|
||||
get onDidChange(): Event<Uri> { return this.onDidChangeEmitter.event; }
|
||||
private _onDidChange = new EventEmitter<Uri>();
|
||||
get onDidChange(): Event<Uri> { return this._onDidChange.event; }
|
||||
|
||||
private changedRepositoryRoots = new Set<string>();
|
||||
private cache: Cache = Object.create(null);
|
||||
@@ -34,6 +35,7 @@ export class GitContentProvider {
|
||||
constructor(private model: Model) {
|
||||
this.disposables.push(
|
||||
model.onDidChangeRepository(this.onDidChangeRepository, this),
|
||||
model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this),
|
||||
workspace.registerTextDocumentContentProvider('git', this)
|
||||
);
|
||||
|
||||
@@ -45,19 +47,33 @@ export class GitContentProvider {
|
||||
this.eventuallyFireChangeEvents();
|
||||
}
|
||||
|
||||
private onDidChangeOriginalResource({ uri }: OriginalResourceChangeEvent): void {
|
||||
if (uri.scheme !== 'file') {
|
||||
return;
|
||||
}
|
||||
|
||||
this._onDidChange.fire(toGitUri(uri, '', true));
|
||||
}
|
||||
|
||||
@debounce(1100)
|
||||
private eventuallyFireChangeEvents(): void {
|
||||
this.fireChangeEvents();
|
||||
}
|
||||
|
||||
private fireChangeEvents(): void {
|
||||
@throttle
|
||||
private async fireChangeEvents(): Promise<void> {
|
||||
if (!window.state.focused) {
|
||||
const onDidFocusWindow = filterEvent(window.onDidChangeWindowState, e => e.focused);
|
||||
await eventToPromise(onDidFocusWindow);
|
||||
}
|
||||
|
||||
Object.keys(this.cache).forEach(key => {
|
||||
const uri = this.cache[key].uri;
|
||||
const fsPath = uri.fsPath;
|
||||
|
||||
for (const root of this.changedRepositoryRoots) {
|
||||
if (fsPath.startsWith(root)) {
|
||||
this.onDidChangeEmitter.fire(uri);
|
||||
this._onDidChange.fire(uri);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +91,7 @@ export class GitContentProvider {
|
||||
|
||||
const cacheKey = uri.toString();
|
||||
const timestamp = new Date().getTime();
|
||||
const cacheValue = { uri, timestamp };
|
||||
const cacheValue: CacheRow = { uri, timestamp };
|
||||
|
||||
this.cache[cacheKey] = cacheValue;
|
||||
|
||||
@@ -101,7 +117,10 @@ export class GitContentProvider {
|
||||
|
||||
Object.keys(this.cache).forEach(key => {
|
||||
const row = this.cache[key];
|
||||
const isOpen = window.visibleTextEditors.some(e => e.document.uri.fsPath === row.uri.fsPath);
|
||||
const { path } = fromGitUri(row.uri);
|
||||
const isOpen = workspace.textDocuments
|
||||
.filter(d => d.uri.scheme === 'file')
|
||||
.some(d => d.uri.fsPath === path);
|
||||
|
||||
if (isOpen || now - row.timestamp < THREE_MINUTES) {
|
||||
cache[row.uri.toString()] = row;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { window, workspace, Uri, Disposable, Event, EventEmitter, DecorationData, DecorationProvider, ThemeColor } from 'vscode';
|
||||
import { Repository, GitResourceGroup } from './repository';
|
||||
import { Model } from './model';
|
||||
import { debounce } from './decorators';
|
||||
import { filterEvent } from './util';
|
||||
|
||||
class GitIgnoreDecorationProvider implements DecorationProvider {
|
||||
|
||||
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
|
||||
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
|
||||
private checkIgnoreQueue = new Map<string, { resolve: (status: boolean) => void, reject: (err: any) => void }>();
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(private repository: Repository) {
|
||||
this.disposables.push(
|
||||
window.registerDecorationProvider(this),
|
||||
filterEvent(workspace.onDidSaveTextDocument, e => e.fileName.endsWith('.gitignore'))(_ => this._onDidChangeDecorations.fire())
|
||||
//todo@joh -> events when the ignore status actually changes, not only when the file changes
|
||||
);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.forEach(d => d.dispose());
|
||||
this.checkIgnoreQueue.clear();
|
||||
}
|
||||
|
||||
provideDecoration(uri: Uri): Promise<DecorationData | undefined> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
this.checkIgnoreQueue.set(uri.fsPath, { resolve, reject });
|
||||
this.checkIgnoreSoon();
|
||||
}).then(ignored => {
|
||||
if (ignored) {
|
||||
return <DecorationData>{
|
||||
priority: 3,
|
||||
color: new ThemeColor('gitDecoration.ignoredResourceForeground')
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
private checkIgnoreSoon(): void {
|
||||
const queue = new Map(this.checkIgnoreQueue.entries());
|
||||
this.checkIgnoreQueue.clear();
|
||||
this.repository.checkIgnore([...queue.keys()]).then(ignoreSet => {
|
||||
for (const [key, value] of queue.entries()) {
|
||||
value.resolve(ignoreSet.has(key));
|
||||
}
|
||||
}, err => {
|
||||
console.error(err);
|
||||
for (const [, value] of queue.entries()) {
|
||||
value.reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class GitDecorationProvider implements DecorationProvider {
|
||||
|
||||
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
|
||||
readonly onDidChangeDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
private decorations = new Map<string, DecorationData>();
|
||||
|
||||
constructor(private repository: Repository) {
|
||||
this.disposables.push(
|
||||
window.registerDecorationProvider(this),
|
||||
repository.onDidRunOperation(this.onDidRunOperation, this)
|
||||
);
|
||||
}
|
||||
|
||||
private onDidRunOperation(): void {
|
||||
let newDecorations = new Map<string, DecorationData>();
|
||||
this.collectDecorationData(this.repository.indexGroup, newDecorations);
|
||||
this.collectDecorationData(this.repository.workingTreeGroup, newDecorations);
|
||||
this.collectDecorationData(this.repository.mergeGroup, newDecorations);
|
||||
|
||||
let uris: Uri[] = [];
|
||||
newDecorations.forEach((value, uriString) => {
|
||||
if (this.decorations.has(uriString)) {
|
||||
this.decorations.delete(uriString);
|
||||
} else {
|
||||
uris.push(Uri.parse(uriString));
|
||||
}
|
||||
});
|
||||
this.decorations.forEach((value, uriString) => {
|
||||
uris.push(Uri.parse(uriString));
|
||||
});
|
||||
this.decorations = newDecorations;
|
||||
this._onDidChangeDecorations.fire(uris);
|
||||
}
|
||||
|
||||
private collectDecorationData(group: GitResourceGroup, bucket: Map<string, DecorationData>): void {
|
||||
group.resourceStates.forEach(r => {
|
||||
if (r.resourceDecoration) {
|
||||
bucket.set(r.original.toString(), r.resourceDecoration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
provideDecoration(uri: Uri): DecorationData | undefined {
|
||||
return this.decorations.get(uri.toString());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class GitDecorations {
|
||||
|
||||
private configListener: Disposable;
|
||||
private modelListener: Disposable[] = [];
|
||||
private providers = new Map<Repository, Disposable>();
|
||||
|
||||
constructor(private model: Model) {
|
||||
this.configListener = workspace.onDidChangeConfiguration(e => e.affectsConfiguration('git.decorations.enabled') && this.update());
|
||||
this.update();
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
const enabled = workspace.getConfiguration('git').get('decorations.enabled');
|
||||
if (enabled) {
|
||||
this.enable();
|
||||
} else {
|
||||
this.disable();
|
||||
}
|
||||
}
|
||||
|
||||
private enable(): void {
|
||||
this.modelListener = [];
|
||||
this.model.onDidOpenRepository(this.onDidOpenRepository, this, this.modelListener);
|
||||
this.model.onDidCloseRepository(this.onDidCloseRepository, this, this.modelListener);
|
||||
this.model.repositories.forEach(this.onDidOpenRepository, this);
|
||||
}
|
||||
|
||||
private disable(): void {
|
||||
this.modelListener.forEach(d => d.dispose());
|
||||
this.providers.forEach(value => value.dispose());
|
||||
this.providers.clear();
|
||||
}
|
||||
|
||||
private onDidOpenRepository(repository: Repository): void {
|
||||
const provider = new GitDecorationProvider(repository);
|
||||
const ignoreProvider = new GitIgnoreDecorationProvider(repository);
|
||||
this.providers.set(repository, Disposable.from(provider, ignoreProvider));
|
||||
}
|
||||
|
||||
private onDidCloseRepository(repository: Repository): void {
|
||||
const provider = this.providers.get(repository);
|
||||
if (provider) {
|
||||
provider.dispose();
|
||||
this.providers.delete(repository);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.configListener.dispose();
|
||||
this.modelListener.forEach(d => d.dispose());
|
||||
this.providers.forEach(value => value.dispose);
|
||||
this.providers.clear();
|
||||
}
|
||||
}
|
||||
+47
-41
@@ -13,7 +13,6 @@ import { EventEmitter } from 'events';
|
||||
import iconv = require('iconv-lite');
|
||||
import { assign, uniqBy, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp } from './util';
|
||||
|
||||
const readdir = denodeify<string[]>(fs.readdir);
|
||||
const readfile = denodeify<string>(fs.readFile);
|
||||
|
||||
export interface IGit {
|
||||
@@ -66,7 +65,7 @@ function findSpecificGit(path: string): Promise<IGit> {
|
||||
const buffers: Buffer[] = [];
|
||||
const child = cp.spawn(path, ['--version']);
|
||||
child.stdout.on('data', (b: Buffer) => buffers.push(b));
|
||||
child.on('error', e);
|
||||
child.on('error', cpErrorHandler(e));
|
||||
child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) }));
|
||||
});
|
||||
}
|
||||
@@ -82,12 +81,12 @@ function findGitDarwin(): Promise<IGit> {
|
||||
|
||||
function getVersion(path: string) {
|
||||
// make sure git executes
|
||||
cp.exec('git --version', (err, stdout: Buffer) => {
|
||||
cp.exec('git --version', (err, stdout) => {
|
||||
if (err) {
|
||||
return e('git not found');
|
||||
}
|
||||
|
||||
return c({ path, version: parseVersion(stdout.toString('utf8').trim()) });
|
||||
return c({ path, version: parseVersion(stdout.trim()) });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -118,48 +117,54 @@ function findSystemGitWin32(base: string): Promise<IGit> {
|
||||
return findSpecificGit(path.join(base, 'Git', 'cmd', 'git.exe'));
|
||||
}
|
||||
|
||||
function findGitHubGitWin32(): Promise<IGit> {
|
||||
const github = path.join(process.env['LOCALAPPDATA'], 'GitHub');
|
||||
|
||||
return readdir(github).then(children => {
|
||||
const git = children.filter(child => /^PortableGit/.test(child))[0];
|
||||
|
||||
if (!git) {
|
||||
return Promise.reject<IGit>('Not found');
|
||||
}
|
||||
|
||||
return findSpecificGit(path.join(github, git, 'cmd', 'git.exe'));
|
||||
});
|
||||
}
|
||||
|
||||
function findGitWin32(): Promise<IGit> {
|
||||
return findSystemGitWin32(process.env['ProgramW6432'])
|
||||
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles(x86)']))
|
||||
.then(void 0, () => findSystemGitWin32(process.env['ProgramFiles']))
|
||||
.then(void 0, () => findSpecificGit('git'))
|
||||
.then(void 0, () => findGitHubGitWin32());
|
||||
.then(void 0, () => findSpecificGit('git'));
|
||||
}
|
||||
|
||||
export function findGit(hint: string | undefined): Promise<IGit> {
|
||||
var first = hint ? findSpecificGit(hint) : Promise.reject<IGit>(null);
|
||||
|
||||
return first.then(void 0, () => {
|
||||
switch (process.platform) {
|
||||
case 'darwin': return findGitDarwin();
|
||||
case 'win32': return findGitWin32();
|
||||
default: return findSpecificGit('git');
|
||||
}
|
||||
});
|
||||
return first
|
||||
.then(void 0, () => {
|
||||
switch (process.platform) {
|
||||
case 'darwin': return findGitDarwin();
|
||||
case 'win32': return findGitWin32();
|
||||
default: return findSpecificGit('git');
|
||||
}
|
||||
})
|
||||
.then(null, () => Promise.reject(new Error('Git installation not found.')));
|
||||
}
|
||||
|
||||
|
||||
export interface IExecutionResult {
|
||||
exitCode: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
async function exec(child: cp.ChildProcess, options: any = {}): Promise<IExecutionResult> {
|
||||
function cpErrorHandler(cb: (reason?: any) => void): (reason?: any) => void {
|
||||
return err => {
|
||||
if (/ENOENT/.test(err.message)) {
|
||||
err = new GitError({
|
||||
error: err,
|
||||
message: 'Failed to execute git (ENOENT)',
|
||||
gitErrorCode: GitErrorCodes.NotAGitRepository
|
||||
});
|
||||
}
|
||||
|
||||
cb(err);
|
||||
};
|
||||
}
|
||||
|
||||
export interface SpawnOptions extends cp.SpawnOptions {
|
||||
input?: string;
|
||||
encoding?: string;
|
||||
log?: boolean;
|
||||
}
|
||||
|
||||
async function exec(child: cp.ChildProcess, options: SpawnOptions = {}): Promise<IExecutionResult> {
|
||||
if (!child.stdout || !child.stderr) {
|
||||
throw new GitError({
|
||||
message: 'Failed to get stdout or stderr from git process.'
|
||||
@@ -183,7 +188,7 @@ async function exec(child: cp.ChildProcess, options: any = {}): Promise<IExecuti
|
||||
|
||||
const [exitCode, stdout, stderr] = await Promise.all<any>([
|
||||
new Promise<number>((c, e) => {
|
||||
once(child, 'error', e);
|
||||
once(child, 'error', cpErrorHandler(e));
|
||||
once(child, 'exit', c);
|
||||
}),
|
||||
new Promise<string>(c => {
|
||||
@@ -246,7 +251,7 @@ export class GitError {
|
||||
gitCommand: this.gitCommand,
|
||||
stdout: this.stdout,
|
||||
stderr: this.stderr
|
||||
}, [], 2);
|
||||
}, null, 2);
|
||||
|
||||
if (this.error) {
|
||||
result += (<any>this.error).stack;
|
||||
@@ -350,17 +355,17 @@ export class Git {
|
||||
return path.normalize(result.stdout.trim());
|
||||
}
|
||||
|
||||
async exec(cwd: string, args: string[], options: any = {}): Promise<IExecutionResult> {
|
||||
async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> {
|
||||
options = assign({ cwd }, options || {});
|
||||
return await this._exec(args, options);
|
||||
}
|
||||
|
||||
stream(cwd: string, args: string[], options: any = {}): cp.ChildProcess {
|
||||
stream(cwd: string, args: string[], options: SpawnOptions = {}): cp.ChildProcess {
|
||||
options = assign({ cwd }, options || {});
|
||||
return this.spawn(args, options);
|
||||
}
|
||||
|
||||
private async _exec(args: string[], options: any = {}): Promise<IExecutionResult> {
|
||||
private async _exec(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> {
|
||||
const child = this.spawn(args, options);
|
||||
|
||||
if (options.input) {
|
||||
@@ -387,7 +392,7 @@ export class Git {
|
||||
return result;
|
||||
}
|
||||
|
||||
spawn(args: string[], options: any = {}): cp.ChildProcess {
|
||||
spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
|
||||
if (!this.gitPath) {
|
||||
throw new Error('git could not be found in the system.');
|
||||
}
|
||||
@@ -505,19 +510,19 @@ export class Repository {
|
||||
}
|
||||
|
||||
// TODO@Joao: rename to exec
|
||||
async run(args: string[], options: any = {}): Promise<IExecutionResult> {
|
||||
async run(args: string[], options: SpawnOptions = {}): Promise<IExecutionResult> {
|
||||
return await this.git.exec(this.repositoryRoot, args, options);
|
||||
}
|
||||
|
||||
stream(args: string[], options: any = {}): cp.ChildProcess {
|
||||
stream(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
|
||||
return this.git.stream(this.repositoryRoot, args, options);
|
||||
}
|
||||
|
||||
spawn(args: string[], options: any = {}): cp.ChildProcess {
|
||||
spawn(args: string[], options: SpawnOptions = {}): cp.ChildProcess {
|
||||
return this.git.spawn(args, options);
|
||||
}
|
||||
|
||||
async config(scope: string, key: string, value: any, options: any): Promise<string> {
|
||||
async config(scope: string, key: string, value: any, options: SpawnOptions): Promise<string> {
|
||||
const args = ['config'];
|
||||
|
||||
if (scope) {
|
||||
@@ -883,7 +888,8 @@ export class Repository {
|
||||
getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> {
|
||||
return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => {
|
||||
const parser = new GitStatusParser();
|
||||
const child = this.stream(['status', '-z', '-u']);
|
||||
const env = { GIT_OPTIONAL_LOCKS: '0' };
|
||||
const child = this.stream(['status', '-z', '-u'], { env });
|
||||
|
||||
const onExit = exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
@@ -919,7 +925,7 @@ export class Repository {
|
||||
child.stderr.setEncoding('utf8');
|
||||
child.stderr.on('data', raw => stderrData.push(raw as string));
|
||||
|
||||
child.on('error', e);
|
||||
child.on('error', cpErrorHandler(e));
|
||||
child.on('exit', onExit);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { findGit, Git, IGit } from './git';
|
||||
import { Model } from './model';
|
||||
import { CommandCenter } from './commands';
|
||||
import { GitContentProvider } from './contentProvider';
|
||||
import { GitDecorations } from './decorationProvider';
|
||||
import { Askpass } from './askpass';
|
||||
import { toDisposable } from './util';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
@@ -54,6 +55,7 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
|
||||
disposables.push(
|
||||
new CommandCenter(git, model, outputChannel, telemetryReporter),
|
||||
new GitContentProvider(model),
|
||||
new GitDecorations(model)
|
||||
);
|
||||
|
||||
await checkGitVersion(info);
|
||||
@@ -70,7 +72,7 @@ export function activate(context: ExtensionContext): any {
|
||||
async function checkGitVersion(info: IGit): Promise<void> {
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// remove Git version check on since for Carbon
|
||||
// remove Git version check for sqlops
|
||||
|
||||
return;
|
||||
|
||||
@@ -101,4 +103,4 @@ async function checkGitVersion(info: IGit): Promise<void> {
|
||||
await config.update('ignoreLegacyWarning', true, true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,16 @@ import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
class RepositoryPick implements QuickPickItem {
|
||||
@memoize get label(): string { return path.basename(this.repository.root); }
|
||||
@memoize get description(): string { return path.dirname(this.repository.root); }
|
||||
@memoize get label(): string {
|
||||
return path.basename(this.repository.root);
|
||||
}
|
||||
|
||||
@memoize get description(): string {
|
||||
return [this.repository.headLabel, this.repository.syncLabel]
|
||||
.filter(l => !!l)
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
constructor(public readonly repository: Repository) { }
|
||||
}
|
||||
|
||||
@@ -27,10 +35,19 @@ export interface ModelChangeEvent {
|
||||
uri: Uri;
|
||||
}
|
||||
|
||||
export interface OriginalResourceChangeEvent {
|
||||
repository: Repository;
|
||||
uri: Uri;
|
||||
}
|
||||
|
||||
interface OpenRepository extends Disposable {
|
||||
repository: Repository;
|
||||
}
|
||||
|
||||
function isParent(parent: string, child: string): boolean {
|
||||
return child.startsWith(parent);
|
||||
}
|
||||
|
||||
export class Model {
|
||||
|
||||
private _onDidOpenRepository = new EventEmitter<Repository>();
|
||||
@@ -42,6 +59,9 @@ export class Model {
|
||||
private _onDidChangeRepository = new EventEmitter<ModelChangeEvent>();
|
||||
readonly onDidChangeRepository: Event<ModelChangeEvent> = this._onDidChangeRepository.event;
|
||||
|
||||
private _onDidChangeOriginalResource = new EventEmitter<OriginalResourceChangeEvent>();
|
||||
readonly onDidChangeOriginalResource: Event<OriginalResourceChangeEvent> = this._onDidChangeOriginalResource.event;
|
||||
|
||||
private openRepositories: OpenRepository[] = [];
|
||||
get repositories(): Repository[] { return this.openRepositories.map(r => r.repository); }
|
||||
|
||||
@@ -147,7 +167,9 @@ export class Model {
|
||||
const activeRepositories = new Set<Repository>(activeRepositoriesList);
|
||||
const openRepositoriesToDispose = removed
|
||||
.map(folder => this.getOpenRepository(folder.uri))
|
||||
.filter(r => !!r && !activeRepositories.has(r.repository)) as OpenRepository[];
|
||||
.filter(r => !!r)
|
||||
.filter(r => !activeRepositories.has(r!.repository))
|
||||
.filter(r => !(workspace.workspaceFolders || []).some(f => isParent(f.uri.fsPath, r!.repository.root))) as OpenRepository[];
|
||||
|
||||
possibleRepositoryFolders.forEach(p => this.tryOpenRepository(p.uri.fsPath));
|
||||
openRepositoriesToDispose.forEach(r => r.dispose());
|
||||
@@ -203,10 +225,14 @@ export class Model {
|
||||
const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === RepositoryState.Disposed);
|
||||
const disappearListener = onDidDisappearRepository(() => dispose());
|
||||
const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri }));
|
||||
const originalResourceChangeListener = repository.onDidChangeOriginalResource(uri => this._onDidChangeOriginalResource.fire({ repository, uri }));
|
||||
|
||||
const dispose = () => {
|
||||
disappearListener.dispose();
|
||||
changeListener.dispose();
|
||||
originalResourceChangeListener.dispose();
|
||||
repository.dispose();
|
||||
|
||||
this.openRepositories = this.openRepositories.filter(e => e !== openRepository);
|
||||
this._onDidCloseRepository.fire(repository);
|
||||
};
|
||||
@@ -216,6 +242,16 @@ export class Model {
|
||||
this._onDidOpenRepository.fire(repository);
|
||||
}
|
||||
|
||||
close(repository: Repository): void {
|
||||
const openRepository = this.getOpenRepository(repository);
|
||||
|
||||
if (!openRepository) {
|
||||
return;
|
||||
}
|
||||
|
||||
openRepository.dispose();
|
||||
}
|
||||
|
||||
async pickRepository(): Promise<Repository | undefined> {
|
||||
if (this.openRepositories.length === 0) {
|
||||
throw new Error(localize('no repositories', "There are no available repositories"));
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit } from 'vscode';
|
||||
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash } from './git';
|
||||
import { Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData } from 'vscode';
|
||||
import { Repository as BaseRepository, Ref, Branch, Remote, Commit, GitErrorCodes, Stash, RefType, GitError } from './git';
|
||||
import { anyEvent, filterEvent, eventToPromise, dispose, find } from './util';
|
||||
import { memoize, throttle, debounce } from './decorators';
|
||||
import { toGitUri } from './uri';
|
||||
@@ -171,13 +171,104 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
|
||||
get decorations(): SourceControlResourceDecorations {
|
||||
const light = { iconPath: this.getIconPath('light') };
|
||||
const dark = { iconPath: this.getIconPath('dark') };
|
||||
// TODO@joh, still requires restart/redraw in the SCM viewlet
|
||||
const decorations = workspace.getConfiguration().get<boolean>('git.decorations.enabled');
|
||||
const light = !decorations ? { iconPath: this.getIconPath('light') } : undefined;
|
||||
const dark = !decorations ? { iconPath: this.getIconPath('dark') } : undefined;
|
||||
const tooltip = this.tooltip;
|
||||
const strikeThrough = this.strikeThrough;
|
||||
const faded = this.faded;
|
||||
const letter = this.letter;
|
||||
const color = this.color;
|
||||
|
||||
return { strikeThrough, faded, tooltip, light, dark };
|
||||
return { strikeThrough, faded, tooltip, light, dark, letter, color, source: 'git.resource' /*todo@joh*/ };
|
||||
}
|
||||
|
||||
get letter(): string | undefined {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
return 'M';
|
||||
case Status.INDEX_ADDED:
|
||||
return 'A';
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return 'D';
|
||||
case Status.INDEX_RENAMED:
|
||||
return 'R';
|
||||
case Status.UNTRACKED:
|
||||
return 'U';
|
||||
case Status.IGNORED:
|
||||
return 'I';
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
case Status.ADDED_BY_THEM:
|
||||
case Status.DELETED_BY_US:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return 'C';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get color(): ThemeColor | undefined {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
return new ThemeColor('gitDecoration.modifiedResourceForeground');
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return new ThemeColor('gitDecoration.deletedResourceForeground');
|
||||
case Status.INDEX_ADDED: // todo@joh - special color?
|
||||
case Status.INDEX_RENAMED: // todo@joh - special color?
|
||||
case Status.UNTRACKED:
|
||||
return new ThemeColor('gitDecoration.untrackedResourceForeground');
|
||||
case Status.IGNORED:
|
||||
return new ThemeColor('gitDecoration.ignoredResourceForeground');
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
case Status.ADDED_BY_THEM:
|
||||
case Status.DELETED_BY_US:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return new ThemeColor('gitDecoration.conflictingResourceForeground');
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get priority(): number {
|
||||
switch (this.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.MODIFIED:
|
||||
return 2;
|
||||
case Status.IGNORED:
|
||||
return 3;
|
||||
case Status.INDEX_COPIED:
|
||||
case Status.BOTH_DELETED:
|
||||
case Status.ADDED_BY_US:
|
||||
case Status.DELETED_BY_THEM:
|
||||
case Status.ADDED_BY_THEM:
|
||||
case Status.DELETED_BY_US:
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return 4;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
get resourceDecoration(): DecorationData | undefined {
|
||||
const title = this.tooltip;
|
||||
const abbreviation = this.letter;
|
||||
const color = this.color;
|
||||
const priority = this.priority;
|
||||
return { bubble: true, source: 'git.resource', title, abbreviation, color, priority };
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -189,54 +280,34 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
|
||||
export enum Operation {
|
||||
Status = 1 << 0,
|
||||
Add = 1 << 1,
|
||||
RevertFiles = 1 << 2,
|
||||
Commit = 1 << 3,
|
||||
Clean = 1 << 4,
|
||||
Branch = 1 << 5,
|
||||
Checkout = 1 << 6,
|
||||
Reset = 1 << 7,
|
||||
Fetch = 1 << 8,
|
||||
Pull = 1 << 9,
|
||||
Push = 1 << 10,
|
||||
Sync = 1 << 11,
|
||||
Show = 1 << 12,
|
||||
Stage = 1 << 13,
|
||||
GetCommitTemplate = 1 << 14,
|
||||
DeleteBranch = 1 << 15,
|
||||
Merge = 1 << 16,
|
||||
Ignore = 1 << 17,
|
||||
Tag = 1 << 18,
|
||||
Stash = 1 << 19
|
||||
Status = 'Status',
|
||||
Add = 'Add',
|
||||
RevertFiles = 'RevertFiles',
|
||||
Commit = 'Commit',
|
||||
Clean = 'Clean',
|
||||
Branch = 'Branch',
|
||||
Checkout = 'Checkout',
|
||||
Reset = 'Reset',
|
||||
Fetch = 'Fetch',
|
||||
Pull = 'Pull',
|
||||
Push = 'Push',
|
||||
Sync = 'Sync',
|
||||
Show = 'Show',
|
||||
Stage = 'Stage',
|
||||
GetCommitTemplate = 'GetCommitTemplate',
|
||||
DeleteBranch = 'DeleteBranch',
|
||||
Merge = 'Merge',
|
||||
Ignore = 'Ignore',
|
||||
Tag = 'Tag',
|
||||
Stash = 'Stash',
|
||||
CheckIgnore = 'CheckIgnore'
|
||||
}
|
||||
|
||||
// function getOperationName(operation: Operation): string {
|
||||
// switch (operation) {
|
||||
// case Operation.Status: return 'Status';
|
||||
// case Operation.Add: return 'Add';
|
||||
// case Operation.RevertFiles: return 'RevertFiles';
|
||||
// case Operation.Commit: return 'Commit';
|
||||
// case Operation.Clean: return 'Clean';
|
||||
// case Operation.Branch: return 'Branch';
|
||||
// case Operation.Checkout: return 'Checkout';
|
||||
// case Operation.Reset: return 'Reset';
|
||||
// case Operation.Fetch: return 'Fetch';
|
||||
// case Operation.Pull: return 'Pull';
|
||||
// case Operation.Push: return 'Push';
|
||||
// case Operation.Sync: return 'Sync';
|
||||
// case Operation.Init: return 'Init';
|
||||
// case Operation.Show: return 'Show';
|
||||
// case Operation.Stage: return 'Stage';
|
||||
// case Operation.GetCommitTemplate: return 'GetCommitTemplate';
|
||||
// default: return 'unknown';
|
||||
// }
|
||||
// }
|
||||
|
||||
function isReadOnly(operation: Operation): boolean {
|
||||
switch (operation) {
|
||||
case Operation.Show:
|
||||
case Operation.GetCommitTemplate:
|
||||
case Operation.CheckIgnore:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -246,6 +317,7 @@ function isReadOnly(operation: Operation): boolean {
|
||||
function shouldShowProgress(operation: Operation): boolean {
|
||||
switch (operation) {
|
||||
case Operation.Fetch:
|
||||
case Operation.CheckIgnore:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
@@ -259,24 +331,36 @@ export interface Operations {
|
||||
|
||||
class OperationsImpl implements Operations {
|
||||
|
||||
constructor(private readonly operations: number = 0) {
|
||||
// noop
|
||||
private operations = new Map<Operation, number>();
|
||||
|
||||
start(operation: Operation): void {
|
||||
this.operations.set(operation, (this.operations.get(operation) || 0) + 1);
|
||||
}
|
||||
|
||||
start(operation: Operation): OperationsImpl {
|
||||
return new OperationsImpl(this.operations | operation);
|
||||
}
|
||||
end(operation: Operation): void {
|
||||
const count = (this.operations.get(operation) || 0) - 1;
|
||||
|
||||
end(operation: Operation): OperationsImpl {
|
||||
return new OperationsImpl(this.operations & ~operation);
|
||||
if (count <= 0) {
|
||||
this.operations.delete(operation);
|
||||
} else {
|
||||
this.operations.set(operation, count);
|
||||
}
|
||||
}
|
||||
|
||||
isRunning(operation: Operation): boolean {
|
||||
return (this.operations & operation) !== 0;
|
||||
return this.operations.has(operation);
|
||||
}
|
||||
|
||||
isIdle(): boolean {
|
||||
return this.operations === 0;
|
||||
const operations = this.operations.keys();
|
||||
|
||||
for (const operation of operations) {
|
||||
if (!isReadOnly(operation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +386,9 @@ export class Repository implements Disposable {
|
||||
private _onDidChangeStatus = new EventEmitter<void>();
|
||||
readonly onDidChangeStatus: Event<void> = this._onDidChangeStatus.event;
|
||||
|
||||
private _onDidChangeOriginalResource = new EventEmitter<Uri>();
|
||||
readonly onDidChangeOriginalResource: Event<Uri> = this._onDidChangeOriginalResource.event;
|
||||
|
||||
private _onRunOperation = new EventEmitter<Operation>();
|
||||
readonly onRunOperation: Event<Operation> = this._onRunOperation.event;
|
||||
|
||||
@@ -382,9 +469,7 @@ export class Repository implements Disposable {
|
||||
const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path));
|
||||
onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables);
|
||||
|
||||
const label = `${path.basename(repository.root)} (Git)`;
|
||||
|
||||
this._sourceControl = scm.createSourceControl('git', label);
|
||||
this._sourceControl = scm.createSourceControl('git', 'Git', Uri.file(repository.root));
|
||||
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit"), arguments: [this._sourceControl] };
|
||||
this._sourceControl.quickDiffProvider = this;
|
||||
this.disposables.push(this._sourceControl);
|
||||
@@ -449,6 +534,7 @@ export class Repository implements Disposable {
|
||||
async stage(resource: Uri, contents: string): Promise<void> {
|
||||
const relativePath = path.relative(this.repository.root, resource.fsPath).replace(/\\/g, '/');
|
||||
await this.run(Operation.Stage, () => this.repository.stage(relativePath, contents));
|
||||
this._onDidChangeOriginalResource.fire(resource);
|
||||
}
|
||||
|
||||
async revert(resources: Uri[]): Promise<void> {
|
||||
@@ -534,11 +620,7 @@ export class Repository implements Disposable {
|
||||
|
||||
@throttle
|
||||
async fetch(): Promise<void> {
|
||||
try {
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch());
|
||||
} catch (err) {
|
||||
// noop
|
||||
}
|
||||
await this.run(Operation.Fetch, () => this.repository.fetch());
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -584,7 +666,7 @@ export class Repository implements Disposable {
|
||||
async show(ref: string, filePath: string): Promise<string> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
const encoding = configFiles.get<string>('encoding');
|
||||
|
||||
return await this.repository.buffer(`${ref}:${relativePath}`, encoding);
|
||||
@@ -629,13 +711,58 @@ export class Repository implements Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
checkIgnore(filePaths: string[]): Promise<Set<string>> {
|
||||
return this.run(Operation.CheckIgnore, () => {
|
||||
return new Promise<Set<string>>((resolve, reject) => {
|
||||
|
||||
filePaths = filePaths.filter(filePath => !path.relative(this.root, filePath).startsWith('..'));
|
||||
|
||||
if (filePaths.length === 0) {
|
||||
// nothing left
|
||||
return resolve(new Set<string>());
|
||||
}
|
||||
|
||||
// https://git-scm.com/docs/git-check-ignore#git-check-ignore--z
|
||||
const child = this.repository.stream(['check-ignore', '-z', '--stdin'], { stdio: [null, null, null] });
|
||||
child.stdin.end(filePaths.join('\0'), 'utf8');
|
||||
|
||||
const onExit = exitCode => {
|
||||
if (exitCode === 1) {
|
||||
// nothing ignored
|
||||
resolve(new Set<string>());
|
||||
} else if (exitCode === 0) {
|
||||
// paths are separated by the null-character
|
||||
resolve(new Set<string>(data.split('\0')));
|
||||
} else {
|
||||
reject(new GitError({ stdout: data, stderr, exitCode }));
|
||||
}
|
||||
};
|
||||
|
||||
let data = '';
|
||||
const onStdoutData = (raw: string) => {
|
||||
data += raw;
|
||||
};
|
||||
|
||||
child.stdout.setEncoding('utf8');
|
||||
child.stdout.on('data', onStdoutData);
|
||||
|
||||
let stderr: string = '';
|
||||
child.stderr.setEncoding('utf8');
|
||||
child.stderr.on('data', raw => stderr += raw);
|
||||
|
||||
child.on('error', reject);
|
||||
child.on('exit', onExit);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async run<T>(operation: Operation, runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
|
||||
if (this.state !== RepositoryState.Idle) {
|
||||
throw new Error('Repository not initialized');
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
this._operations = this._operations.start(operation);
|
||||
this._operations.start(operation);
|
||||
this._onRunOperation.fire(operation);
|
||||
|
||||
try {
|
||||
@@ -653,7 +780,7 @@ export class Repository implements Disposable {
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
this._operations = this._operations.end(operation);
|
||||
this._operations.end(operation);
|
||||
this._onDidRunOperation.fire(operation);
|
||||
}
|
||||
};
|
||||
@@ -818,7 +945,7 @@ export class Repository implements Disposable {
|
||||
await timeout(5000);
|
||||
}
|
||||
|
||||
private async whenIdleAndFocused(): Promise<void> {
|
||||
async whenIdleAndFocused(): Promise<void> {
|
||||
while (true) {
|
||||
if (!this.operations.isIdle()) {
|
||||
await eventToPromise(this.onDidRunOperation);
|
||||
@@ -835,6 +962,36 @@ export class Repository implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
get headLabel(): string {
|
||||
const HEAD = this.HEAD;
|
||||
|
||||
if (!HEAD) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0];
|
||||
const tagName = tag && tag.name;
|
||||
const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8);
|
||||
|
||||
return head
|
||||
+ (this.workingTreeGroup.resourceStates.length > 0 ? '*' : '')
|
||||
+ (this.indexGroup.resourceStates.length > 0 ? '+' : '')
|
||||
+ (this.mergeGroup.resourceStates.length > 0 ? '!' : '');
|
||||
}
|
||||
|
||||
get syncLabel(): string {
|
||||
if (!this.HEAD
|
||||
|| !this.HEAD.name
|
||||
|| !this.HEAD.commit
|
||||
|| !this.HEAD.upstream
|
||||
|| !(this.HEAD.ahead || this.HEAD.behind)
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `${this.HEAD.behind}↓ ${this.HEAD.ahead}↑`;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
import { Disposable, Command, EventEmitter, Event } from 'vscode';
|
||||
import { RefType, Branch } from './git';
|
||||
import { Branch } from './git';
|
||||
import { Repository, Operation } from './repository';
|
||||
import { anyEvent, dispose } from './util';
|
||||
import * as nls from 'vscode-nls';
|
||||
@@ -24,20 +24,7 @@ class CheckoutStatusBar {
|
||||
}
|
||||
|
||||
get command(): Command | undefined {
|
||||
const HEAD = this.repository.HEAD;
|
||||
|
||||
if (!HEAD) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const tag = this.repository.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0];
|
||||
const tagName = tag && tag.name;
|
||||
const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8);
|
||||
const title = '$(git-branch) '
|
||||
+ head
|
||||
+ (this.repository.workingTreeGroup.resourceStates.length > 0 ? '*' : '')
|
||||
+ (this.repository.indexGroup.resourceStates.length > 0 ? '+' : '')
|
||||
+ (this.repository.mergeGroup.resourceStates.length > 0 ? '!' : '');
|
||||
const title = `$(git-branch) ${this.repository.headLabel}`;
|
||||
|
||||
return {
|
||||
command: 'git.checkout',
|
||||
@@ -112,7 +99,7 @@ class SyncStatusBar {
|
||||
if (HEAD && HEAD.name && HEAD.commit) {
|
||||
if (HEAD.upstream) {
|
||||
if (HEAD.ahead || HEAD.behind) {
|
||||
text += `${HEAD.behind}↓ ${HEAD.ahead}↑`;
|
||||
text += this.repository.syncLabel;
|
||||
}
|
||||
command = 'git.sync';
|
||||
tooltip = localize('sync changes', "Synchronize Changes");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { Event } from 'vscode';
|
||||
import { dirname } from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as byline from 'byline';
|
||||
|
||||
export function log(...args: any[]): void {
|
||||
console.log.apply(console, ['git:', ...args]);
|
||||
@@ -188,4 +189,20 @@ export function find<T>(array: T[], fn: (t: T) => boolean): T | undefined {
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function grep(filename: string, pattern: RegExp): Promise<boolean> {
|
||||
return new Promise<boolean>((c, e) => {
|
||||
const fileStream = fs.createReadStream(filename, { encoding: 'utf8' });
|
||||
const stream = byline(fileStream);
|
||||
stream.on('data', (line: string) => {
|
||||
if (pattern.test(line)) {
|
||||
fileStream.close();
|
||||
c(true);
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('error', e);
|
||||
stream.on('end', () => c(false));
|
||||
});
|
||||
}
|
||||
@@ -50,6 +50,11 @@
|
||||
"scopeName": "text.git-rebase",
|
||||
"path": "./syntaxes/git-rebase.tmLanguage.json"
|
||||
}
|
||||
]
|
||||
],
|
||||
"configurationDefaults": {
|
||||
"[git-commit]": {
|
||||
"editor.rulers": [72]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,7 @@
|
||||
{
|
||||
"id": "backup-history-server-insight",
|
||||
"contrib": {
|
||||
"cacheId": "backup-history-server-insight",
|
||||
"name": "Backup Status",
|
||||
"provider": "MSSQL",
|
||||
"edition": [0,1,2,3,4],
|
||||
|
||||
@@ -6,20 +6,20 @@ SUM(ALOC.data_pages) AS data_pages,
|
||||
(SUM(ALOC.total_pages)*8/1024) AS total_space_MB,
|
||||
(SUM(ALOC.used_pages)*8/1024) AS used_space_MB,
|
||||
(SUM(ALOC.data_pages)*8/1024) AS data_space_MB
|
||||
FROM sys.Tables AS TABL
|
||||
INNER JOIN sys.Indexes AS INDX
|
||||
FROM sys.tables AS TABL
|
||||
INNER JOIN sys.indexes AS INDX
|
||||
ON TABL.object_id = INDX.object_id
|
||||
INNER JOIN sys.Partitions AS PART
|
||||
INNER JOIN sys.partitions AS PART
|
||||
ON INDX.object_id = PART.object_id
|
||||
AND INDX.index_id = PART.index_id
|
||||
INNER JOIN sys.Allocation_Units AS ALOC
|
||||
INNER JOIN sys.allocation_units AS ALOC
|
||||
ON PART.partition_id = ALOC.container_id
|
||||
WHERE
|
||||
INDX.object_id > 255
|
||||
AND INDX.index_id <= 1
|
||||
GROUP BY TABL.name,
|
||||
GROUP BY TABL.name,
|
||||
INDX.object_id,
|
||||
INDX.index_id,
|
||||
INDX.name
|
||||
ORDER BY
|
||||
ORDER BY
|
||||
(SUM(ALOC.total_pages)*8/1024) DESC
|
||||
Vendored
+5
-5
@@ -7,11 +7,11 @@
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}"
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/client/out"],
|
||||
"outFiles": ["${workspaceFolder}/client/out"],
|
||||
"preLaunchTask": "npm"
|
||||
},
|
||||
{
|
||||
@@ -19,10 +19,10 @@
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/client/out/test" ],
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/client/out/test" ],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/client/out/test"],
|
||||
"outFiles": ["${workspaceFolder}/client/out/test"],
|
||||
"preLaunchTask": "npm"
|
||||
},
|
||||
{
|
||||
@@ -31,7 +31,7 @@
|
||||
"request": "attach",
|
||||
"port": 6004,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/server/out"]
|
||||
"outFiles": ["${workspaceFolder}/server/out"]
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// Available variables which can be used inside of strings.
|
||||
// ${workspaceRoot}: the root folder of the team
|
||||
// ${workspaceFolder}: the root folder of the team
|
||||
// ${file}: the current opened file
|
||||
// ${fileBasename}: the current opened file's basename
|
||||
// ${fileDirname}: the current opened file's dirname
|
||||
|
||||
@@ -6,21 +6,25 @@
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorRange, Color } from 'vscode';
|
||||
import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorInformation, Color, ColorPresentation } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed';
|
||||
|
||||
import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
|
||||
import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed';
|
||||
import { DocumentColorRequest, DocumentColorParams, ColorPresentationParams, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
|
||||
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import { hash } from './utils/hash';
|
||||
let localize = nls.loadMessageBundle();
|
||||
|
||||
namespace VSCodeContentRequest {
|
||||
export const type: RequestType<string, string, any, any> = new RequestType('vscode/content');
|
||||
}
|
||||
|
||||
namespace SchemaContentChangeNotification {
|
||||
export const type: NotificationType<string, any> = new NotificationType('json/schemaContent');
|
||||
}
|
||||
|
||||
export interface ISchemaAssociations {
|
||||
[pattern: string]: string[];
|
||||
}
|
||||
@@ -56,16 +60,13 @@ interface JSONSchemaSettings {
|
||||
schema?: any;
|
||||
}
|
||||
|
||||
const ColorFormat_HEX = {
|
||||
opaque: '"#{red:X}{green:X}{blue:X}"',
|
||||
transparent: '"#{red:X}{green:X}{blue:X}{alpha:X}"'
|
||||
};
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
|
||||
let toDispose = context.subscriptions;
|
||||
|
||||
let packageInfo = getPackageInfo(context);
|
||||
let telemetryReporter: TelemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
|
||||
context.subscriptions.push(telemetryReporter);
|
||||
toDispose.push(telemetryReporter);
|
||||
|
||||
// The server is implemented in node
|
||||
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'jsonServerMain.js'));
|
||||
@@ -102,6 +103,7 @@ export function activate(context: ExtensionContext) {
|
||||
client.registerFeature(new ConfigurationFeature(client));
|
||||
|
||||
let disposable = client.start();
|
||||
toDispose.push(disposable);
|
||||
client.onReady().then(() => {
|
||||
client.onTelemetry(e => {
|
||||
if (telemetryReporter) {
|
||||
@@ -119,27 +121,48 @@ export function activate(context: ExtensionContext) {
|
||||
});
|
||||
});
|
||||
|
||||
let handleContentChange = (uri: Uri) => {
|
||||
if (uri.scheme === 'vscode' && uri.authority === 'schemas') {
|
||||
client.sendNotification(SchemaContentChangeNotification.type, uri.toString());
|
||||
}
|
||||
};
|
||||
toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri)));
|
||||
toDispose.push(workspace.onDidCloseTextDocument(d => handleContentChange(d.uri)));
|
||||
|
||||
client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context));
|
||||
|
||||
// register color provider
|
||||
context.subscriptions.push(languages.registerColorProvider(documentSelector, {
|
||||
provideDocumentColors(document: TextDocument): Thenable<ColorRange[]> {
|
||||
let params = client.code2ProtocolConverter.asDocumentSymbolParams(document);
|
||||
toDispose.push(languages.registerColorProvider(documentSelector, {
|
||||
provideDocumentColors(document: TextDocument): Thenable<ColorInformation[]> {
|
||||
let params: DocumentColorParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document)
|
||||
};
|
||||
return client.sendRequest(DocumentColorRequest.type, params).then(symbols => {
|
||||
return symbols.map(symbol => {
|
||||
let range = client.protocol2CodeConverter.asRange(symbol.range);
|
||||
let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha);
|
||||
return new ColorRange(range, color, [ColorFormat_HEX]);
|
||||
let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha);
|
||||
return new ColorInformation(range, color);
|
||||
});
|
||||
});
|
||||
},
|
||||
provideColorPresentations(color: Color, context): Thenable<ColorPresentation[]> {
|
||||
let params: ColorPresentationParams = {
|
||||
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(context.document),
|
||||
color: color,
|
||||
range: client.code2ProtocolConverter.asRange(context.range)
|
||||
};
|
||||
return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => {
|
||||
return presentations.map(p => {
|
||||
let presentation = new ColorPresentation(p.label);
|
||||
presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit);
|
||||
presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits);
|
||||
return presentation;
|
||||
});
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
context.subscriptions.push(disposable);
|
||||
|
||||
languages.setLanguageConfiguration('json', {
|
||||
wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/,
|
||||
indentationRules: {
|
||||
@@ -184,9 +207,6 @@ function getSchemaAssociation(context: ExtensionContext): ISchemaAssociations {
|
||||
|
||||
function getSettings(): Settings {
|
||||
let httpSettings = workspace.getConfiguration('http');
|
||||
let jsonSettings = workspace.getConfiguration('json');
|
||||
|
||||
let schemas = [];
|
||||
|
||||
let settings: Settings = {
|
||||
http: {
|
||||
@@ -194,42 +214,70 @@ function getSettings(): Settings {
|
||||
proxyStrictSSL: httpSettings.get('proxyStrictSSL')
|
||||
},
|
||||
json: {
|
||||
format: jsonSettings.get('format'),
|
||||
schemas: schemas,
|
||||
format: workspace.getConfiguration('json').get('format'),
|
||||
schemas: [],
|
||||
}
|
||||
};
|
||||
let schemaSettingsById: { [schemaId: string]: JSONSchemaSettings } = Object.create(null);
|
||||
let collectSchemaSettings = (schemaSettings: JSONSchemaSettings[], rootPath?: string, fileMatchPrefix?: string) => {
|
||||
for (let setting of schemaSettings) {
|
||||
let url = getSchemaId(setting, rootPath);
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
let schemaSetting = schemaSettingsById[url];
|
||||
if (!schemaSetting) {
|
||||
schemaSetting = schemaSettingsById[url] = { url, fileMatch: [] };
|
||||
settings.json.schemas.push(schemaSetting);
|
||||
}
|
||||
let fileMatches = setting.fileMatch;
|
||||
if (Array.isArray(fileMatches)) {
|
||||
if (fileMatchPrefix) {
|
||||
fileMatches = fileMatches.map(m => fileMatchPrefix + m);
|
||||
}
|
||||
schemaSetting.fileMatch.push(...fileMatches);
|
||||
}
|
||||
if (setting.schema) {
|
||||
schemaSetting.schema = setting.schema;
|
||||
}
|
||||
}
|
||||
};
|
||||
let settingsSchemas = jsonSettings.get('schemas');
|
||||
if (Array.isArray(settingsSchemas)) {
|
||||
schemas.push(...settingsSchemas);
|
||||
}
|
||||
|
||||
// merge global and folder settings. Qualify all file matches with the folder path.
|
||||
let globalSettings = workspace.getConfiguration('json', null).get<JSONSchemaSettings[]>('schemas');
|
||||
if (Array.isArray(globalSettings)) {
|
||||
collectSchemaSettings(globalSettings, workspace.rootPath);
|
||||
}
|
||||
let folders = workspace.workspaceFolders;
|
||||
if (folders) {
|
||||
folders.forEach(folder => {
|
||||
let jsonConfig = workspace.getConfiguration('json', folder.uri);
|
||||
let schemaConfigInfo = jsonConfig.inspect<JSONSchemaSettings[]>('schemas');
|
||||
for (let folder of folders) {
|
||||
let folderUri = folder.uri;
|
||||
let schemaConfigInfo = workspace.getConfiguration('json', folderUri).inspect<JSONSchemaSettings[]>('schemas');
|
||||
let folderSchemas = schemaConfigInfo.workspaceFolderValue;
|
||||
if (Array.isArray(folderSchemas)) {
|
||||
folderSchemas.forEach(schema => {
|
||||
let url = schema.url;
|
||||
if (!url && schema.schema) {
|
||||
url = schema.schema.id;
|
||||
}
|
||||
if (url && url[0] === '.') {
|
||||
url = Uri.file(path.normalize(path.join(folder.uri.fsPath, url))).toString();
|
||||
}
|
||||
let fileMatch = schema.fileMatch;
|
||||
if (fileMatch) {
|
||||
fileMatch = fileMatch.map(m => folder.uri.toString() + '*' + m);
|
||||
}
|
||||
schemas.push({ url, fileMatch, schema: schema.schema });
|
||||
});
|
||||
let folderPath = folderUri.toString();
|
||||
if (folderPath[folderPath.length - 1] !== '/') {
|
||||
folderPath = folderPath + '/';
|
||||
}
|
||||
collectSchemaSettings(folderSchemas, folderUri.fsPath, folderPath + '*');
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
function getSchemaId(schema: JSONSchemaSettings, rootPath?: string) {
|
||||
let url = schema.url;
|
||||
if (!url) {
|
||||
if (schema.schema) {
|
||||
url = schema.schema.id || `vscode://schemas/custom/${encodeURIComponent(hash(schema.schema).toString(16))}`;
|
||||
}
|
||||
} else if (rootPath && (url[0] === '.' || url[0] === '/')) {
|
||||
url = Uri.file(path.normalize(path.join(rootPath, url))).toString();
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function getPackageInfo(context: ExtensionContext): IPackageInfo {
|
||||
let extensionPackage = require(context.asAbsolutePath('./package.json'));
|
||||
if (extensionPackage) {
|
||||
@@ -240,4 +288,4 @@ function getPackageInfo(context: ExtensionContext): IPackageInfo {
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Return a hash value for an object.
|
||||
*/
|
||||
export function hash(obj: any, hashVal = 0): number {
|
||||
switch (typeof obj) {
|
||||
case 'object':
|
||||
if (obj === null) {
|
||||
return numberHash(349, hashVal);
|
||||
} else if (Array.isArray(obj)) {
|
||||
return arrayHash(obj, hashVal);
|
||||
}
|
||||
return objectHash(obj, hashVal);
|
||||
case 'string':
|
||||
return stringHash(obj, hashVal);
|
||||
case 'boolean':
|
||||
return booleanHash(obj, hashVal);
|
||||
case 'number':
|
||||
return numberHash(obj, hashVal);
|
||||
case 'undefined':
|
||||
return numberHash(obj, 937);
|
||||
default:
|
||||
return numberHash(obj, 617);
|
||||
}
|
||||
}
|
||||
|
||||
function numberHash(val: number, initialHashVal: number): number {
|
||||
return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32
|
||||
}
|
||||
|
||||
function booleanHash(b: boolean, initialHashVal: number): number {
|
||||
return numberHash(b ? 433 : 863, initialHashVal);
|
||||
}
|
||||
|
||||
function stringHash(s: string, hashVal: number) {
|
||||
hashVal = numberHash(149417, hashVal);
|
||||
for (let i = 0, length = s.length; i < length; i++) {
|
||||
hashVal = numberHash(s.charCodeAt(i), hashVal);
|
||||
}
|
||||
return hashVal;
|
||||
}
|
||||
|
||||
function arrayHash(arr: any[], initialHashVal: number): number {
|
||||
initialHashVal = numberHash(104579, initialHashVal);
|
||||
return arr.reduce((hashVal, item) => hash(item, hashVal), initialHashVal);
|
||||
}
|
||||
|
||||
function objectHash(obj: any, initialHashVal: number): number {
|
||||
initialHashVal = numberHash(181387, initialHashVal);
|
||||
return Object.keys(obj).sort().reduce((hashVal, key) => {
|
||||
hashVal = stringHash(key, hashVal);
|
||||
return hash(obj[key], hashVal);
|
||||
}, initialHashVal);
|
||||
}
|
||||
Generated
+12
-12
@@ -13,24 +13,24 @@
|
||||
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz"
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "3.3.1",
|
||||
"from": "vscode-jsonrpc@>=3.3.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz"
|
||||
"version": "3.5.0-next.2",
|
||||
"from": "vscode-jsonrpc@3.5.0-next.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz"
|
||||
},
|
||||
"vscode-languageclient": {
|
||||
"version": "3.4.0-next.17",
|
||||
"from": "vscode-languageclient@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz"
|
||||
"version": "3.5.0-next.4",
|
||||
"from": "vscode-languageclient@3.5.0-next.4",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0-next.4.tgz"
|
||||
},
|
||||
"vscode-languageserver-protocol": {
|
||||
"version": "3.1.1",
|
||||
"from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz"
|
||||
"version": "3.5.0-next.5",
|
||||
"from": "vscode-languageserver-protocol@3.5.0-next.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz"
|
||||
},
|
||||
"vscode-languageserver-types": {
|
||||
"version": "3.3.0",
|
||||
"from": "vscode-languageserver-types@>=3.3.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz"
|
||||
"version": "3.5.0-next.2",
|
||||
"from": "vscode-languageserver-types@3.5.0-next.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz"
|
||||
},
|
||||
"vscode-nls": {
|
||||
"version": "2.0.2",
|
||||
|
||||
@@ -133,11 +133,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.0.8",
|
||||
"vscode-languageclient": "3.4.0-next.17",
|
||||
"vscode-languageserver-protocol": "^3.1.1",
|
||||
"vscode-languageclient": "3.5.0-next.4",
|
||||
"vscode-nls": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^6.0.51"
|
||||
"@types/node": "7.0.43"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -8,25 +8,25 @@
|
||||
"request": "attach",
|
||||
"port": 6004,
|
||||
"sourceMaps": true,
|
||||
"outDir": "${workspaceRoot}/out"
|
||||
"outDir": "${workspaceFolder}/out"
|
||||
},
|
||||
{
|
||||
"name": "Unit Tests",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha",
|
||||
"program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha",
|
||||
"stopOnEntry": false,
|
||||
"args": [
|
||||
"--timeout",
|
||||
"999999",
|
||||
"--colors"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"runtimeExecutable": null,
|
||||
"runtimeArgs": [],
|
||||
"env": {},
|
||||
"sourceMaps": true,
|
||||
"outDir": "${workspaceRoot}/out"
|
||||
"outDir": "${workspaceFolder}/out"
|
||||
}
|
||||
]
|
||||
}
|
||||
+14
-14
@@ -43,29 +43,29 @@
|
||||
"resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz"
|
||||
},
|
||||
"vscode-json-languageservice": {
|
||||
"version": "2.0.16",
|
||||
"version": "3.0.0",
|
||||
"from": "vscode-json-languageservice@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.16.tgz"
|
||||
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-3.0.0.tgz"
|
||||
},
|
||||
"vscode-jsonrpc": {
|
||||
"version": "3.3.1",
|
||||
"from": "vscode-jsonrpc@>=3.3.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz"
|
||||
"version": "3.5.0-next.2",
|
||||
"from": "vscode-jsonrpc@3.5.0-next.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz"
|
||||
},
|
||||
"vscode-languageserver": {
|
||||
"version": "3.4.0-next.6",
|
||||
"from": "vscode-languageserver@next",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz"
|
||||
"version": "3.5.0-next.6",
|
||||
"from": "vscode-languageserver@3.5.0-next.6",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz"
|
||||
},
|
||||
"vscode-languageserver-protocol": {
|
||||
"version": "3.1.1",
|
||||
"from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz"
|
||||
"version": "3.5.0-next.5",
|
||||
"from": "vscode-languageserver-protocol@3.5.0-next.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz"
|
||||
},
|
||||
"vscode-languageserver-types": {
|
||||
"version": "3.3.0",
|
||||
"from": "vscode-languageserver-types@>=3.0.3 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz"
|
||||
"version": "3.5.0-next.2",
|
||||
"from": "vscode-languageserver-types@3.5.0-next.2",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz"
|
||||
},
|
||||
"vscode-nls": {
|
||||
"version": "2.0.2",
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^1.0.0",
|
||||
"request-light": "^0.2.1",
|
||||
"vscode-json-languageservice": "^2.0.16",
|
||||
"vscode-languageserver": "3.4.0-next.6",
|
||||
"vscode-languageserver-protocol": "^3.1.1",
|
||||
"vscode-nls": "^2.0.2"
|
||||
"vscode-json-languageservice": "3.0.0",
|
||||
"vscode-languageserver": "3.5.0-next.6",
|
||||
"vscode-nls": "^2.0.2",
|
||||
"vscode-uri": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^6.0.51"
|
||||
"@types/node": "7.0.43"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:json-server",
|
||||
|
||||
@@ -10,12 +10,11 @@ import {
|
||||
DocumentRangeFormattingRequest, Disposable, ServerCapabilities
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
|
||||
import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
|
||||
|
||||
import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light';
|
||||
import path = require('path');
|
||||
import fs = require('fs');
|
||||
import URI from './utils/uri';
|
||||
import URI from 'vscode-uri';
|
||||
import * as URL from 'url';
|
||||
import Strings = require('./utils/strings');
|
||||
import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService } from 'vscode-json-languageservice';
|
||||
@@ -36,6 +35,10 @@ namespace VSCodeContentRequest {
|
||||
export const type: RequestType<string, string, any, any> = new RequestType('vscode/content');
|
||||
}
|
||||
|
||||
namespace SchemaContentChangeNotification {
|
||||
export const type: NotificationType<string, any> = new NotificationType('json/schemaContent');
|
||||
}
|
||||
|
||||
// Create a connection for the server
|
||||
let connection: IConnection = createConnection();
|
||||
|
||||
@@ -54,9 +57,7 @@ let clientDynamicRegisterSupport = false;
|
||||
|
||||
// After the server has started the client sends an initilize request. The server receives
|
||||
// in the passed params the rootPath of the workspace plus the client capabilities.
|
||||
let workspaceRoot: URI;
|
||||
connection.onInitialize((params: InitializeParams): InitializeResult => {
|
||||
workspaceRoot = URI.parse(params.rootPath);
|
||||
|
||||
function hasClientCapability(...keys: string[]) {
|
||||
let c = params.capabilities;
|
||||
@@ -175,6 +176,11 @@ connection.onNotification(SchemaAssociationNotification.type, associations => {
|
||||
updateConfiguration();
|
||||
});
|
||||
|
||||
// A schema has changed
|
||||
connection.onNotification(SchemaContentChangeNotification.type, uri => {
|
||||
languageService.resetSchema(uri);
|
||||
});
|
||||
|
||||
function updateConfiguration() {
|
||||
let languageSettings: LanguageSettings = {
|
||||
validate: true,
|
||||
@@ -192,19 +198,12 @@ function updateConfiguration() {
|
||||
}
|
||||
}
|
||||
if (jsonConfigurationSettings) {
|
||||
jsonConfigurationSettings.forEach(schema => {
|
||||
jsonConfigurationSettings.forEach((schema, index) => {
|
||||
let uri = schema.url;
|
||||
if (!uri && schema.schema) {
|
||||
uri = schema.schema.id;
|
||||
}
|
||||
if (!uri && schema.fileMatch) {
|
||||
uri = 'vscode://schemas/custom/' + encodeURIComponent(schema.fileMatch.join('&'));
|
||||
uri = schema.schema.id || `vscode://schemas/custom/${index}`;
|
||||
}
|
||||
if (uri) {
|
||||
if (uri[0] === '.' && workspaceRoot) {
|
||||
// workspace relative path
|
||||
uri = URI.file(path.normalize(path.join(workspaceRoot.fsPath, uri))).toString();
|
||||
}
|
||||
languageSettings.schemas.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema });
|
||||
}
|
||||
});
|
||||
@@ -321,5 +320,14 @@ connection.onRequest(DocumentColorRequest.type, params => {
|
||||
return [];
|
||||
});
|
||||
|
||||
connection.onRequest(ColorPresentationRequest.type, params => {
|
||||
let document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
let jsonDocument = getJSONDocument(document);
|
||||
return languageService.getColorPresentations(document, jsonDocument, params.color, params.range);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
@@ -388,11 +388,11 @@
|
||||
"c": "\\u0056",
|
||||
"t": "source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json constant.character.escape.json",
|
||||
"r": {
|
||||
"dark_plus": "string: #CE9178",
|
||||
"light_plus": "string: #A31515",
|
||||
"dark_plus": "constant.character.escape: #D7BA7D",
|
||||
"light_plus": "constant.character.escape: #A31515",
|
||||
"dark_vs": "string: #CE9178",
|
||||
"light_vs": "string: #A31515",
|
||||
"hc_black": "string: #CE9178"
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -37,5 +37,8 @@
|
||||
["(", ")"],
|
||||
["[", "]"],
|
||||
["`", "`"]
|
||||
]
|
||||
],
|
||||
"folding": {
|
||||
"offSide": true
|
||||
}
|
||||
}
|
||||
Generated
+132
-18
@@ -2,75 +2,189 @@
|
||||
"name": "vscode-markdown",
|
||||
"version": "0.2.0",
|
||||
"dependencies": {
|
||||
"@types/highlight.js": {
|
||||
"version": "9.1.10",
|
||||
"from": "@types/highlight.js@9.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.1.10.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"@types/markdown-it": {
|
||||
"version": "0.0.2",
|
||||
"from": "@types/markdown-it@0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-0.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "7.0.43",
|
||||
"from": "@types/node@7.0.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.43.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"applicationinsights": {
|
||||
"version": "0.18.0",
|
||||
"from": "applicationinsights@0.18.0",
|
||||
"from": "applicationinsights@https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz"
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.9",
|
||||
"from": "argparse@>=1.0.7 <2.0.0",
|
||||
"from": "argparse@https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz"
|
||||
},
|
||||
"binaryextensions": {
|
||||
"version": "1.0.1",
|
||||
"from": "binaryextensions@1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"from": "core-util-is@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.1.1",
|
||||
"from": "entities@>=1.1.1 <1.2.0",
|
||||
"from": "entities@https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz"
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"from": "escape-string-regexp@1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"gulp-rename": {
|
||||
"version": "1.2.2",
|
||||
"from": "gulp-rename@1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"gulp-replace": {
|
||||
"version": "0.5.4",
|
||||
"from": "gulp-replace@0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-0.5.4.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "9.5.0",
|
||||
"from": "highlight.js@>=9.3.0 <10.0.0",
|
||||
"from": "highlight.js@https://registry.npmjs.org/highlight.js/-/highlight.js-9.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.5.0.tgz"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"from": "inherits@2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"from": "isarray@1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"istextorbinary": {
|
||||
"version": "1.0.2",
|
||||
"from": "istextorbinary@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "2.0.3",
|
||||
"from": "linkify-it@>=2.0.0 <3.0.0",
|
||||
"from": "linkify-it@https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz"
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "8.2.2",
|
||||
"from": "markdown-it@8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.2.2.tgz"
|
||||
"version": "8.4.0",
|
||||
"from": "markdown-it@8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.0.tgz"
|
||||
},
|
||||
"markdown-it-named-headers": {
|
||||
"version": "0.0.4",
|
||||
"from": "markdown-it-named-headers@0.0.4",
|
||||
"from": "markdown-it-named-headers@https://registry.npmjs.org/markdown-it-named-headers/-/markdown-it-named-headers-0.0.4.tgz",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it-named-headers/-/markdown-it-named-headers-0.0.4.tgz"
|
||||
},
|
||||
"mdurl": {
|
||||
"version": "1.0.1",
|
||||
"from": "mdurl@>=1.0.1 <1.1.0",
|
||||
"from": "mdurl@https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz"
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"from": "object-assign@4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
"from": "process-nextick-args@1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.3",
|
||||
"from": "readable-stream@2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"replacestream": {
|
||||
"version": "4.0.2",
|
||||
"from": "replacestream@4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"from": "safe-buffer@5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"from": "sprintf-js@>=1.0.2 <1.1.0",
|
||||
"from": "sprintf-js@https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
||||
},
|
||||
"string": {
|
||||
"version": "3.3.1",
|
||||
"from": "string@>=3.0.1 <4.0.0",
|
||||
"from": "string@https://registry.npmjs.org/string/-/string-3.3.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string/-/string-3.3.1.tgz"
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"from": "string_decoder@1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"textextensions": {
|
||||
"version": "1.0.2",
|
||||
"from": "textextensions@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.3",
|
||||
"from": "uc.micro@>=1.0.3 <2.0.0",
|
||||
"from": "uc.micro@https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz"
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"from": "util-deprecate@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"vscode-extension-telemetry": {
|
||||
"version": "0.0.7",
|
||||
"from": "vscode-extension-telemetry@>=0.0.8 <0.0.9",
|
||||
"version": "0.0.8",
|
||||
"from": "vscode-extension-telemetry@https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz"
|
||||
},
|
||||
"vscode-nls": {
|
||||
"version": "2.0.2",
|
||||
"from": "vscode-nls@>=2.0.1 <3.0.0",
|
||||
"from": "vscode-nls@https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
|
||||
},
|
||||
"winreg": {
|
||||
"version": "1.2.3",
|
||||
"from": "winreg@1.2.3",
|
||||
"from": "winreg@https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,52 @@
|
||||
{
|
||||
"language": "markdown",
|
||||
"scopeName": "text.html.markdown",
|
||||
"path": "./syntaxes/markdown.tmLanguage"
|
||||
"path": "./syntaxes/markdown.tmLanguage",
|
||||
"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.jade": "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"
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
@@ -131,6 +176,10 @@
|
||||
{
|
||||
"command": "markdown.showPreviewSecuritySelector",
|
||||
"when": "editorLangId == markdown"
|
||||
},
|
||||
{
|
||||
"command": "markdown.showPreviewSecuritySelector",
|
||||
"when": "resourceScheme == markdown"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -162,7 +211,8 @@
|
||||
"markdown.styles": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"description": "%markdown.styles.dec%"
|
||||
"description": "%markdown.styles.dec%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.previewFrontMatter": {
|
||||
"type": "string",
|
||||
@@ -171,52 +221,62 @@
|
||||
"show"
|
||||
],
|
||||
"default": "hide",
|
||||
"description": "%markdown.previewFrontMatter.dec%"
|
||||
"description": "%markdown.previewFrontMatter.dec%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.breaks": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%markdown.preview.breaks.desc%"
|
||||
"description": "%markdown.preview.breaks.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.linkify": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%markdown.preview.linkify%"
|
||||
"description": "%markdown.preview.linkify%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.fontFamily": {
|
||||
"type": "string",
|
||||
"default": "-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'HelveticaNeue-Light', 'Ubuntu', 'Droid Sans', sans-serif",
|
||||
"description": "%markdown.preview.fontFamily.desc%"
|
||||
"description": "%markdown.preview.fontFamily.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.fontSize": {
|
||||
"type": "number",
|
||||
"default": 14,
|
||||
"description": "%markdown.preview.fontSize.desc%"
|
||||
"description": "%markdown.preview.fontSize.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.lineHeight": {
|
||||
"type": "number",
|
||||
"default": 1.6,
|
||||
"description": "%markdown.preview.lineHeight.desc%"
|
||||
"description": "%markdown.preview.lineHeight.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.scrollPreviewWithEditorSelection": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%markdown.preview.scrollPreviewWithEditorSelection.desc%"
|
||||
"description": "%markdown.preview.scrollPreviewWithEditorSelection.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.markEditorSelection": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%markdown.preview.markEditorSelection.desc%"
|
||||
"description": "%markdown.preview.markEditorSelection.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.scrollEditorWithPreview": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%markdown.preview.scrollEditorWithPreview.desc%"
|
||||
"description": "%markdown.preview.scrollEditorWithPreview.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.preview.doubleClickToSwitchToEditor": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%markdown.preview.doubleClickToSwitchToEditor.desc%"
|
||||
"description": "%markdown.preview.doubleClickToSwitchToEditor.desc%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"markdown.trace": {
|
||||
"type": "string",
|
||||
@@ -225,7 +285,8 @@
|
||||
"verbose"
|
||||
],
|
||||
"default": "off",
|
||||
"description": "%markdown.trace.desc%"
|
||||
"description": "%markdown.trace.desc%",
|
||||
"scope": "window"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -234,7 +295,13 @@
|
||||
"editor.wordWrap": "on",
|
||||
"editor.quickSuggestions": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"jsonValidation": [
|
||||
{
|
||||
"fileMatch": "package.json",
|
||||
"url": "./schemas/package.schema.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown ./tsconfig.json",
|
||||
@@ -242,15 +309,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"highlight.js": "9.5.0",
|
||||
"markdown-it": "8.2.2",
|
||||
"markdown-it": "^8.4.0",
|
||||
"markdown-it-named-headers": "0.0.4",
|
||||
"vscode-extension-telemetry": "0.0.8",
|
||||
"vscode-nls": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/highlight.js": "^9.1.9",
|
||||
"@types/highlight.js": "9.1.10",
|
||||
"@types/markdown-it": "0.0.2",
|
||||
"@types/node": "^7.0.4",
|
||||
"@types/node": "8.0.33",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-replace": "^0.5.4"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Markdown contributions to package.json",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"contributes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"markdown.previewStyles": {
|
||||
"type": "array",
|
||||
"description": "Contributed CSS files that change the look or layout of the Markdown preview",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Extension relative path to a css file"
|
||||
}
|
||||
},
|
||||
"markdown.previewScripts": {
|
||||
"type": "array",
|
||||
"description": "Contributed scripts that are executed in the Markdown preview",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Extension relative path to a JavaScript file"
|
||||
}
|
||||
},
|
||||
"markdown.markdownItPlugins": {
|
||||
"type": "boolean",
|
||||
"description": "Does this extension contribute a markdown-it plugin?"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,20 +8,61 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
export default class MarkdownDocumentLinkProvider implements vscode.DocumentLinkProvider {
|
||||
function normalizeLink(document: vscode.TextDocument, link: string, base: string): vscode.Uri {
|
||||
const uri = vscode.Uri.parse(link);
|
||||
if (uri.scheme) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
private _linkPattern = /(\[[^\]]*\]\(\s*?)(((((?=.*\)\)+)|(?=.*\)\]+))[^\s\)]+?)|([^\s]+)))\)/g;
|
||||
// assume it must be a file
|
||||
let resourcePath = uri.path;
|
||||
if (!uri.path) {
|
||||
resourcePath = document.uri.path;
|
||||
} else if (uri.path[0] === '/') {
|
||||
const root = vscode.workspace.getWorkspaceFolder(document.uri);
|
||||
if (root) {
|
||||
resourcePath = path.join(root.uri.fsPath, uri.path);
|
||||
}
|
||||
} else {
|
||||
resourcePath = path.join(base, uri.path);
|
||||
}
|
||||
|
||||
constructor() { }
|
||||
return vscode.Uri.parse(`command:_markdown.openDocumentLink?${encodeURIComponent(JSON.stringify({ fragment: uri.fragment, path: resourcePath }))}`);
|
||||
}
|
||||
|
||||
public provideDocumentLinks(document: vscode.TextDocument, _token: vscode.CancellationToken): vscode.DocumentLink[] {
|
||||
const results: vscode.DocumentLink[] = [];
|
||||
function matchAll(pattern: RegExp, text: string): Array<RegExpMatchArray> {
|
||||
const out: RegExpMatchArray[] = [];
|
||||
pattern.lastIndex = 0;
|
||||
let match: RegExpMatchArray | null;
|
||||
while ((match = pattern.exec(text))) {
|
||||
out.push(match);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
private linkPattern = /(\[[^\]]*\]\(\s*?)(((((?=.*\)\)+)|(?=.*\)\]+))[^\s\)]+?)|([^\s]+)))\)/g;
|
||||
private referenceLinkPattern = /(\[([^\]]+)\]\[\s*?)([^\s\]]*?)\]/g;
|
||||
private definitionPattern = /^([\t ]*\[([^\]]+)\]:\s*)(\S+)/gm;
|
||||
|
||||
public provideDocumentLinks(
|
||||
document: vscode.TextDocument,
|
||||
_token: vscode.CancellationToken
|
||||
): vscode.DocumentLink[] {
|
||||
const base = path.dirname(document.uri.fsPath);
|
||||
const text = document.getText();
|
||||
|
||||
this._linkPattern.lastIndex = 0;
|
||||
let match: RegExpMatchArray | null;
|
||||
while ((match = this._linkPattern.exec(text))) {
|
||||
return this.providerInlineLinks(text, document, base)
|
||||
.concat(this.provideReferenceLinks(text, document, base));
|
||||
}
|
||||
|
||||
private providerInlineLinks(
|
||||
text: string,
|
||||
document: vscode.TextDocument,
|
||||
base: string
|
||||
): vscode.DocumentLink[] {
|
||||
const results: vscode.DocumentLink[] = [];
|
||||
for (const match of matchAll(this.linkPattern, text)) {
|
||||
const pre = match[1];
|
||||
const link = match[2];
|
||||
const offset = (match.index || 0) + pre.length;
|
||||
@@ -30,7 +71,7 @@ export default class MarkdownDocumentLinkProvider implements vscode.DocumentLink
|
||||
try {
|
||||
results.push(new vscode.DocumentLink(
|
||||
new vscode.Range(linkStart, linkEnd),
|
||||
this.normalizeLink(document, link, base)));
|
||||
normalizeLink(document, link, base)));
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
@@ -39,25 +80,73 @@ export default class MarkdownDocumentLinkProvider implements vscode.DocumentLink
|
||||
return results;
|
||||
}
|
||||
|
||||
private normalizeLink(document: vscode.TextDocument, link: string, base: string): vscode.Uri {
|
||||
const uri = vscode.Uri.parse(link);
|
||||
if (uri.scheme) {
|
||||
return uri;
|
||||
}
|
||||
private provideReferenceLinks(
|
||||
text: string,
|
||||
document: vscode.TextDocument,
|
||||
base: string
|
||||
): vscode.DocumentLink[] {
|
||||
const results: vscode.DocumentLink[] = [];
|
||||
|
||||
// assume it must be a file
|
||||
let resourcePath = uri.path;
|
||||
if (!uri.path) {
|
||||
resourcePath = document.uri.path;
|
||||
} else if (uri.path[0] === '/') {
|
||||
const root = vscode.workspace.getWorkspaceFolder(document.uri);
|
||||
if (root) {
|
||||
resourcePath = path.join(root.uri.fsPath, uri.path);
|
||||
const definitions = this.getDefinitions(text, document);
|
||||
for (const match of matchAll(this.referenceLinkPattern, text)) {
|
||||
let linkStart: vscode.Position;
|
||||
let linkEnd: vscode.Position;
|
||||
let reference = match[3];
|
||||
if (reference) { // [text][ref]
|
||||
const pre = match[1];
|
||||
const offset = (match.index || 0) + pre.length;
|
||||
linkStart = document.positionAt(offset);
|
||||
linkEnd = document.positionAt(offset + reference.length);
|
||||
} else if (match[2]) { // [ref][]
|
||||
reference = match[2];
|
||||
const offset = (match.index || 0) + 1;
|
||||
linkStart = document.positionAt(offset);
|
||||
linkEnd = document.positionAt(offset + match[2].length);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const link = definitions.get(reference);
|
||||
if (link) {
|
||||
results.push(new vscode.DocumentLink(
|
||||
new vscode.Range(linkStart, linkEnd),
|
||||
vscode.Uri.parse(`command:_markdown.moveCursorToPosition?${encodeURIComponent(JSON.stringify([link.linkRange.start.line, link.linkRange.start.character]))}`)));
|
||||
}
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
} else {
|
||||
resourcePath = path.join(base, uri.path);
|
||||
}
|
||||
|
||||
return vscode.Uri.parse(`command:_markdown.openDocumentLink?${encodeURIComponent(JSON.stringify({ fragment: uri.fragment, path: resourcePath }))}`);
|
||||
for (const definition of Array.from(definitions.values())) {
|
||||
try {
|
||||
results.push(new vscode.DocumentLink(
|
||||
definition.linkRange,
|
||||
normalizeLink(document, definition.link, base)));
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private getDefinitions(text: string, document: vscode.TextDocument) {
|
||||
const out = new Map<string, { link: string, linkRange: vscode.Range }>();
|
||||
for (const match of matchAll(this.definitionPattern, text)) {
|
||||
const pre = match[1];
|
||||
const reference = match[2];
|
||||
const link = match[3].trim();
|
||||
|
||||
const offset = (match.index || 0) + pre.length;
|
||||
const linkStart = document.positionAt(offset);
|
||||
const linkEnd = document.positionAt(offset + link.length);
|
||||
|
||||
out.set(reference, {
|
||||
link: link,
|
||||
linkRange: new vscode.Range(linkStart, linkEnd)
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import { MarkdownEngine } from './markdownEngine';
|
||||
import DocumentLinkProvider from './documentLinkProvider';
|
||||
import LinkProvider from './documentLinkProvider';
|
||||
import MDDocumentSymbolProvider from './documentSymbolProvider';
|
||||
import { ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './security';
|
||||
import { MDDocumentContentProvider, getMarkdownUri, isMarkdownFile } from './previewContentProvider';
|
||||
@@ -96,18 +96,28 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const symbolsProviderRegistration = vscode.languages.registerDocumentSymbolProvider({ language: 'markdown' }, symbolsProvider);
|
||||
context.subscriptions.push(contentProviderRegistration, symbolsProviderRegistration);
|
||||
|
||||
context.subscriptions.push(vscode.languages.registerDocumentLinkProvider('markdown', new DocumentLinkProvider()));
|
||||
context.subscriptions.push(vscode.languages.registerDocumentLinkProvider('markdown', new LinkProvider()));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('markdown.showPreview', (uri) => showPreview(cspArbiter, uri, false)));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('markdown.showPreviewToSide', uri => showPreview(cspArbiter, uri, true)));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('markdown.showSource', showSource));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('_markdown.moveCursorToPosition', (line: number, character: number) => {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return;
|
||||
}
|
||||
const position = new vscode.Position(line, character);
|
||||
const selection = new vscode.Selection(position, position);
|
||||
vscode.window.activeTextEditor.revealRange(selection);
|
||||
vscode.window.activeTextEditor.selection = selection;
|
||||
}));
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('_markdown.revealLine', (uri, line) => {
|
||||
const sourceUri = vscode.Uri.parse(decodeURIComponent(uri));
|
||||
logger.log('revealLine', { uri, sourceUri: sourceUri.toString(), line });
|
||||
|
||||
vscode.window.visibleTextEditors
|
||||
.filter(editor => isMarkdownFile(editor.document) && editor.document.uri.fsPath === sourceUri.fsPath)
|
||||
.filter(editor => isMarkdownFile(editor.document) && editor.document.uri.toString() === sourceUri.toString())
|
||||
.forEach(editor => {
|
||||
const sourceLine = Math.floor(line);
|
||||
const fraction = line - sourceLine;
|
||||
@@ -243,13 +253,19 @@ function showPreview(cspArbiter: ExtensionContentSecurityPolicyArbiter, uri?: vs
|
||||
const thenable = vscode.commands.executeCommand('vscode.previewHtml',
|
||||
getMarkdownUri(resource),
|
||||
getViewColumn(sideBySide),
|
||||
`Preview '${path.basename(resource.fsPath)}'`,
|
||||
localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath)),
|
||||
{
|
||||
allowScripts: true,
|
||||
allowSvgs: cspArbiter.shouldAllowSvgsForResource(resource)
|
||||
});
|
||||
|
||||
if (telemetryReporter) {
|
||||
/* __GDPR__
|
||||
"openPreview" : {
|
||||
"where" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"how": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
telemetryReporter.sendTelemetryEvent('openPreview', {
|
||||
where: sideBySide ? 'sideBySide' : 'inPlace',
|
||||
how: (uri instanceof vscode.Uri) ? 'action' : 'pallete'
|
||||
@@ -286,7 +302,7 @@ function showSource(mdUri: vscode.Uri) {
|
||||
|
||||
const docUri = vscode.Uri.parse(mdUri.query);
|
||||
for (const editor of vscode.window.visibleTextEditors) {
|
||||
if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.fsPath === docUri.fsPath) {
|
||||
if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.toString() === docUri.toString()) {
|
||||
return vscode.window.showTextDocument(editor.document, editor.viewColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export class MarkdownEngine {
|
||||
}
|
||||
}
|
||||
|
||||
private async getEngine(): Promise<MarkdownIt> {
|
||||
private async getEngine(resource: vscode.Uri): Promise<MarkdownIt> {
|
||||
if (!this.md) {
|
||||
const hljs = await import('highlight.js');
|
||||
const mdnh = await import('markdown-it-named-headers');
|
||||
@@ -66,10 +66,10 @@ export class MarkdownEngine {
|
||||
this.addLinkValidator(this.md);
|
||||
}
|
||||
|
||||
const config = vscode.workspace.getConfiguration('markdown');
|
||||
const config = vscode.workspace.getConfiguration('markdown', resource);
|
||||
this.md.set({
|
||||
breaks: config.get('preview.breaks', false),
|
||||
linkify: config.get('preview.linkify', true)
|
||||
breaks: config.get<boolean>('preview.breaks', false),
|
||||
linkify: config.get<boolean>('preview.linkify', true)
|
||||
});
|
||||
return this.md;
|
||||
}
|
||||
@@ -94,14 +94,14 @@ export class MarkdownEngine {
|
||||
}
|
||||
this.currentDocument = document;
|
||||
this.firstLine = offset;
|
||||
const engine = await this.getEngine();
|
||||
const engine = await this.getEngine(document);
|
||||
return engine.render(text);
|
||||
}
|
||||
|
||||
public async parse(document: vscode.Uri, source: string): Promise<Token[]> {
|
||||
const { text, offset } = this.stripFrontmatter(source);
|
||||
this.currentDocument = document;
|
||||
const engine = await this.getEngine();
|
||||
const engine = await this.getEngine(document);
|
||||
|
||||
return engine.parse(text, {}).map(token => {
|
||||
if (token.map) {
|
||||
|
||||
@@ -38,8 +38,8 @@ export function getMarkdownUri(uri: vscode.Uri) {
|
||||
}
|
||||
|
||||
class MarkdownPreviewConfig {
|
||||
public static getCurrentConfig() {
|
||||
return new MarkdownPreviewConfig();
|
||||
public static getConfigForResource(resource: vscode.Uri) {
|
||||
return new MarkdownPreviewConfig(resource);
|
||||
}
|
||||
|
||||
public readonly scrollBeyondLastLine: boolean;
|
||||
@@ -56,9 +56,9 @@ class MarkdownPreviewConfig {
|
||||
public readonly fontFamily: string | undefined;
|
||||
public readonly styles: string[];
|
||||
|
||||
private constructor() {
|
||||
const editorConfig = vscode.workspace.getConfiguration('editor');
|
||||
const markdownConfig = vscode.workspace.getConfiguration('markdown');
|
||||
private constructor(resource: vscode.Uri) {
|
||||
const editorConfig = vscode.workspace.getConfiguration('editor', resource);
|
||||
const markdownConfig = vscode.workspace.getConfiguration('markdown', resource);
|
||||
const markdownEditorConfig = vscode.workspace.getConfiguration('[markdown]');
|
||||
|
||||
this.scrollBeyondLastLine = editorConfig.get<boolean>('scrollBeyondLastLine', false);
|
||||
@@ -107,11 +107,41 @@ class MarkdownPreviewConfig {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
class PreviewConfigManager {
|
||||
private previewConfigurationsForWorkspaces = new Map<string, MarkdownPreviewConfig>();
|
||||
|
||||
public loadAndCacheConfiguration(
|
||||
resource: vscode.Uri
|
||||
) {
|
||||
const config = MarkdownPreviewConfig.getConfigForResource(resource);
|
||||
this.previewConfigurationsForWorkspaces.set(this.getKey(resource), config);
|
||||
return config;
|
||||
}
|
||||
|
||||
public shouldUpdateConfiguration(
|
||||
resource: vscode.Uri
|
||||
): boolean {
|
||||
const key = this.getKey(resource);
|
||||
const currentConfig = this.previewConfigurationsForWorkspaces.get(key);
|
||||
const newConfig = MarkdownPreviewConfig.getConfigForResource(resource);
|
||||
return (!currentConfig || !currentConfig.isEqualTo(newConfig));
|
||||
}
|
||||
|
||||
private getKey(
|
||||
resource: vscode.Uri
|
||||
): string {
|
||||
const folder = vscode.workspace.getWorkspaceFolder(resource);
|
||||
if (!folder) {
|
||||
return '';
|
||||
}
|
||||
return folder.uri.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
|
||||
private _onDidChange = new vscode.EventEmitter<vscode.Uri>();
|
||||
private _waiting: boolean = false;
|
||||
|
||||
private config: MarkdownPreviewConfig;
|
||||
private previewConfigurations = new PreviewConfigManager();
|
||||
|
||||
private extraStyles: Array<vscode.Uri> = [];
|
||||
private extraScripts: Array<vscode.Uri> = [];
|
||||
@@ -121,9 +151,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
private context: vscode.ExtensionContext,
|
||||
private cspArbiter: ContentSecurityPolicyArbiter,
|
||||
private logger: Logger
|
||||
) {
|
||||
this.config = MarkdownPreviewConfig.getCurrentConfig();
|
||||
}
|
||||
) { }
|
||||
|
||||
public addScript(resource: vscode.Uri): void {
|
||||
this.extraScripts.push(resource);
|
||||
@@ -163,34 +191,34 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)).toString();
|
||||
}
|
||||
|
||||
private computeCustomStyleSheetIncludes(uri: vscode.Uri): string {
|
||||
if (this.config.styles && Array.isArray(this.config.styles)) {
|
||||
return this.config.styles.map((style) => {
|
||||
return `<link rel="stylesheet" class="code-user-style" data-source="${style.replace(/"/g, '"')}" href="${this.fixHref(uri, style)}" type="text/css" media="screen">`;
|
||||
private computeCustomStyleSheetIncludes(resource: vscode.Uri, config: MarkdownPreviewConfig): string {
|
||||
if (config.styles && Array.isArray(config.styles)) {
|
||||
return config.styles.map(style => {
|
||||
return `<link rel="stylesheet" class="code-user-style" data-source="${style.replace(/"/g, '"')}" href="${this.fixHref(resource, style)}" type="text/css" media="screen">`;
|
||||
}).join('\n');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private getSettingsOverrideStyles(nonce: string): string {
|
||||
private getSettingsOverrideStyles(nonce: string, config: MarkdownPreviewConfig): string {
|
||||
return `<style nonce="${nonce}">
|
||||
body {
|
||||
${this.config.fontFamily ? `font-family: ${this.config.fontFamily};` : ''}
|
||||
${isNaN(this.config.fontSize) ? '' : `font-size: ${this.config.fontSize}px;`}
|
||||
${isNaN(this.config.lineHeight) ? '' : `line-height: ${this.config.lineHeight};`}
|
||||
${config.fontFamily ? `font-family: ${config.fontFamily};` : ''}
|
||||
${isNaN(config.fontSize) ? '' : `font-size: ${config.fontSize}px;`}
|
||||
${isNaN(config.lineHeight) ? '' : `line-height: ${config.lineHeight};`}
|
||||
}
|
||||
</style>`;
|
||||
}
|
||||
|
||||
private getStyles(resource: vscode.Uri, nonce: string): string {
|
||||
private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfig): string {
|
||||
const baseStyles = [
|
||||
this.getMediaPath('markdown.css'),
|
||||
this.getMediaPath('tomorrow.css')
|
||||
].concat(this.extraStyles.map(resource => resource.toString()));
|
||||
|
||||
return `${baseStyles.map(href => `<link rel="stylesheet" type="text/css" href="${href}">`).join('\n')}
|
||||
${this.getSettingsOverrideStyles(nonce)}
|
||||
${this.computeCustomStyleSheetIncludes(resource)}`;
|
||||
${this.getSettingsOverrideStyles(nonce, config)}
|
||||
${this.computeCustomStyleSheetIncludes(resource, config)}`;
|
||||
}
|
||||
|
||||
private getScripts(nonce: string): string {
|
||||
@@ -205,20 +233,20 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
|
||||
let initialLine: number | undefined = undefined;
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor && editor.document.uri.fsPath === sourceUri.fsPath) {
|
||||
if (editor && editor.document.uri.toString() === sourceUri.toString()) {
|
||||
initialLine = editor.selection.active.line;
|
||||
}
|
||||
|
||||
const document = await vscode.workspace.openTextDocument(sourceUri);
|
||||
this.config = MarkdownPreviewConfig.getCurrentConfig();
|
||||
const config = this.previewConfigurations.loadAndCacheConfiguration(sourceUri);
|
||||
|
||||
const initialData = {
|
||||
previewUri: uri.toString(),
|
||||
source: sourceUri.toString(),
|
||||
line: initialLine,
|
||||
scrollPreviewWithEditorSelection: this.config.scrollPreviewWithEditorSelection,
|
||||
scrollEditorWithPreview: this.config.scrollEditorWithPreview,
|
||||
doubleClickToSwitchToEditor: this.config.doubleClickToSwitchToEditor
|
||||
scrollPreviewWithEditorSelection: config.scrollPreviewWithEditorSelection,
|
||||
scrollEditorWithPreview: config.scrollEditorWithPreview,
|
||||
doubleClickToSwitchToEditor: config.doubleClickToSwitchToEditor
|
||||
};
|
||||
|
||||
this.logger.log('provideTextDocumentContent', initialData);
|
||||
@@ -227,7 +255,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
const nonce = new Date().getTime() + '' + new Date().getMilliseconds();
|
||||
const csp = this.getCspForResource(sourceUri, nonce);
|
||||
|
||||
const body = await this.engine.render(sourceUri, this.config.previewFrontMatter === 'hide', document.getText());
|
||||
const body = await this.engine.render(sourceUri, config.previewFrontMatter === 'hide', document.getText());
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -236,10 +264,10 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
<meta id="vscode-markdown-preview-data" data-settings="${JSON.stringify(initialData).replace(/"/g, '"')}" data-strings="${JSON.stringify(previewStrings).replace(/"/g, '"')}">
|
||||
<script src="${this.getMediaPath('csp.js')}" nonce="${nonce}"></script>
|
||||
<script src="${this.getMediaPath('loading.js')}" nonce="${nonce}"></script>
|
||||
${this.getStyles(sourceUri, nonce)}
|
||||
${this.getStyles(sourceUri, nonce, config)}
|
||||
<base href="${document.uri.toString(true)}">
|
||||
</head>
|
||||
<body class="vscode-body ${this.config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${this.config.wordWrap ? 'wordWrap' : ''} ${this.config.markEditorSelection ? 'showEditorSelection' : ''}">
|
||||
<body class="vscode-body ${config.scrollBeyondLastLine ? 'scrollBeyondLastLine' : ''} ${config.wordWrap ? 'wordWrap' : ''} ${config.markEditorSelection ? 'showEditorSelection' : ''}">
|
||||
${body}
|
||||
<div class="code-line" data-line="${document.lineCount}"></div>
|
||||
${this.getScripts(nonce)}
|
||||
@@ -248,12 +276,11 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
}
|
||||
|
||||
public updateConfiguration() {
|
||||
const newConfig = MarkdownPreviewConfig.getCurrentConfig();
|
||||
if (!this.config.isEqualTo(newConfig)) {
|
||||
this.config = newConfig;
|
||||
// update all generated md documents
|
||||
for (const document of vscode.workspace.textDocuments) {
|
||||
if (document.uri.scheme === 'markdown') {
|
||||
// update all generated md documents
|
||||
for (const document of vscode.workspace.textDocuments) {
|
||||
if (document.uri.scheme === 'markdown') {
|
||||
const sourceUri = vscode.Uri.parse(document.uri.query);
|
||||
if (this.previewConfigurations.shouldUpdateConfiguration(sourceUri)) {
|
||||
this.update(document.uri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ export class TableOfContentsProvider {
|
||||
}
|
||||
|
||||
private static getHeaderText(header: string): string {
|
||||
return header.replace(/^\s*#+\s*(.*?)\s*\1*$/, (_, word) => `${word.trim()}`);
|
||||
return header.replace(/^\s*#+\s*(.*?)\s*#*$/, (_, word) => word.trim());
|
||||
}
|
||||
|
||||
public static slugify(header: string): string {
|
||||
|
||||
@@ -1,64 +1,69 @@
|
||||
// @ts-check
|
||||
|
||||
var gulp = require('gulp');
|
||||
var util = require("gulp-util");
|
||||
var replace = require('gulp-replace');
|
||||
var rename = require('gulp-rename');
|
||||
|
||||
const languages = [
|
||||
{ name: 'css', identifiers: ['css', 'css.erb'], source: 'source.css' },
|
||||
{ name: 'basic', identifiers: ['html', 'htm', 'shtml', 'xhtml', 'inc', 'tmpl', 'tpl'], source: 'text.html.basic' },
|
||||
{ name: 'ini', identifiers: ['ini', 'conf'], source: 'source.ini' },
|
||||
{ name: 'java', identifiers: ['java', 'bsh'], source: 'source.java' },
|
||||
{ name: 'lua', identifiers: ['lua'], source: 'source.lua' },
|
||||
{ name: 'makefile', identifiers: ['Makefile', 'makefile', 'GNUmakefile', 'OCamlMakefile'], source: 'source.makefile' },
|
||||
{ name: 'perl', identifiers: ['perl', 'pl', 'pm', 'pod', 't', 'PL', 'psgi', 'vcl'], source: 'source.perl' },
|
||||
{ name: 'r', identifiers: ['R', 'r', 's', 'S', 'Rprofile'], source: 'source.r' },
|
||||
{ name: 'ruby', identifiers: ['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'], source: 'source.ruby' },
|
||||
{ name: 'css', language: 'css', identifiers: ['css', 'css.erb'], source: 'source.css' },
|
||||
{ name: 'basic', language: 'html', identifiers: ['html', 'htm', 'shtml', 'xhtml', 'inc', 'tmpl', 'tpl'], source: 'text.html.basic' },
|
||||
{ name: 'ini', language: 'ini', identifiers: ['ini', 'conf'], source: 'source.ini' },
|
||||
{ name: 'java', language: 'java', identifiers: ['java', 'bsh'], source: 'source.java' },
|
||||
{ name: 'lua', language: 'lua', identifiers: ['lua'], source: 'source.lua' },
|
||||
{ name: 'makefile', language: 'makefile', identifiers: ['Makefile', 'makefile', 'GNUmakefile', 'OCamlMakefile'], source: 'source.makefile' },
|
||||
{ name: 'perl', language: 'perl', identifiers: ['perl', 'pl', 'pm', 'pod', 't', 'PL', 'psgi', 'vcl'], source: 'source.perl' },
|
||||
{ name: 'r', language: 'r', identifiers: ['R', 'r', 's', 'S', 'Rprofile'], source: 'source.r' },
|
||||
{ name: 'ruby', language: 'ruby', identifiers: ['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'], source: 'source.ruby' },
|
||||
// Left to its own devices, the PHP grammar will match HTML as a combination of operators
|
||||
// and constants. Therefore, HTML must take precedence over PHP in order to get proper
|
||||
// syntax highlighting.
|
||||
{ name: 'php', identifiers: ['php', 'php3', 'php4', 'php5', 'phpt', 'phtml', 'aw', 'ctp'], source: ['text.html.basic', 'text.html.php#language'] },
|
||||
{ name: 'sql', identifiers: ['sql', 'ddl', 'dml'], source: 'source.sql' },
|
||||
{ name: 'vs_net', identifiers: ['vb'], source: 'source.asp.vb.net' },
|
||||
{ name: 'xml', identifiers: ['xml', 'xsd', 'tld', 'jsp', 'pt', 'cpt', 'dtml', 'rss', 'opml'], source: 'text.xml' },
|
||||
{ name: 'xsl', identifiers: ['xsl', 'xslt'], source: 'text.xml.xsl' },
|
||||
{ name: 'yaml', identifiers: ['yaml', 'yml'], source: 'source.yaml' },
|
||||
{ name: 'dosbatch', identifiers: ['bat', 'batch'], source: 'source.dosbatch' },
|
||||
{ name: 'clojure', identifiers: ['clj', 'cljs', 'clojure'], source: 'source.clojure' },
|
||||
{ name: 'coffee', identifiers: ['coffee', 'Cakefile', 'coffee.erb'], source: 'source.coffee' },
|
||||
{ name: 'c', identifiers: ['c', 'h'], source: 'source.c' },
|
||||
{ name: 'cpp', identifiers: ['cpp', 'c\\+\\+', 'cxx'], source: 'source.cpp' },
|
||||
{ name: 'diff', identifiers: ['patch', 'diff', 'rej'], source: 'source.diff' },
|
||||
{ name: 'dockerfile', identifiers: ['dockerfile', 'Dockerfile'], source: 'source.dockerfile' },
|
||||
{ name: 'php', language: 'php', identifiers: ['php', 'php3', 'php4', 'php5', 'phpt', 'phtml', 'aw', 'ctp'], source: ['text.html.basic', 'text.html.php#language'] },
|
||||
{ name: 'sql', language: 'sql', identifiers: ['sql', 'ddl', 'dml'], source: 'source.sql' },
|
||||
{ name: 'vs_net', language: 'vs_net', identifiers: ['vb'], source: 'source.asp.vb.net' },
|
||||
{ name: 'xml', language: 'xml', identifiers: ['xml', 'xsd', 'tld', 'jsp', 'pt', 'cpt', 'dtml', 'rss', 'opml'], source: 'text.xml' },
|
||||
{ name: 'xsl', language: 'xsl', identifiers: ['xsl', 'xslt'], source: 'text.xml.xsl' },
|
||||
{ name: 'yaml', language: 'yaml', identifiers: ['yaml', 'yml'], source: 'source.yaml' },
|
||||
{ name: 'dosbatch', language: 'dosbatch', identifiers: ['bat', 'batch'], source: 'source.dosbatch' },
|
||||
{ name: 'clojure', language: 'clojure', identifiers: ['clj', 'cljs', 'clojure'], source: 'source.clojure' },
|
||||
{ name: 'coffee', language: 'coffee', identifiers: ['coffee', 'Cakefile', 'coffee.erb'], source: 'source.coffee' },
|
||||
{ name: 'c', language: 'c', identifiers: ['c', 'h'], source: 'source.c' },
|
||||
{ name: 'cpp', language: 'cpp', identifiers: ['cpp', 'c\\+\\+', 'cxx'], source: 'source.cpp' },
|
||||
{ name: 'diff', language: 'diff', identifiers: ['patch', 'diff', 'rej'], source: 'source.diff' },
|
||||
{ name: 'dockerfile', language: 'dockerfile', identifiers: ['dockerfile', 'Dockerfile'], source: 'source.dockerfile' },
|
||||
{ name: 'git_commit', identifiers: ['COMMIT_EDITMSG', 'MERGE_MSG'], source: 'text.git-commit' },
|
||||
{ name: 'git_rebase', identifiers: ['git-rebase-todo'], source: 'text.git-rebase' },
|
||||
{ name: 'go', identifiers: ['go', 'golang'], source: 'source.go' },
|
||||
{ name: 'groovy', identifiers: ['groovy', 'gvy'], source: 'source.groovy' },
|
||||
{ name: 'jade', identifiers: ['jade', 'pug'], source: 'text.jade' },
|
||||
{ name: 'go', language: 'go', identifiers: ['go', 'golang'], source: 'source.go' },
|
||||
{ name: 'groovy', language: 'groovy', identifiers: ['groovy', 'gvy'], source: 'source.groovy' },
|
||||
{ name: 'jade', language: 'jade', identifiers: ['jade', 'pug'], source: 'text.jade' },
|
||||
|
||||
{ name: 'js', identifiers: ['js', 'jsx', 'javascript', 'es6', 'mjs'], source: 'source.js' },
|
||||
{ name: 'js', language: 'javascript', identifiers: ['js', 'jsx', 'javascript', 'es6', 'mjs'], source: 'source.js' },
|
||||
{ name: 'js_regexp', identifiers: ['regexp'], source: 'source.js.regexp' },
|
||||
{ name: 'json', identifiers: ['json', 'sublime-settings', 'sublime-menu', 'sublime-keymap', 'sublime-mousemap', 'sublime-theme', 'sublime-build', 'sublime-project', 'sublime-completions'], source: 'source.json' },
|
||||
{ name: 'less', identifiers: ['less'], source: 'source.css.less' },
|
||||
{ name: 'objc', identifiers: ['objectivec', 'objective-c', 'mm', 'objc', 'obj-c', 'm', 'h'], source: 'source.objc' },
|
||||
{ name: 'scss', identifiers: ['scss'], source: 'source.css.scss' },
|
||||
{ name: 'json', language: 'json', identifiers: ['json', 'sublime-settings', 'sublime-menu', 'sublime-keymap', 'sublime-mousemap', 'sublime-theme', 'sublime-build', 'sublime-project', 'sublime-completions'], source: 'source.json' },
|
||||
{ name: 'less', language: 'less', identifiers: ['less'], source: 'source.css.less' },
|
||||
{ name: 'objc', language: 'objc', identifiers: ['objectivec', 'objective-c', 'mm', 'objc', 'obj-c', 'm', 'h'], source: 'source.objc' },
|
||||
{ name: 'scss', language: 'scss', identifiers: ['scss'], source: 'source.css.scss' },
|
||||
|
||||
{ name: 'perl6', identifiers: ['perl6', 'p6', 'pl6', 'pm6', 'nqp'], source: 'source.perl.6' },
|
||||
{ name: 'powershell', identifiers: ['powershell', 'ps1', 'psm1', 'psd1'], source: 'source.powershell' },
|
||||
{ name: 'python', identifiers: ['python', 'py', 'py3', 'rpy', 'pyw', 'cpy', 'SConstruct', 'Sconstruct', 'sconstruct', 'SConscript', 'gyp', 'gypi'], source: 'source.python' },
|
||||
{ name: 'perl6', language: 'perl6', identifiers: ['perl6', 'p6', 'pl6', 'pm6', 'nqp'], source: 'source.perl.6' },
|
||||
{ name: 'powershell', language: 'powershell', identifiers: ['powershell', 'ps1', 'psm1', 'psd1'], source: 'source.powershell' },
|
||||
{ name: 'python', language: 'python', identifiers: ['python', 'py', 'py3', 'rpy', 'pyw', 'cpy', 'SConstruct', 'Sconstruct', 'sconstruct', 'SConscript', 'gyp', 'gypi'], source: 'source.python' },
|
||||
{ name: 'regexp_python', identifiers: ['re'], source: 'source.regexp.python' },
|
||||
{ name: 'rust', identifiers: ['rust', 'rs'], source: 'source.rust' },
|
||||
{ name: 'scala', identifiers: ['scala', 'sbt'], source: 'source.scala' },
|
||||
{ name: 'shell', identifiers: ['shell', 'sh', 'bash', 'zsh', 'bashrc', 'bash_profile', 'bash_login', 'profile', 'bash_logout', '.textmate_init'], source: 'source.shell' },
|
||||
{ name: 'ts', identifiers: ['typescript', 'ts'], source: 'source.ts' },
|
||||
{ name: 'tsx', identifiers: ['tsx'], source: 'source.tsx' },
|
||||
{ name: 'csharp', identifiers: ['cs', 'csharp', 'c#'], source: 'source.cs' },
|
||||
{ name: 'fsharp', identifiers: ['fs', 'fsharp', 'f#'], source: 'source.fsharp' },
|
||||
{ name: 'rust', language: 'rust', identifiers: ['rust', 'rs'], source: 'source.rust' },
|
||||
{ name: 'scala', language: 'scala', identifiers: ['scala', 'sbt'], source: 'source.scala' },
|
||||
{ name: 'shell', language: 'shellscript', identifiers: ['shell', 'sh', 'bash', 'zsh', 'bashrc', 'bash_profile', 'bash_login', 'profile', 'bash_logout', '.textmate_init'], source: 'source.shell' },
|
||||
{ name: 'ts', language: 'typescript', identifiers: ['typescript', 'ts'], source: 'source.ts' },
|
||||
{ name: 'tsx', language: 'typescriptreact', identifiers: ['tsx'], source: 'source.tsx' },
|
||||
{ name: 'csharp', language: 'csharp', identifiers: ['cs', 'csharp', 'c#'], source: 'source.cs' },
|
||||
{ name: 'fsharp', language: 'fsharp', identifiers: ['fs', 'fsharp', 'f#'], source: 'source.fsharp' },
|
||||
];
|
||||
|
||||
const fencedCodeBlockDefinition = (name, identifiers, sourceScope) => {
|
||||
const fencedCodeBlockDefinition = (name, identifiers, sourceScope, language) => {
|
||||
if (!Array.isArray(sourceScope)) {
|
||||
sourceScope = [sourceScope];
|
||||
}
|
||||
|
||||
language = language || name
|
||||
|
||||
const scopes = sourceScope.map(scope =>
|
||||
`<dict>
|
||||
<key>include</key>
|
||||
@@ -106,6 +111,8 @@ const fencedCodeBlockDefinition = (name, identifiers, sourceScope) => {
|
||||
<string>(^|\\G)(\\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\\G)(?!\\s*([\`~]{3,})\\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.${language}</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
${indent(4, scopes)}
|
||||
@@ -129,7 +136,7 @@ const fencedCodeBlockInclude = (name) =>
|
||||
|
||||
const fencedCodeBlockDefinitions = () =>
|
||||
languages
|
||||
.map(language => fencedCodeBlockDefinition(language.name, language.identifiers, language.source))
|
||||
.map(language => fencedCodeBlockDefinition(language.name, language.identifiers, language.source, language.language))
|
||||
.join('\n');
|
||||
|
||||
|
||||
@@ -147,3 +154,11 @@ gulp.task('default', function () {
|
||||
.pipe(rename('markdown.tmLanguage'))
|
||||
.pipe(gulp.dest('.'));
|
||||
});
|
||||
|
||||
gulp.task('embedded', function () {
|
||||
const out = {}
|
||||
for (const lang of languages.filter(x => x.language)) {
|
||||
out['meta.embedded.block.' +lang.language] = lang.language;
|
||||
}
|
||||
util.log(JSON.stringify(out, undefined, 4));
|
||||
});
|
||||
|
||||
@@ -354,11 +354,11 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>while</key>
|
||||
<string>^\s*(?!</(script|style|pre)>)</string>
|
||||
<string>^(?!.*</(script|style|pre)>)</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>end</key>
|
||||
<string>(?=</(script|style|pre)>)</string>
|
||||
<string>(?=.*</(script|style|pre)>)</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
@@ -626,6 +626,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.css</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -677,6 +679,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.html</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -728,6 +732,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.ini</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -779,6 +785,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.java</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -830,6 +838,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.lua</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -881,6 +891,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.makefile</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -932,6 +944,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -983,6 +997,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.r</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1034,6 +1050,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.ruby</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1085,6 +1103,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.php</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1140,6 +1160,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.sql</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1191,6 +1213,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.vs_net</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1242,6 +1266,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.xml</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1293,6 +1319,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.xsl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1344,6 +1372,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.yaml</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1395,6 +1425,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.dosbatch</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1446,6 +1478,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.clojure</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1497,6 +1531,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.coffee</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1548,6 +1584,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.c</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1599,6 +1637,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.cpp</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1650,6 +1690,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.diff</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1701,6 +1743,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.dockerfile</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1752,6 +1796,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.git_commit</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1803,6 +1849,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.git_rebase</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1854,6 +1902,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.go</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1905,6 +1955,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.groovy</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -1956,6 +2008,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.jade</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2007,6 +2061,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.javascript</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2058,6 +2114,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.js_regexp</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2109,6 +2167,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.json</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2160,6 +2220,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.less</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2211,6 +2273,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.objc</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2262,6 +2326,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.scss</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2313,6 +2379,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.perl6</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2364,6 +2432,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.powershell</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2415,6 +2485,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.python</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2466,6 +2538,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.regexp_python</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2517,6 +2591,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.rust</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2568,6 +2644,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.scala</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2619,6 +2697,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.shellscript</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2670,6 +2750,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.typescript</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2721,6 +2803,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.typescriptreact</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2772,6 +2856,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.csharp</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -2823,6 +2909,8 @@
|
||||
<string>(^|\G)(\s*)(.*)</string>
|
||||
<key>while</key>
|
||||
<string>(^|\G)(?!\s*([`~]{3,})\s*$)</string>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.fsharp</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -3597,12 +3685,14 @@
|
||||
<key>match</key>
|
||||
<string>(`+)([^`]|(?!(?<!`)\1(?!`))`)*+(\1)</string>
|
||||
<key>name</key>
|
||||
<string>markup.inline.raw.markdown</string>
|
||||
<string>markup.inline.raw.string.markdown</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>frontMatter</key>
|
||||
<dict>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.frontmatter</string>
|
||||
<key>begin</key>
|
||||
<string>\A-{3}\s*$</string>
|
||||
<key>while</key>
|
||||
|
||||
@@ -179,11 +179,11 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>while</key>
|
||||
<string>^\s*(?!</(script|style|pre)>)</string>
|
||||
<string>^(?!.*</(script|style|pre)>)</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>end</key>
|
||||
<string>(?=</(script|style|pre)>)</string>
|
||||
<string>(?=.*</(script|style|pre)>)</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
@@ -1175,12 +1175,14 @@
|
||||
<key>match</key>
|
||||
<string>(`+)([^`]|(?!(?<!`)\1(?!`))`)*+(\1)</string>
|
||||
<key>name</key>
|
||||
<string>markup.inline.raw.markdown</string>
|
||||
<string>markup.inline.raw.string.markdown</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>frontMatter</key>
|
||||
<dict>
|
||||
<key>contentName</key>
|
||||
<string>meta.embedded.block.frontmatter</string>
|
||||
<key>begin</key>
|
||||
<string>\A-{3}\s*$</string>
|
||||
<key>while</key>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# h
|
||||
|
||||
<pre><code>
|
||||
# a
|
||||
</code></pre>
|
||||
|
||||
# h
|
||||
|
||||
<pre>
|
||||
# a
|
||||
a</pre>
|
||||
|
||||
# h
|
||||
@@ -0,0 +1,332 @@
|
||||
[
|
||||
{
|
||||
"c": "#",
|
||||
"t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown markup.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "h",
|
||||
"t": "text.html.markdown markup.heading.markdown entity.name.section.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "<",
|
||||
"t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "pre",
|
||||
"t": "text.html.markdown meta.tag.block.any.html entity.name.tag.block.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "<",
|
||||
"t": "text.html.markdown meta.tag.inline.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "code",
|
||||
"t": "text.html.markdown meta.tag.inline.any.html entity.name.tag.inline.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.tag.inline.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "# a",
|
||||
"t": "text.html.markdown",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "</",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "code",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.any.html entity.name.tag.inline.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "</",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "pre",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html entity.name.tag.block.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown markup.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "h",
|
||||
"t": "text.html.markdown markup.heading.markdown entity.name.section.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "<",
|
||||
"t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "pre",
|
||||
"t": "text.html.markdown meta.tag.block.any.html entity.name.tag.block.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.tag.block.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "# a",
|
||||
"t": "text.html.markdown",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "a",
|
||||
"t": "text.html.markdown meta.paragraph.markdown",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "</",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.begin.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "pre",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html entity.name.tag.block.any.html",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.tag: #569CD6",
|
||||
"light_plus": "entity.name.tag: #800000",
|
||||
"dark_vs": "entity.name.tag: #569CD6",
|
||||
"light_vs": "entity.name.tag: #800000",
|
||||
"hc_black": "entity.name.tag: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ">",
|
||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.block.any.html punctuation.definition.tag.end.html",
|
||||
"r": {
|
||||
"dark_plus": "punctuation.definition.tag: #808080",
|
||||
"light_plus": "punctuation.definition.tag: #800000",
|
||||
"dark_vs": "punctuation.definition.tag: #808080",
|
||||
"light_vs": "punctuation.definition.tag: #800000",
|
||||
"hc_black": "punctuation.definition.tag: #808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "text.html.markdown markup.heading.markdown punctuation.definition.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown markup.heading.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "h",
|
||||
"t": "text.html.markdown markup.heading.markdown entity.name.section.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.heading: #569CD6",
|
||||
"light_plus": "markup.heading: #800000",
|
||||
"dark_vs": "markup.heading: #569CD6",
|
||||
"light_vs": "markup.heading: #800000",
|
||||
"hc_black": "markup.heading: #6796E6"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -652,11 +652,11 @@
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html meta.tag.metadata.script.html",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -674,11 +674,11 @@
|
||||
"c": "=",
|
||||
"t": "text.html.markdown meta.embedded.block.html meta.tag.metadata.script.html",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -729,22 +729,22 @@
|
||||
"c": " function( x: int ) { return x*x; }",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.unknown",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.unknown",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1026,11 +1026,11 @@
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1048,33 +1048,33 @@
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "{",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1092,22 +1092,22 @@
|
||||
"c": ":",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.separator.key-value.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1147,33 +1147,33 @@
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css meta.property-list.css punctuation.section.property-list.end.bracket.curly.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "text.html.markdown meta.embedded.block.html source.css",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
"dark_plus": "meta.embedded: #D4D4D4",
|
||||
"light_plus": "meta.embedded: #000000",
|
||||
"dark_vs": "meta.embedded: #D4D4D4",
|
||||
"light_vs": "meta.embedded: #000000",
|
||||
"hc_black": "meta.embedded: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1541,7 +1541,7 @@
|
||||
},
|
||||
{
|
||||
"c": "`",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown punctuation.definition.raw.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.inline.raw: #CE9178",
|
||||
"light_plus": "markup.inline.raw: #800000",
|
||||
@@ -1552,7 +1552,7 @@
|
||||
},
|
||||
{
|
||||
"c": "code()",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.inline.raw: #CE9178",
|
||||
"light_plus": "markup.inline.raw: #800000",
|
||||
@@ -1563,7 +1563,7 @@
|
||||
},
|
||||
{
|
||||
"c": "`",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.markdown punctuation.definition.raw.markdown",
|
||||
"t": "text.html.markdown meta.paragraph.markdown markup.inline.raw.string.markdown punctuation.definition.raw.markdown",
|
||||
"r": {
|
||||
"dark_plus": "markup.inline.raw: #CE9178",
|
||||
"light_plus": "markup.inline.raw: #800000",
|
||||
|
||||
@@ -88,6 +88,6 @@
|
||||
"vscode-nls": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.4"
|
||||
"@types/node": "8.0.33"
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@
|
||||
{
|
||||
"name": "balanced-match",
|
||||
"repositoryURL": "https://github.com/juliangruber/balanced-match",
|
||||
"version": "0.4.2",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "brace-expansion",
|
||||
"repositoryURL": "https://github.com/juliangruber/brace-expansion",
|
||||
"version": "1.1.6",
|
||||
"version": "1.1.8",
|
||||
"license": "MIT",
|
||||
"isProd": true
|
||||
},
|
||||
@@ -31,14 +31,14 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"repositoryURL": "https://github.com/visionmedia/debug",
|
||||
"version": "2.3.3",
|
||||
"version": "2.6.8",
|
||||
"license": "MIT",
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "extend",
|
||||
"repositoryURL": "https://github.com/justmoon/node-extend",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"license": "MIT",
|
||||
"isProd": true
|
||||
},
|
||||
@@ -52,7 +52,7 @@
|
||||
{
|
||||
"name": "glob",
|
||||
"repositoryURL": "https://github.com/isaacs/node-glob",
|
||||
"version": "7.1.1",
|
||||
"version": "7.1.2",
|
||||
"license": "ISC",
|
||||
"isProd": true
|
||||
},
|
||||
@@ -87,14 +87,14 @@
|
||||
{
|
||||
"name": "minimatch",
|
||||
"repositoryURL": "https://github.com/isaacs/minimatch",
|
||||
"version": "3.0.3",
|
||||
"version": "3.0.4",
|
||||
"license": "ISC",
|
||||
"isProd": true
|
||||
},
|
||||
{
|
||||
"name": "ms",
|
||||
"repositoryURL": "https://github.com/rauchg/ms.js",
|
||||
"version": "0.7.2",
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
"isProd": true
|
||||
},
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as adal from 'adal-node';
|
||||
import * as data from 'data';
|
||||
import * as request from 'request';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as vscode from 'vscode';
|
||||
import * as url from 'url';
|
||||
import {
|
||||
Arguments,
|
||||
AzureAccount,
|
||||
AzureAccountProviderMetadata,
|
||||
AzureAccountSecurityTokenCollection,
|
||||
Tenant
|
||||
} from './interfaces';
|
||||
import TokenCache from './tokenCache';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzureAccountProvider implements data.AccountProvider {
|
||||
// CONSTANTS ///////////////////////////////////////////////////////////
|
||||
private static WorkSchoolAccountType: string = 'work_school';
|
||||
private static MicrosoftAccountType: string = 'microsoft';
|
||||
private static AadCommonTenant: string = 'common';
|
||||
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||
private _args: Arguments;
|
||||
private _autoOAuthCancelled: boolean;
|
||||
private _commonAuthorityUrl: string;
|
||||
private _inProgressAutoOAuth: InProgressAutoOAuth;
|
||||
private _isInitialized: boolean;
|
||||
|
||||
constructor(private _metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) {
|
||||
this._args = {
|
||||
host: this._metadata.settings.host,
|
||||
clientId: this._metadata.settings.clientId
|
||||
};
|
||||
this._autoOAuthCancelled = false;
|
||||
this._inProgressAutoOAuth = null;
|
||||
this._isInitialized = false;
|
||||
|
||||
this._commonAuthorityUrl = url.resolve(this._metadata.settings.host, AzureAccountProvider.AadCommonTenant);
|
||||
}
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public autoOAuthCancelled(): Thenable<void> {
|
||||
return this.doIfInitialized(() => this.cancelAutoOAuth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all tokens that belong to the given account from the token cache
|
||||
* @param {"data".AccountKey} accountKey Key identifying the account to delete tokens for
|
||||
* @returns {Thenable<void>} Promise to clear requested tokens from the token cache
|
||||
*/
|
||||
public clear(accountKey: data.AccountKey): Thenable<void> {
|
||||
return this.doIfInitialized(() => this.clearAccountTokens(accountKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the entire token cache. Invoked by command palette action.
|
||||
* @returns {Thenable<void>} Promise to clear the token cache
|
||||
*/
|
||||
public clearTokenCache(): Thenable<void> {
|
||||
return this._tokenCache.clear();
|
||||
}
|
||||
|
||||
public getSecurityToken(account: AzureAccount): Thenable<AzureAccountSecurityTokenCollection> {
|
||||
return this.doIfInitialized(() => this.getAccessTokens(account));
|
||||
}
|
||||
|
||||
public initialize(restoredAccounts: data.Account[]): Thenable<data.Account[]> {
|
||||
let self = this;
|
||||
|
||||
let rehydrationTasks: Thenable<data.Account>[] = [];
|
||||
for (let account of restoredAccounts) {
|
||||
// Purge any invalid accounts
|
||||
if (!account) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Refresh the contextual logo based on whether the account is a MS account
|
||||
account.displayInfo.accountType = account.properties.isMsAccount
|
||||
? AzureAccountProvider.MicrosoftAccountType
|
||||
: AzureAccountProvider.WorkSchoolAccountType;
|
||||
|
||||
// Attempt to get fresh tokens. If this fails then the account is stale.
|
||||
// NOTE: Based on ADAL implementation, getting tokens should use the refresh token if necessary
|
||||
let task = this.getAccessTokens(account)
|
||||
.then(
|
||||
() => {
|
||||
return account;
|
||||
},
|
||||
() => {
|
||||
account.isStale = true;
|
||||
return account;
|
||||
}
|
||||
);
|
||||
rehydrationTasks.push(task);
|
||||
}
|
||||
|
||||
// Collect the rehydration tasks and mark the provider as initialized
|
||||
return Promise.all(rehydrationTasks)
|
||||
.then(accounts => {
|
||||
self._isInitialized = true;
|
||||
return accounts;
|
||||
});
|
||||
}
|
||||
|
||||
public prompt(): Thenable<AzureAccount> {
|
||||
return this.doIfInitialized(() => this.signIn(true));
|
||||
}
|
||||
|
||||
public refresh(account: AzureAccount): Thenable<AzureAccount> {
|
||||
return this.doIfInitialized(() => this.signIn(false));
|
||||
}
|
||||
|
||||
// PRIVATE METHODS /////////////////////////////////////////////////////
|
||||
private cancelAutoOAuth(): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
if (!this._inProgressAutoOAuth) {
|
||||
console.warn('Attempted to cancel auto OAuth when auto OAuth is not in progress!');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Indicate oauth was cancelled by the user
|
||||
let inProgress = self._inProgressAutoOAuth;
|
||||
self._autoOAuthCancelled = true;
|
||||
self._inProgressAutoOAuth = null;
|
||||
|
||||
// Use the auth context that was originally used to open the polling request, and cancel the polling
|
||||
let context = inProgress.context;
|
||||
context.cancelRequestToGetTokenWithDeviceCode(inProgress.userCodeInfo, err => {
|
||||
// Callback is only called in failure scenarios.
|
||||
if (err) {
|
||||
console.warn(`Error while cancelling auto OAuth: ${err}`);
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private clearAccountTokens(accountKey: data.AccountKey): Thenable<void> {
|
||||
// Put together a query to look up any tokens associated with the account key
|
||||
let query = <adal.TokenResponse>{ userId: accountKey.accountId };
|
||||
|
||||
// 1) Look up the tokens associated with the query
|
||||
// 2) Remove them
|
||||
return this._tokenCache.findThenable(query)
|
||||
.then(results => this._tokenCache.removeThenable(results));
|
||||
}
|
||||
|
||||
private doIfInitialized<T>(op: () => Thenable<T>): Thenable<T> {
|
||||
return this._isInitialized
|
||||
? op()
|
||||
: Promise.reject(localize('accountProviderNotInitialized', 'Account provider not initialized, cannot perform action'));
|
||||
}
|
||||
|
||||
private getAccessTokens(account: AzureAccount): Thenable<AzureAccountSecurityTokenCollection> {
|
||||
let self = this;
|
||||
|
||||
let accessTokenPromises: Thenable<void>[] = [];
|
||||
let tokenCollection: AzureAccountSecurityTokenCollection = {};
|
||||
for (let tenant of account.properties.tenants) {
|
||||
let promise = new Promise<void>((resolve, reject) => {
|
||||
let authorityUrl = url.resolve(self._metadata.settings.host, tenant.id);
|
||||
let context = new adal.AuthenticationContext(authorityUrl, null, self._tokenCache);
|
||||
|
||||
context.acquireToken(
|
||||
self._metadata.settings.armResource.id,
|
||||
tenant.userId,
|
||||
self._metadata.settings.clientId,
|
||||
(error: Error, response: adal.TokenResponse | adal.ErrorResponse) => {
|
||||
// Handle errors first
|
||||
if (error) {
|
||||
// TODO: We'll assume for now that the account is stale, though that might not be accurate
|
||||
account.isStale = true;
|
||||
data.accounts.accountUpdated(account);
|
||||
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// We know that the response was not an error
|
||||
let tokenResponse = <adal.TokenResponse>response;
|
||||
|
||||
// Generate a token object and add it to the collection
|
||||
tokenCollection[tenant.id] = {
|
||||
expiresOn: tokenResponse.expiresOn,
|
||||
resource: tokenResponse.resource,
|
||||
token: tokenResponse.accessToken,
|
||||
tokenType: tokenResponse.tokenType
|
||||
};
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
accessTokenPromises.push(promise);
|
||||
}
|
||||
|
||||
// Wait until all the tokens have been acquired then return the collection
|
||||
return Promise.all(accessTokenPromises)
|
||||
.then(() => tokenCollection);
|
||||
}
|
||||
|
||||
private getDeviceLoginUserCode(): Thenable<InProgressAutoOAuth> {
|
||||
let self = this;
|
||||
|
||||
// Create authentication context and acquire user code
|
||||
return new Promise<InProgressAutoOAuth>((resolve, reject) => {
|
||||
let context = new adal.AuthenticationContext(self._commonAuthorityUrl, null, self._tokenCache);
|
||||
context.acquireUserCode(self._metadata.settings.signInResourceId, self._metadata.settings.clientId, vscode.env.language,
|
||||
(err, response) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
let result: InProgressAutoOAuth = {
|
||||
context: context,
|
||||
userCodeInfo: response
|
||||
};
|
||||
|
||||
resolve(result);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private getDeviceLoginToken(oAuth: InProgressAutoOAuth, isAddAccount: boolean): Thenable<adal.TokenResponse> {
|
||||
let self = this;
|
||||
|
||||
// 1) Open the auto OAuth dialog
|
||||
// 2) Begin the acquiring token polling
|
||||
// 3) When that completes via callback, close the auto oauth
|
||||
let title = isAddAccount ?
|
||||
localize('addAccount', 'Add {0} account', self._metadata.displayName) :
|
||||
localize('refreshAccount', 'Refresh {0} account', self._metadata.displayName);
|
||||
return data.accounts.beginAutoOAuthDeviceCode(self._metadata.id, title, oAuth.userCodeInfo.message, oAuth.userCodeInfo.userCode, oAuth.userCodeInfo.verificationUrl)
|
||||
.then(() => {
|
||||
return new Promise<adal.TokenResponse>((resolve, reject) => {
|
||||
let context = oAuth.context;
|
||||
context.acquireTokenWithDeviceCode(self._metadata.settings.signInResourceId, self._metadata.settings.clientId, oAuth.userCodeInfo,
|
||||
(err, response) => {
|
||||
if (err) {
|
||||
if (self._autoOAuthCancelled) {
|
||||
// Auto OAuth was cancelled by the user, indicate this with the error we return
|
||||
reject(<data.UserCancelledSignInError>{ userCancelledSignIn: true });
|
||||
} else {
|
||||
// Auto OAuth failed for some other reason
|
||||
data.accounts.endAutoOAuthDeviceCode();
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
data.accounts.endAutoOAuthDeviceCode();
|
||||
resolve(<adal.TokenResponse>response);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getTenants(userId: string, homeTenant: string): Thenable<Tenant[]> {
|
||||
let self = this;
|
||||
|
||||
// 1) Get a token we can use for looking up the tenant IDs
|
||||
// 2) Send a request to the ARM endpoint (the root management API) to get the list of tenant IDs
|
||||
// 3) For all the tenants
|
||||
// b) Get a token we can use for the AAD Graph API
|
||||
// a) Get the display name of the tenant
|
||||
// c) create a tenant object
|
||||
// 4) Sort to make sure the "home tenant" is the first tenant on the list
|
||||
return this.getToken(userId, AzureAccountProvider.AadCommonTenant, this._metadata.settings.armResource.id)
|
||||
.then((armToken: adal.TokenResponse) => {
|
||||
let tenantUri = url.resolve(self._metadata.settings.armResource.endpoint, 'tenants?api-version=2015-01-01');
|
||||
return self.makeWebRequest(armToken, tenantUri);
|
||||
})
|
||||
.then((tenantResponse: any[]) => {
|
||||
let promises: Thenable<Tenant>[] = tenantResponse.map(value => {
|
||||
return self.getToken(userId, value.tenantId, self._metadata.settings.graphResource.id)
|
||||
.then((graphToken: adal.TokenResponse) => {
|
||||
let tenantDetailsUri = url.resolve(self._metadata.settings.graphResource.endpoint, value.tenantId + '/');
|
||||
tenantDetailsUri = url.resolve(tenantDetailsUri, 'tenantDetails?api-version=2013-04-05');
|
||||
return self.makeWebRequest(graphToken, tenantDetailsUri);
|
||||
})
|
||||
.then((tenantDetails: any) => {
|
||||
return <Tenant>{
|
||||
id: value.tenantId,
|
||||
userId: userId,
|
||||
displayName: tenantDetails.length && tenantDetails[0].displayName
|
||||
? tenantDetails[0].displayName
|
||||
: localize('azureWorkAccountDisplayName', 'Work or school account')
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then((tenants: Tenant[]) => {
|
||||
let homeTenantIndex = tenants.findIndex(tenant => tenant.id === homeTenant);
|
||||
if (homeTenantIndex >= 0) {
|
||||
let homeTenant = tenants.splice(homeTenantIndex, 1);
|
||||
tenants.unshift(homeTenant[0]);
|
||||
}
|
||||
return tenants;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a token for the given user ID for the specific tenant ID. If the token can, it
|
||||
* will be retrieved from the cache as per the ADAL API. AFAIK, the ADAL API will also utilize
|
||||
* the refresh token if there aren't any unexpired tokens to use.
|
||||
* @param {string} userId ID of the user to get a token for
|
||||
* @param {string} tenantId Tenant to get the token for
|
||||
* @param {string} resourceId ID of the resource the token will be good for
|
||||
* @returns {Thenable<TokenResponse>} Promise to return a token. Rejected if retrieving the token fails.
|
||||
*/
|
||||
private getToken(userId: string, tenantId: string, resourceId: string): Thenable<adal.TokenResponse> {
|
||||
let self = this;
|
||||
|
||||
return new Promise<adal.TokenResponse>((resolve, reject) => {
|
||||
let authorityUrl = url.resolve(self._metadata.settings.host, tenantId);
|
||||
let context = new adal.AuthenticationContext(authorityUrl, null, self._tokenCache);
|
||||
context.acquireToken(resourceId, userId, self._metadata.settings.clientId,
|
||||
(error: Error, response: adal.TokenResponse | adal.ErrorResponse) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(<adal.TokenResponse>response);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a web request using the provided bearer token
|
||||
* @param {TokenResponse} accessToken Bearer token for accessing the provided URI
|
||||
* @param {string} uri URI to access
|
||||
* @returns {Thenable<any>} Promise to return the deserialized body of the request. Rejected if error occurred.
|
||||
*/
|
||||
private makeWebRequest(accessToken: adal.TokenResponse, uri: string): Thenable<any> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
// Setup parameters for the request
|
||||
// NOTE: setting json true means the returned object will be deserialized
|
||||
let params = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken.accessToken}`
|
||||
},
|
||||
json: true
|
||||
};
|
||||
|
||||
// Setup the callback to resolve/reject this promise
|
||||
let callback = (error, response, body: { error: any; value: any; }) => {
|
||||
if (error || body.error) {
|
||||
reject(error || JSON.stringify(body.error));
|
||||
} else {
|
||||
resolve(body.value);
|
||||
}
|
||||
};
|
||||
|
||||
// Make the request
|
||||
request.get(uri, params, callback);
|
||||
});
|
||||
}
|
||||
|
||||
private signIn(isAddAccount: boolean): Thenable<AzureAccount> {
|
||||
let self = this;
|
||||
|
||||
// 1) Get the user code for this login
|
||||
// 2) Get an access token from the device code
|
||||
// 3) Get the list of tenants
|
||||
// 4) Generate the AzureAccount object and return it
|
||||
let tokenResponse: adal.TokenResponse = null;
|
||||
return this.getDeviceLoginUserCode()
|
||||
.then((result: InProgressAutoOAuth) => {
|
||||
self._autoOAuthCancelled = false;
|
||||
self._inProgressAutoOAuth = result;
|
||||
return self.getDeviceLoginToken(self._inProgressAutoOAuth, isAddAccount);
|
||||
})
|
||||
.then((response: adal.TokenResponse) => {
|
||||
tokenResponse = response;
|
||||
self._autoOAuthCancelled = false;
|
||||
self._inProgressAutoOAuth = null;
|
||||
return self.getTenants(tokenResponse.userId, tokenResponse.userId);
|
||||
})
|
||||
.then((tenants: Tenant[]) => {
|
||||
// Figure out where we're getting the identity from
|
||||
let identityProvider = tokenResponse.identityProvider;
|
||||
if (identityProvider) {
|
||||
identityProvider = identityProvider.toLowerCase();
|
||||
}
|
||||
|
||||
// Determine if this is a microsoft account
|
||||
let msa = identityProvider && (
|
||||
identityProvider.indexOf('live.com') !== -1 ||
|
||||
identityProvider.indexOf('live-int.com') !== -1 ||
|
||||
identityProvider.indexOf('f8cdef31-a31e-4b4a-93e4-5f571e91255a') !== -1 ||
|
||||
identityProvider.indexOf('ea8a4392-515e-481f-879e-6571ff2a8a36') !== -1);
|
||||
|
||||
// Calculate the display name for the user
|
||||
let displayName = (tokenResponse.givenName && tokenResponse.familyName)
|
||||
? `${tokenResponse.givenName} ${tokenResponse.familyName}`
|
||||
: tokenResponse.userId;
|
||||
|
||||
// Calculate the home tenant display name to use for the contextual display name
|
||||
let contextualDisplayName = msa
|
||||
? localize('microsoftAccountDisplayName', 'Microsoft Account')
|
||||
: tenants[0].displayName;
|
||||
|
||||
// Calculate the account type
|
||||
let accountType = msa
|
||||
? AzureAccountProvider.MicrosoftAccountType
|
||||
: AzureAccountProvider.WorkSchoolAccountType;
|
||||
|
||||
return <AzureAccount>{
|
||||
key: {
|
||||
providerId: self._metadata.id,
|
||||
accountId: tokenResponse.userId
|
||||
},
|
||||
name: tokenResponse.userId,
|
||||
displayInfo: {
|
||||
accountType: accountType,
|
||||
contextualDisplayName: contextualDisplayName,
|
||||
displayName: displayName
|
||||
},
|
||||
properties: {
|
||||
isMsAccount: msa,
|
||||
tenants: tenants
|
||||
},
|
||||
isStale: false
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface InProgressAutoOAuth {
|
||||
context: adal.AuthenticationContext;
|
||||
userCodeInfo: adal.UserCodeInfo;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as data from 'data';
|
||||
import * as events from 'events';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import CredentialServiceTokenCache from './tokenCache';
|
||||
import providerSettings from './providerSettings';
|
||||
import { AzureAccountProvider } from './azureAccountProvider';
|
||||
import { AzureAccountProviderMetadata, ProviderSettings } from './interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzureAccountProviderService implements vscode.Disposable {
|
||||
// CONSTANTS ///////////////////////////////////////////////////////////////
|
||||
private static CommandClearTokenCache = 'extension.clearTokenCache';
|
||||
private static ConfigurationSection = 'accounts.azure';
|
||||
private static CredentialNamespace = 'azureAccountProviderCredentials';
|
||||
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////////
|
||||
private _accountDisposals: { [accountProviderId: string]: vscode.Disposable };
|
||||
private _accountProviders: { [accountProviderId: string]: AzureAccountProvider };
|
||||
private _credentialProvider: data.CredentialProvider;
|
||||
private _configChangePromiseChain: Thenable<void>;
|
||||
private _currentConfig: vscode.WorkspaceConfiguration;
|
||||
private _event: events.EventEmitter;
|
||||
|
||||
constructor(private _context: vscode.ExtensionContext, private _userStoragePath: string) {
|
||||
this._accountDisposals = {};
|
||||
this._accountProviders = {};
|
||||
this._configChangePromiseChain = Promise.resolve();
|
||||
this._currentConfig = null;
|
||||
this._event = new events.EventEmitter();
|
||||
}
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public activate(): Thenable<boolean> {
|
||||
let self = this;
|
||||
|
||||
// Register commands
|
||||
this._context.subscriptions.push(vscode.commands.registerCommand(
|
||||
AzureAccountProviderService.CommandClearTokenCache,
|
||||
() => { self._event.emit(AzureAccountProviderService.CommandClearTokenCache); }
|
||||
));
|
||||
this._event.on(AzureAccountProviderService.CommandClearTokenCache, () => { self.onClearTokenCache(); });
|
||||
|
||||
// 1) Get a credential provider
|
||||
// 2a) Store the credential provider for use later
|
||||
// 2b) Register the configuration change handler
|
||||
// 2c) Perform an initial config change handling
|
||||
return data.credentials.getProvider(AzureAccountProviderService.CredentialNamespace)
|
||||
.then(credProvider => {
|
||||
self._credentialProvider = credProvider;
|
||||
|
||||
self._context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(self.onDidChangeConfiguration, self));
|
||||
self.onDidChangeConfiguration();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public dispose() { }
|
||||
|
||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||
private onClearTokenCache(): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
let promises: Thenable<void>[] = providerSettings.map(provider => {
|
||||
return self._accountProviders[provider.metadata.id].clearTokenCache();
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
let message = localize('clearTokenCacheSuccess', 'Token cache successfully cleared');
|
||||
vscode.window.showInformationMessage(`mssql: ${message}`);
|
||||
},
|
||||
err => {
|
||||
let message = localize('clearTokenCacheFailure', 'Failed to clear token cache');
|
||||
vscode.window.showErrorMessage(`mssql: ${message}: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
private onDidChangeConfiguration(): void {
|
||||
let self = this;
|
||||
|
||||
// Add a new change processing onto the existing promise change
|
||||
this._configChangePromiseChain = this._configChangePromiseChain.then(() => {
|
||||
// Grab the stored config and the latest config
|
||||
let newConfig = vscode.workspace.getConfiguration(AzureAccountProviderService.ConfigurationSection);
|
||||
let oldConfig = self._currentConfig;
|
||||
self._currentConfig = newConfig;
|
||||
|
||||
// Determine what providers need to be changed
|
||||
let providerChanges: Thenable<void>[] = [];
|
||||
for(let provider of providerSettings) {
|
||||
// If the old config doesn't exist, then assume everything was disabled
|
||||
// There will always be a new config value
|
||||
let oldConfigValue = oldConfig
|
||||
? oldConfig.get<boolean>(provider.configKey)
|
||||
: false;
|
||||
let newConfigValue = newConfig.get<boolean>(provider.configKey);
|
||||
|
||||
// Case 1: Provider config has not changed - do nothing
|
||||
if (oldConfigValue === newConfigValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Case 2: Provider was enabled and is now disabled - unregister provider
|
||||
if (oldConfigValue && !newConfigValue) {
|
||||
providerChanges.push(self.unregisterAccountProvider(provider));
|
||||
}
|
||||
|
||||
// Case 3: Provider was disabled and is now enabled - register provider
|
||||
if (!oldConfigValue && newConfigValue) {
|
||||
providerChanges.push(self.registerAccountProvider(provider));
|
||||
}
|
||||
}
|
||||
|
||||
// Process all the changes before continuing
|
||||
return Promise.all(providerChanges);
|
||||
}).then(null, () => { return Promise.resolve(); });
|
||||
}
|
||||
|
||||
private registerAccountProvider(provider: ProviderSettings): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let tokenCacheKey = `azureTokenCache-${provider.metadata.id}`;
|
||||
let tokenCachePath = path.join(this._userStoragePath, tokenCacheKey);
|
||||
let tokenCache = new CredentialServiceTokenCache(self._credentialProvider, tokenCacheKey, tokenCachePath);
|
||||
let accountProvider = new AzureAccountProvider(<AzureAccountProviderMetadata>provider.metadata, tokenCache);
|
||||
self._accountProviders[provider.metadata.id] = accountProvider;
|
||||
self._accountDisposals[provider.metadata.id] = data.accounts.registerAccountProvider(provider.metadata, accountProvider);
|
||||
resolve();
|
||||
} catch(e) {
|
||||
console.error(`Failed to register account provider: ${e}`);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private unregisterAccountProvider(provider: ProviderSettings): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
self._accountDisposals[provider.metadata.id].dispose();
|
||||
delete self._accountProviders[provider.metadata.id];
|
||||
delete self._accountDisposals[provider.metadata.id];
|
||||
resolve();
|
||||
} catch(e) {
|
||||
console.error(`Failed to unregister account provider: ${e}`);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
'use strict';
|
||||
|
||||
import * as data from 'data';
|
||||
|
||||
/**
|
||||
* Represents a tenant (an Azure Active Directory instance) to which a user has access
|
||||
*/
|
||||
export interface Tenant {
|
||||
/**
|
||||
* Globally unique identifier of the tenant
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Display name of the tenant
|
||||
*/
|
||||
displayName: string;
|
||||
|
||||
/**
|
||||
* Identifier of the user in the tenant
|
||||
*/
|
||||
userId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a resource exposed by an Azure Active Directory
|
||||
*/
|
||||
export interface Resource {
|
||||
/**
|
||||
* Identifier of the resource
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Endpoint url used to access the resource
|
||||
*/
|
||||
endpoint: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the arguments that identify an instantiation of the AAD account provider
|
||||
*/
|
||||
export interface Arguments {
|
||||
/**
|
||||
* Host of the authority
|
||||
*/
|
||||
host: string;
|
||||
|
||||
/**
|
||||
* Identifier of the client application
|
||||
*/
|
||||
clientId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents settings for an AAD account provider
|
||||
*/
|
||||
export interface Settings {
|
||||
/**
|
||||
* Host of the authority
|
||||
*/
|
||||
host?: string;
|
||||
|
||||
/**
|
||||
* Identifier of the client application
|
||||
*/
|
||||
clientId?: string;
|
||||
|
||||
/**
|
||||
* Identifier of the resource to request when signing in
|
||||
*/
|
||||
signInResourceId?: string;
|
||||
|
||||
/**
|
||||
* Information that describes the AAD graph resource
|
||||
*/
|
||||
graphResource?: Resource;
|
||||
|
||||
/**
|
||||
* Information that describes the Azure resource management resource
|
||||
*/
|
||||
armResource?: Resource;
|
||||
|
||||
/**
|
||||
* A list of tenant IDs to authenticate against. If defined, then these IDs will be used
|
||||
* instead of querying the tenants endpoint of the armResource
|
||||
*/
|
||||
adTenants?: string[];
|
||||
|
||||
// AuthorizationCodeGrantFlowSettings //////////////////////////////////
|
||||
|
||||
/**
|
||||
* An optional site ID that brands the interactive aspect of sign in
|
||||
*/
|
||||
siteId?: string;
|
||||
|
||||
/**
|
||||
* Redirect URI that is used to signify the end of the interactive aspect of sign it
|
||||
*/
|
||||
redirectUri?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of configuration key with the metadata to instantiate the account provider
|
||||
*/
|
||||
export interface ProviderSettings {
|
||||
/**
|
||||
* Key for configuration regarding whether the account provider is enabled
|
||||
*/
|
||||
configKey: string;
|
||||
|
||||
/**
|
||||
* Metadata for the provider
|
||||
*/
|
||||
metadata: AzureAccountProviderMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of account provider metadata to override settings type for Azure account providers
|
||||
*/
|
||||
export interface AzureAccountProviderMetadata extends data.AccountProviderMetadata {
|
||||
/**
|
||||
* Azure specific account provider settings.
|
||||
*/
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties specific to an Azure account
|
||||
*/
|
||||
export interface AzureAccountProperties {
|
||||
/**
|
||||
* Whether or not the account is a Microsoft account
|
||||
*/
|
||||
isMsAccount: boolean;
|
||||
|
||||
/**
|
||||
* A list of tenants (aka directories) that the account belongs to
|
||||
*/
|
||||
tenants: Tenant[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Override of the Account type to enforce properties that are AzureAccountProperties
|
||||
*/
|
||||
export interface AzureAccount extends data.Account {
|
||||
/**
|
||||
* AzureAccountProperties specifically used for Azure accounts
|
||||
*/
|
||||
properties: AzureAccountProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token returned from a request for an access token
|
||||
*/
|
||||
export interface AzureAccountSecurityToken {
|
||||
/**
|
||||
* Access token, itself
|
||||
*/
|
||||
token: string;
|
||||
|
||||
/**
|
||||
* Date that the token expires on
|
||||
*/
|
||||
expiresOn: Date | string;
|
||||
|
||||
/**
|
||||
* Name of the resource the token is good for (ie, management.core.windows.net)
|
||||
*/
|
||||
resource: string;
|
||||
|
||||
/**
|
||||
* Type of the token (pretty much always 'Bearer')
|
||||
*/
|
||||
tokenType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure account security token maps a tenant ID to the information returned from a request to get
|
||||
* an access token. The list of tenants correspond to the tenants in the account properties.
|
||||
*/
|
||||
export type AzureAccountSecurityTokenCollection = {[tenantId: string]: AzureAccountSecurityToken};
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><defs><style>.cls-1{fill:#fff;}</style></defs><title>microsoft_logo-white</title><rect class="cls-1" x="0.06" y="0.06" width="5.65" height="5.65"/><rect class="cls-1" x="6.29" y="0.06" width="5.65" height="5.65"/><rect class="cls-1" x="0.06" y="6.3" width="5.65" height="5.65"/><rect class="cls-1" x="6.29" y="6.3" width="5.65" height="5.65"/></svg>
|
||||
|
After Width: | Height: | Size: 442 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#231f20;}</style></defs><title>microsoft_account_Blk</title><rect class="cls-1" width="7.6" height="7.6"/><rect class="cls-1" x="8.4" width="7.6" height="7.6"/><rect class="cls-1" y="8.4" width="7.6" height="7.6"/><rect class="cls-1" x="8.4" y="8.4" width="7.6" height="7.6"/></svg>
|
||||
|
After Width: | Height: | Size: 400 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>other_account_inverse_16x16</title><path class="cls-1" d="M7.92.29A7.71,7.71,0,1,0,15.64,8,7.73,7.73,0,0,0,7.92.29ZM4.12,13.54a4,4,0,0,1,.13-.93,3.69,3.69,0,0,1,1-1.66A3.56,3.56,0,0,1,6,10.37a4,4,0,0,1,.9-.38,4.17,4.17,0,0,1,1-.13,3.79,3.79,0,0,1,1.48.29,3.61,3.61,0,0,1,2,2,3.74,3.74,0,0,1,.29,1.47,6.62,6.62,0,0,1-3.7,1.12A6.71,6.71,0,0,1,4.12,13.54Zm2-5a2.76,2.76,0,0,1-.54-.79,2.43,2.43,0,0,1-.19-1,2.4,2.4,0,0,1,.19-1A2.82,2.82,0,0,1,6.1,5a2.81,2.81,0,0,1,.8-.54,2.4,2.4,0,0,1,1-.19,2.43,2.43,0,0,1,1,.19A2.76,2.76,0,0,1,9.63,5a2.46,2.46,0,0,1,.54.8,2.4,2.4,0,0,1,.2,1,2.44,2.44,0,0,1-.2,1A2.59,2.59,0,0,1,8.84,9a2.44,2.44,0,0,1-1,.2,2.4,2.4,0,0,1-1-.2A2.46,2.46,0,0,1,6.1,8.49Zm6.12,4.66a4.39,4.39,0,0,0-.18-.89,4.22,4.22,0,0,0-.57-1.19A4.24,4.24,0,0,0,9.36,9.49,3.41,3.41,0,0,0,10,9a3.36,3.36,0,0,0,.84-1.42A3.32,3.32,0,0,0,11,6.74a3.09,3.09,0,0,0-.24-1.22,3.26,3.26,0,0,0-.67-1,3,3,0,0,0-1-.67,3,3,0,0,0-1.22-.25,2.93,2.93,0,0,0-1.22.25A3.07,3.07,0,0,0,5,5.51a2.93,2.93,0,0,0-.25,1.22,3,3,0,0,0,.12.84,3,3,0,0,0,.32.76A3.3,3.3,0,0,0,5.7,9a3.06,3.06,0,0,0,.68.5,4.41,4.41,0,0,0-1.19.65,4.1,4.1,0,0,0-.91,1,4.18,4.18,0,0,0-.58,1.18,4.41,4.41,0,0,0-.18.8A6.66,6.66,0,0,1,1.2,8a6.72,6.72,0,1,1,11,5.15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>other_account_16x16</title><path d="M8,.28A7.71,7.71,0,1,0,15.72,8,7.73,7.73,0,0,0,8,.28ZM4.2,13.53a4,4,0,0,1,.13-.93,3.69,3.69,0,0,1,1-1.66A3.56,3.56,0,0,1,6,10.36a4,4,0,0,1,.9-.38,4.17,4.17,0,0,1,1-.13,3.79,3.79,0,0,1,1.48.29,3.61,3.61,0,0,1,2,2,3.74,3.74,0,0,1,.29,1.47A6.62,6.62,0,0,1,8,14.71,6.71,6.71,0,0,1,4.2,13.53Zm2-5a2.76,2.76,0,0,1-.54-.79,2.43,2.43,0,0,1-.19-1,2.4,2.4,0,0,1,.19-1A2.82,2.82,0,0,1,6.18,5,2.81,2.81,0,0,1,7,4.42a2.4,2.4,0,0,1,1-.19,2.43,2.43,0,0,1,1,.19A2.76,2.76,0,0,1,9.71,5a2.46,2.46,0,0,1,.54.8,2.4,2.4,0,0,1,.2,1,2.44,2.44,0,0,1-.2,1A2.59,2.59,0,0,1,8.92,9a2.44,2.44,0,0,1-1,.2A2.4,2.4,0,0,1,7,9,2.46,2.46,0,0,1,6.18,8.49Zm6.12,4.66a4.39,4.39,0,0,0-.18-.89,4.22,4.22,0,0,0-.57-1.19A4.24,4.24,0,0,0,9.44,9.48a3.41,3.41,0,0,0,.68-.5A3.36,3.36,0,0,0,11,7.56a3.32,3.32,0,0,0,.11-.83,3.09,3.09,0,0,0-.24-1.22,3.26,3.26,0,0,0-.67-1,3,3,0,0,0-1-.67A3,3,0,0,0,7.95,3.6a2.93,2.93,0,0,0-1.22.25A3.07,3.07,0,0,0,5.07,5.51a2.93,2.93,0,0,0-.25,1.22,3,3,0,0,0,.12.84,3,3,0,0,0,.32.76A3.3,3.3,0,0,0,5.78,9a3.06,3.06,0,0,0,.68.5,4.41,4.41,0,0,0-1.19.65,4.1,4.1,0,0,0-.91,1,4.18,4.18,0,0,0-.58,1.18,4.41,4.41,0,0,0-.18.8A6.66,6.66,0,0,1,1.28,8a6.72,6.72,0,1,1,11,5.15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,102 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ProviderSettings } from './interfaces';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
const publicAzureSettings: ProviderSettings = {
|
||||
configKey: 'enablePublicCloud',
|
||||
metadata: {
|
||||
displayName: localize('publicCloudDisplayName', 'Azure'),
|
||||
id: 'azurePublicCloud',
|
||||
settings: {
|
||||
host: 'https://login.microsoftonline.com/',
|
||||
clientId: 'a69788c6-1d43-44ed-9ca3-b83e194da255',
|
||||
signInResourceId: 'https://management.core.windows.net/',
|
||||
graphResource: {
|
||||
id: 'https://graph.windows.net/',
|
||||
endpoint: 'https://graph.windows.net'
|
||||
},
|
||||
armResource: {
|
||||
id: 'https://management.core.windows.net/',
|
||||
endpoint: 'https://management.azure.com'
|
||||
},
|
||||
redirectUri: 'http://localhost/redirect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const usGovAzureSettings: ProviderSettings = {
|
||||
configKey: 'enableUsGovCloud',
|
||||
metadata: {
|
||||
displayName: localize('usGovCloudDisplayName', 'Azure (US Government)'),
|
||||
id: 'usGovAzureCloud',
|
||||
settings: {
|
||||
host: 'https://login.microsoftonline.com/',
|
||||
clientId: 'TBD',
|
||||
signInResourceId: 'https://management.core.usgovcloudapi.net/',
|
||||
graphResource: {
|
||||
id: 'https://graph.usgovcloudapi.net/',
|
||||
endpoint: 'https://graph.usgovcloudapi.net'
|
||||
},
|
||||
armResource: {
|
||||
id: 'https://management.core.usgovcloudapi.net/',
|
||||
endpoint: 'https://management.usgovcloudapi.net'
|
||||
},
|
||||
redirectUri: 'http://localhost/redirect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const chinaAzureSettings: ProviderSettings = {
|
||||
configKey: 'enableChinaCloud',
|
||||
metadata: {
|
||||
displayName: localize('chinaCloudDisplayName', 'Azure (China)'),
|
||||
id: 'chinaAzureCloud',
|
||||
settings: {
|
||||
host: 'https://login.chinacloudapi.cn/',
|
||||
clientId: 'TBD',
|
||||
signInResourceId: 'https://management.core.chinacloudapi.cn/',
|
||||
graphResource: {
|
||||
id: 'https://graph.chinacloudapi.cn/',
|
||||
endpoint: 'https://graph.chinacloudapi.cn'
|
||||
},
|
||||
armResource: {
|
||||
id: 'https://management.core.chinacloudapi.cn/',
|
||||
endpoint: 'https://managemement.chinacloudapi.net'
|
||||
},
|
||||
redirectUri: 'http://localhost/redirect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const germanyAzureSettings: ProviderSettings = {
|
||||
configKey: 'enableGermanyCloud',
|
||||
metadata: {
|
||||
displayName: localize('germanyCloud', 'Azure (Germany)'),
|
||||
id: 'germanyAzureCloud',
|
||||
settings: {
|
||||
host: 'https://login.microsoftazure.de/',
|
||||
clientId: 'TBD',
|
||||
signInResourceId: 'https://management.core.cloudapi.de/',
|
||||
graphResource: {
|
||||
id: 'https://graph.cloudapi.de/',
|
||||
endpoint: 'https://graph.cloudapi.de'
|
||||
},
|
||||
armResource: {
|
||||
id: 'https://management.core.cloudapi.de/',
|
||||
endpoint: 'https://management.microsoftazure.de'
|
||||
},
|
||||
redirectUri: 'http://localhost/redirect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Enable China, Germany, and US Gov clouds: (#3031)
|
||||
export default <ProviderSettings[]>[publicAzureSettings, /*chinaAzureSettings, germanyAzureSettings, usGovAzureSettings*/];
|
||||
@@ -0,0 +1,291 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as adal from 'adal-node';
|
||||
import * as data from 'data';
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export default class TokenCache implements adal.TokenCache {
|
||||
private static CipherAlgorithm = 'aes256';
|
||||
private static CipherAlgorithmIvLength = 16;
|
||||
private static CipherKeyLength = 32;
|
||||
private static FsOptions = { encoding: 'ascii' };
|
||||
|
||||
private _activeOperation: Thenable<any>;
|
||||
|
||||
constructor(
|
||||
private _credentialProvider: data.CredentialProvider,
|
||||
private _credentialServiceKey: string,
|
||||
private _cacheSerializationPath: string
|
||||
) {
|
||||
}
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public add(entries: adal.TokenResponse[], callback: (error: Error, result: boolean) => void): void {
|
||||
let self = this;
|
||||
|
||||
this.doOperation(() => {
|
||||
return self.readCache()
|
||||
.then(cache => self.addToCache(cache, entries))
|
||||
.then(updatedCache => self.writeCache(updatedCache))
|
||||
.then(
|
||||
() => callback(null, false),
|
||||
(err) => callback(err, true)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public clear(): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
// 1) Delete encrypted serialization file
|
||||
// If we got an 'ENOENT' response, the file doesn't exist, which is fine
|
||||
// 3) Delete the encryption key
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.unlink(self._cacheSerializationPath, err => {
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(() => { return self._credentialProvider.deleteCredential(self._credentialServiceKey); })
|
||||
.then(() => {});
|
||||
}
|
||||
|
||||
public find(query: any, callback: (error: Error, results: any[]) => void): void {
|
||||
let self = this;
|
||||
|
||||
this.doOperation(() => {
|
||||
return self.readCache()
|
||||
.then(cache => {
|
||||
return cache.filter(
|
||||
entry => TokenCache.findByPartial(entry, query)
|
||||
);
|
||||
})
|
||||
.then(
|
||||
results => callback(null, results),
|
||||
(err) => callback(err, null)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to make callback-based find method into a thenable method
|
||||
* @param query Partial object to use to look up tokens. Ideally should be partial of adal.TokenResponse
|
||||
* @returns {Thenable<any[]>} Promise to return the matching adal.TokenResponse objects.
|
||||
* Rejected if an error was sent in the callback
|
||||
*/
|
||||
public findThenable(query: any): Thenable<any[]> {
|
||||
let self = this;
|
||||
|
||||
return new Promise<any[]>((resolve, reject) => {
|
||||
self.find(query, (error: Error, results: any[]) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(results);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public remove(entries: adal.TokenResponse[], callback: (error: Error, result: null) => void): void {
|
||||
let self = this;
|
||||
|
||||
this.doOperation(() => {
|
||||
return this.readCache()
|
||||
.then(cache => self.removeFromCache(cache, entries))
|
||||
.then(updatedCache => self.writeCache(updatedCache))
|
||||
.then(
|
||||
() => callback(null, null),
|
||||
(err) => callback(err, null)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to make callback-based remove method into a thenable method
|
||||
* @param {TokenResponse[]} entries Array of entries to remove from the token cache
|
||||
* @returns {Thenable<void>} Promise to remove the given tokens from the token cache
|
||||
* Rejected if an error was sent in the callback
|
||||
*/
|
||||
public removeThenable(entries: adal.TokenResponse[]): Thenable<void> {
|
||||
let self = this;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
self.remove(entries, (error: Error, result: null) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// PRIVATE METHODS /////////////////////////////////////////////////////
|
||||
private static findByKeyHelper(entry1: adal.TokenResponse, entry2: adal.TokenResponse): boolean {
|
||||
return entry1._authority === entry2._authority
|
||||
&& entry1._clientId === entry2._clientId
|
||||
&& entry1.userId === entry2.userId
|
||||
&& entry1.resource === entry2.resource;
|
||||
}
|
||||
|
||||
private static findByPartial(entry: adal.TokenResponse, query: object): boolean {
|
||||
for (let key in query) {
|
||||
if (entry[key] === undefined || entry[key] !== query[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private doOperation<T>(op: () => Thenable<T>): void {
|
||||
// Initialize the active operation to an empty promise if necessary
|
||||
let activeOperation = this._activeOperation || Promise.resolve<any>(null);
|
||||
|
||||
// Chain the operation to perform to the end of the existing promise
|
||||
activeOperation = activeOperation.then(op);
|
||||
|
||||
// Add a catch at the end to make sure we can continue after any errors
|
||||
activeOperation = activeOperation.then(null, err => {
|
||||
console.error(`Failed to perform token cache operation: ${err}`);
|
||||
});
|
||||
|
||||
// Point the current active operation to this one
|
||||
this._activeOperation = activeOperation;
|
||||
}
|
||||
|
||||
private addToCache(cache: adal.TokenResponse[], entries: adal.TokenResponse[]): adal.TokenResponse[] {
|
||||
// First remove entries from the db that are being updated
|
||||
cache = this.removeFromCache(cache, entries);
|
||||
|
||||
// Then add the new entries to the cache
|
||||
entries.forEach((entry: adal.TokenResponse) => {
|
||||
cache.push(entry);
|
||||
});
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private getOrCreateEncryptionParams(): Thenable<EncryptionParams> {
|
||||
let self = this;
|
||||
|
||||
return this._credentialProvider.readCredential(this._credentialServiceKey)
|
||||
.then(credential => {
|
||||
if (credential.password) {
|
||||
// We already have encryption params, deserialize them
|
||||
let splitValues = credential.password.split('|');
|
||||
if (splitValues.length === 2 && splitValues[0] && splitValues[1]) {
|
||||
try {
|
||||
return <EncryptionParams>{
|
||||
key: new Buffer(splitValues[0], 'hex'),
|
||||
initializationVector: new Buffer(splitValues[1], 'hex')
|
||||
};
|
||||
} catch(e) {
|
||||
// Swallow the error and fall through to generate new params
|
||||
console.warn('Failed to deserialize encryption params, new ones will be generated.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We haven't stored encryption values, so generate them
|
||||
let encryptKey = crypto.randomBytes(TokenCache.CipherKeyLength);
|
||||
let initializationVector = crypto.randomBytes(TokenCache.CipherAlgorithmIvLength);
|
||||
|
||||
// Serialize the values
|
||||
let serializedValues = `${encryptKey.toString('hex')}|${initializationVector.toString('hex')}`;
|
||||
return self._credentialProvider.saveCredential(self._credentialServiceKey, serializedValues)
|
||||
.then(() => {
|
||||
return <EncryptionParams> {
|
||||
key: encryptKey,
|
||||
initializationVector: initializationVector
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private readCache(): Thenable<adal.TokenResponse[]> {
|
||||
let self = this;
|
||||
|
||||
// NOTE: File system operations are performed synchronously to avoid annoying nested callbacks
|
||||
// 1) Get the encryption key
|
||||
// 2) Read the encrypted token cache file
|
||||
// 3) Decrypt the file contents
|
||||
// 4) Deserialize and return
|
||||
return this.getOrCreateEncryptionParams()
|
||||
.then(encryptionParams => {
|
||||
try {
|
||||
let cacheCipher = fs.readFileSync(self._cacheSerializationPath, TokenCache.FsOptions);
|
||||
|
||||
let decipher = crypto.createDecipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
||||
let cacheJson = decipher.update(cacheCipher, 'hex', 'binary');
|
||||
cacheJson += decipher.final('binary');
|
||||
|
||||
// Deserialize the JSON into the array of tokens
|
||||
let cacheObj = <adal.TokenResponse[]>JSON.parse(cacheJson);
|
||||
for (let objIndex in cacheObj) {
|
||||
// Rehydrate Date objects since they will always serialize as a string
|
||||
cacheObj[objIndex].expiresOn = new Date(<string>cacheObj[objIndex].expiresOn);
|
||||
}
|
||||
|
||||
return cacheObj;
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
.then(null, err => {
|
||||
// If reading the token cache fails, we'll just assume the tokens are garbage
|
||||
console.warn(`Failed to read token cache: ${err}`);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
private removeFromCache(cache: adal.TokenResponse[], entries: adal.TokenResponse[]): adal.TokenResponse[] {
|
||||
entries.forEach((entry: adal.TokenResponse) => {
|
||||
// Check to see if the entry exists
|
||||
let match = cache.findIndex(entry2 => TokenCache.findByKeyHelper(entry, entry2));
|
||||
if (match >= 0) {
|
||||
// Entry exists, remove it from cache
|
||||
cache.splice(match, 1);
|
||||
}
|
||||
});
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private writeCache(cache: adal.TokenResponse[]): Thenable<void> {
|
||||
let self = this;
|
||||
// NOTE: File system operations are being done synchronously to avoid annoying callback nesting
|
||||
// 1) Get (or generate) the encryption key
|
||||
// 2) Stringify the token cache entries
|
||||
// 4) Encrypt the JSON
|
||||
// 3) Write to the file
|
||||
return this.getOrCreateEncryptionParams()
|
||||
.then(encryptionParams => {
|
||||
try {
|
||||
let cacheJson = JSON.stringify(cache);
|
||||
|
||||
let cipher = crypto.createCipheriv(TokenCache.CipherAlgorithm, encryptionParams.key, encryptionParams.initializationVector);
|
||||
let cacheCipher = cipher.update(cacheJson, 'binary', 'hex');
|
||||
cacheCipher += cipher.final('hex');
|
||||
|
||||
fs.writeFileSync(self._cacheSerializationPath, cacheCipher, TokenCache.FsOptions);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface EncryptionParams {
|
||||
key: Buffer;
|
||||
initializationVector: Buffer;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"service": {
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.2.0-alpha.37",
|
||||
"version": "1.2.0-alpha.49",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.0.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.0.zip",
|
||||
|
||||
@@ -8,10 +8,15 @@ import vscode = require('vscode');
|
||||
import data = require('data');
|
||||
import { Constants } from '../models/constants';
|
||||
import { Serialization } from '../serialize/serialization';
|
||||
import { AzureResourceProvider } from '../resourceProvider/resourceProvider';
|
||||
import { AzureResourceProvider } from '../resourceprovider/resourceprovider';
|
||||
import { CredentialStore } from '../credentialstore/credentialstore';
|
||||
import {IExtensionConstants, Telemetry, SharedConstants, SqlToolsServiceClient, VscodeWrapper, Utils, PlatformInformation} from 'extensions-modules';
|
||||
import { LanguageClient } from 'dataprotocol-client';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
|
||||
import { AzureAccountProviderService } from '../account-provider/azureAccountProviderService';
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
@@ -92,77 +97,94 @@ export default class MainController implements vscode.Disposable {
|
||||
|
||||
// initialize language service client
|
||||
return new Promise<boolean>( (resolve, reject) => {
|
||||
const self = this;
|
||||
SqlToolsServiceClient.instance.initialize(self._context).then(serverResult => {
|
||||
|
||||
// Initialize telemetry
|
||||
Telemetry.initialize(self._context, new Constants());
|
||||
let constants = new Constants();
|
||||
|
||||
// telemetry for activation
|
||||
Telemetry.sendTelemetryEvent('ExtensionActivated', {},
|
||||
{ serviceInstalled: serverResult.installedBeforeInitializing ? 1 : 0 }
|
||||
);
|
||||
// Create the folder for storing the token caches
|
||||
let storagePath = path.join(Utils.getDefaultLogLocation(), constants.extensionName);
|
||||
try {
|
||||
if (!fs.existsSync(storagePath)) {
|
||||
fs.mkdirSync(storagePath);
|
||||
console.log('Initialized Azure account extension storage.');
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(`Initialization of Azure account extension storage failed: ${e}`);
|
||||
console.error('Azure accounts will not be available');
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
self.createSerializationClient().then(serializationClient => {
|
||||
let serialization = new Serialization(self._client, serializationClient);
|
||||
// Serialization
|
||||
let serializationProvider: data.SerializationProvider = {
|
||||
handle: 0,
|
||||
saveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<data.SaveResultRequestResult> {
|
||||
return self._serialization.saveAs(saveFormat, savePath, results, appendToFile);
|
||||
}
|
||||
};
|
||||
data.serialization.registerProvider(serializationProvider);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find Serialization executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
// Create the provider service and activate
|
||||
const accountProviderService = new AzureAccountProviderService(this._context, storagePath);
|
||||
this._context.subscriptions.push(accountProviderService);
|
||||
accountProviderService.activate();
|
||||
|
||||
self.createResourceProviderClient().then(rpClient => {
|
||||
let resourceProvider = new AzureResourceProvider(self._client, rpClient);
|
||||
data.resources.registerResourceProvider({
|
||||
displayName: 'Azure SQL Resource Provider', // TODO Localize
|
||||
id: 'Microsoft.Azure.SQL.ResourceProvider',
|
||||
settings: {
|
||||
const self = this;
|
||||
SqlToolsServiceClient.instance.initialize(self._context).then(serverResult => {
|
||||
|
||||
}
|
||||
}, resourceProvider);
|
||||
Utils.logDebug('resourceProvider registered', MainController._extensionConstants.extensionConfigSectionName);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find ResourceProvider executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
*/
|
||||
// Initialize telemetry
|
||||
Telemetry.initialize(self._context, new Constants());
|
||||
|
||||
self.createCredentialClient().then(credentialClient => {
|
||||
// telemetry for activation
|
||||
Telemetry.sendTelemetryEvent('ExtensionActivated', {},
|
||||
{ serviceInstalled: serverResult.installedBeforeInitializing ? 1 : 0 }
|
||||
);
|
||||
|
||||
self._credentialStore.languageClient = credentialClient;
|
||||
let credentialProvider: data.CredentialProvider = {
|
||||
handle: 0,
|
||||
saveCredential(credentialId: string, password: string): Thenable<boolean> {
|
||||
return self._credentialStore.saveCredential(credentialId, password);
|
||||
},
|
||||
readCredential(credentialId: string): Thenable<data.Credential> {
|
||||
return self._credentialStore.readCredential(credentialId);
|
||||
},
|
||||
deleteCredential(credentialId: string): Thenable<boolean> {
|
||||
return self._credentialStore.deleteCredential(credentialId);
|
||||
}
|
||||
};
|
||||
data.credentials.registerProvider(credentialProvider);
|
||||
Utils.logDebug('credentialProvider registered', MainController._extensionConstants.extensionConfigSectionName);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find credentials executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Utils.logDebug(SharedConstants.extensionActivated, MainController._extensionConstants.extensionConfigSectionName);
|
||||
self._initialized = true;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
Telemetry.sendTelemetryEventForException(err, 'initialize', MainController._extensionConstants.extensionConfigSectionName);
|
||||
reject(err);
|
||||
self.createSerializationClient().then(serializationClient => {
|
||||
let serialization = new Serialization(self._client, serializationClient);
|
||||
// Serialization
|
||||
let serializationProvider: data.SerializationProvider = {
|
||||
handle: 0,
|
||||
saveAs(saveFormat: string, savePath: string, results: string, appendToFile: boolean): Thenable<data.SaveResultRequestResult> {
|
||||
return self._serialization.saveAs(saveFormat, savePath, results, appendToFile);
|
||||
}
|
||||
};
|
||||
data.serialization.registerProvider(serializationProvider);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find Serialization executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
|
||||
self.createResourceProviderClient().then(rpClient => {
|
||||
let resourceProvider = new AzureResourceProvider(self._client, rpClient);
|
||||
data.resources.registerResourceProvider({
|
||||
displayName: 'Azure SQL Resource Provider', // TODO Localize
|
||||
id: 'Microsoft.Azure.SQL.ResourceProvider',
|
||||
settings: {
|
||||
|
||||
}
|
||||
}, resourceProvider);
|
||||
Utils.logDebug('resourceProvider registered', MainController._extensionConstants.extensionConfigSectionName);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find ResourceProvider executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
|
||||
self.createCredentialClient().then(credentialClient => {
|
||||
|
||||
self._credentialStore.languageClient = credentialClient;
|
||||
let credentialProvider: data.CredentialProvider = {
|
||||
handle: 0,
|
||||
saveCredential(credentialId: string, password: string): Thenable<boolean> {
|
||||
return self._credentialStore.saveCredential(credentialId, password);
|
||||
},
|
||||
readCredential(credentialId: string): Thenable<data.Credential> {
|
||||
return self._credentialStore.readCredential(credentialId);
|
||||
},
|
||||
deleteCredential(credentialId: string): Thenable<boolean> {
|
||||
return self._credentialStore.deleteCredential(credentialId);
|
||||
}
|
||||
};
|
||||
data.credentials.registerProvider(credentialProvider);
|
||||
Utils.logDebug('credentialProvider registered', MainController._extensionConstants.extensionConfigSectionName);
|
||||
}, error => {
|
||||
Utils.logDebug('Cannot find credentials executables. error: ' + error , MainController._extensionConstants.extensionConfigSectionName);
|
||||
});
|
||||
|
||||
Utils.logDebug(SharedConstants.extensionActivated, MainController._extensionConstants.extensionConfigSectionName);
|
||||
self._initialized = true;
|
||||
resolve(true);
|
||||
}).catch(err => {
|
||||
Telemetry.sendTelemetryEventForException(err, 'initialize', MainController._extensionConstants.extensionConfigSectionName);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -4,5 +4,4 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../../src/sql/data.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
||||
/// <reference path='../../../../../src/sql/data.d.ts'/>
|
||||
Generated
+1918
-2
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"accounts.azure.enableUsGovCloud": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.enableUsGovCloudDescription%"
|
||||
},
|
||||
"accounts.azure.enableChinaCloud": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.enableChinaCloudDescription%"
|
||||
},
|
||||
"accounts.azure.enableGermanyCloud": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.enableGermanyCloudDescription%"
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,38 @@
|
||||
"path": "./snippets/mssql.json"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "extension.clearTokenCache",
|
||||
"title": "%extension.clearTokenCache%",
|
||||
"category": "Azure Accounts"
|
||||
}
|
||||
],
|
||||
"account-type": [
|
||||
{
|
||||
"id": "microsoft",
|
||||
"icon": {
|
||||
"light": "./out/account-provider/media/microsoft_account_light.svg",
|
||||
"dark": "./out/account-provider/media/microsoft_account_dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "work_school",
|
||||
"icon": {
|
||||
"light": "./out/account-provider/media/work_school_account_light.svg",
|
||||
"dark": "./out/account-provider/media/work_school_account_dark.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "MSSQL configuration",
|
||||
"properties": {
|
||||
"accounts.azure.enablePublicCloud": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%config.enablePublicCloudDescription%"
|
||||
},
|
||||
"mssql.query.displayBitAsNumber": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
@@ -101,13 +129,116 @@
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"provider": "MSSQL",
|
||||
"flavors": [
|
||||
{
|
||||
"flavor": "on_prem",
|
||||
"condition": {
|
||||
"field": "isCloud",
|
||||
"operator": "!=",
|
||||
"value": true
|
||||
},
|
||||
"databaseProperties": [
|
||||
{
|
||||
"displayName": "Recovery Model",
|
||||
"value": "recoveryModel"
|
||||
},
|
||||
{
|
||||
"displayName": "Last Database Backup",
|
||||
"value": "lastBackupDate",
|
||||
"ignore": [
|
||||
"1/1/0001 12:00:00 AM"
|
||||
]
|
||||
},
|
||||
{
|
||||
"displayName": "Last Log Backup",
|
||||
"value": "lastLogBackupDate",
|
||||
"ignore": [
|
||||
"1/1/0001 12:00:00 AM"
|
||||
]
|
||||
},
|
||||
{
|
||||
"displayName": "Compatibility Level",
|
||||
"value": "compatibilityLevel"
|
||||
},
|
||||
{
|
||||
"displayName": "Owner",
|
||||
"value": "owner"
|
||||
}
|
||||
],
|
||||
"serverProperties": [
|
||||
{
|
||||
"displayName": "Version",
|
||||
"value": "serverVersion"
|
||||
},
|
||||
{
|
||||
"displayName": "Edition",
|
||||
"value": "serverEdition"
|
||||
},
|
||||
{
|
||||
"displayName": "Computer Name",
|
||||
"value": "machineName"
|
||||
},
|
||||
{
|
||||
"displayName": "OS Version",
|
||||
"value": "osVersion"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"flavor": "cloud",
|
||||
"condition": {
|
||||
"field": "isCloud",
|
||||
"operator": "==",
|
||||
"value": true
|
||||
},
|
||||
"databaseProperties": [
|
||||
{
|
||||
"displayName": "Edition",
|
||||
"value": "azureEdition"
|
||||
},
|
||||
{
|
||||
"displayName": "Pricing Tier",
|
||||
"value": "serviceLevelObjective"
|
||||
},
|
||||
{
|
||||
"displayName": "Compatibility Level",
|
||||
"value": "compatibilityLevel"
|
||||
},
|
||||
{
|
||||
"displayName": "Owner",
|
||||
"value": "owner"
|
||||
}
|
||||
],
|
||||
"serverProperties": [
|
||||
{
|
||||
"displayName": "Version",
|
||||
"value": "serverVersion"
|
||||
},
|
||||
{
|
||||
"displayName": "Type",
|
||||
"value": "serverEdition"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"dataprotocol-client": "file:../../dataprotocol-node/client",
|
||||
"extensions-modules": "file:../../extensions-modules"
|
||||
"extensions-modules": "file:../../extensions-modules",
|
||||
"adal-node": "0.1.25",
|
||||
"decompress": "^4.0.0",
|
||||
"fs-extra-promise": "^1.0.1",
|
||||
"opener": "1.4.3",
|
||||
"request": "2.63.0",
|
||||
"vscode-extension-telemetry": "^0.0.8",
|
||||
"vscode-nls": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vscode": "1.0.1"
|
||||
"vscode": "1.0.1",
|
||||
"@types/node": "^8.0.24"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"json.schemas.desc": "Associate schemas to JSON files in the current project",
|
||||
"json.schemas.url.desc": "A URL to a schema or a relative path to a schema in the current directory",
|
||||
"json.schemas.fileMatch.desc": "An array of file patterns to match against when resolving JSON files to schemas.",
|
||||
"json.schemas.fileMatch.item.desc": "A file pattern that can contain '*' to match against when resolving JSON files to schemas.",
|
||||
"json.schemas.schema.desc": "The schema definition for the given URL. The schema only needs to be provided to avoid accesses to the schema URL.",
|
||||
"json.format.enable.desc": "Enable/disable default JSON formatter (requires restart)"
|
||||
"extension.clearTokenCache": "Clear Azure Account Token Cache",
|
||||
"config.enablePublicCloudDescription": "Should Azure public cloud integration be enabled",
|
||||
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
|
||||
"config.enableChinaCloudDescription": "Should Azure China integration be enabled",
|
||||
"config.enableGermanyCloudDescription": "Should Azure Germany integration be enabled"
|
||||
}
|
||||
Generated
+3
-3
@@ -3,9 +3,9 @@
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"typescript": {
|
||||
"version": "2.5.2",
|
||||
"from": "typescript@2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz"
|
||||
"version": "2.6.1",
|
||||
"from": "typescript@2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.1.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"description": "Dependencies shared by all extensions",
|
||||
"dependencies": {
|
||||
"typescript": "2.5.2"
|
||||
"typescript": "2.6.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node ./postinstall"
|
||||
|
||||
@@ -22,5 +22,11 @@
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
]
|
||||
],
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*#region\\b",
|
||||
"end": "^\\s*#endregion\\b"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,10 @@
|
||||
"language": "powershell",
|
||||
"scopeName": "source.powershell",
|
||||
"path": "./syntaxes/PowershellSyntax.tmLanguage"
|
||||
}],
|
||||
"snippets": [{
|
||||
"language": "powershell",
|
||||
"path": "./snippets/powershell.json"
|
||||
}]
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"Region Start": {
|
||||
"prefix": "#region",
|
||||
"body": [
|
||||
"#region $0"
|
||||
],
|
||||
"description": "Folding Region Start"
|
||||
},
|
||||
"Region End": {
|
||||
"prefix": "#endregion",
|
||||
"body": [
|
||||
"#endregion"
|
||||
],
|
||||
"description": "Folding Region End"
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(?<![\\-])#</string>
|
||||
<string>(?<![`\\-])#</string>
|
||||
<key>end</key>
|
||||
<string>$</string>
|
||||
<key>name</key>
|
||||
@@ -246,7 +246,7 @@
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>(?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!=-object)|while)|%|\?)(?!\w)</string>
|
||||
<string>(?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!-object)|while)|%|\?)(?!\w)</string>
|
||||
<key>name</key>
|
||||
<string>keyword.control.powershell</string>
|
||||
</dict>
|
||||
@@ -426,6 +426,14 @@
|
||||
<key>name</key>
|
||||
<string>support.function.powershell</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>comment</key>
|
||||
<string>Builtin cmdlets with reserved verbs</string>
|
||||
<key>match</key>
|
||||
<string>(?<!\w)(?i:where-object)(?!\w)</string>
|
||||
<key>name</key>
|
||||
<string>support.function.powershell</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>commentEmbeddedDocs</key>
|
||||
|
||||
+3
-3
@@ -7,12 +7,12 @@
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}"
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outDir": "${workspaceRoot}/out",
|
||||
"outDir": "${workspaceFolder}/out",
|
||||
"preLaunchTask": "npm"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// Available variables which can be used inside of strings.
|
||||
// ${workspaceRoot}: the root folder of the team
|
||||
// ${workspaceFolder}: the root folder of the team
|
||||
// ${file}: the current opened file
|
||||
// ${fileBasename}: the current opened file's basename
|
||||
// ${fileDirname}: the current opened file's dirname
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
]
|
||||
// enhancedBrackets: [ { open: /.*:\s*$/, closeComplete: 'else:' } ],
|
||||
}
|
||||
],
|
||||
"folding": {
|
||||
"offSide": true,
|
||||
"markers": {
|
||||
"start": "^\\s*#region\\b",
|
||||
"end": "^\\s*#endregion\\b"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5294,8 +5294,8 @@
|
||||
"c": "(",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5305,8 +5305,8 @@
|
||||
"c": "[",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "punctuation.character.set.begin.regexp: #CE9178",
|
||||
"light_plus": "punctuation.character.set.begin.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5316,19 +5316,19 @@
|
||||
"c": "0-9-",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "constant.character.set.regexp: #D16969",
|
||||
"light_plus": "constant.character.set.regexp: #811F3F",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "]",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "punctuation.character.set.end.regexp: #CE9178",
|
||||
"light_plus": "punctuation.character.set.end.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5338,8 +5338,8 @@
|
||||
"c": "*",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D",
|
||||
"light_plus": "keyword.operator.quantifier.regexp: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
@@ -5349,8 +5349,8 @@
|
||||
"c": ")",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5371,8 +5371,8 @@
|
||||
"c": "*",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D",
|
||||
"light_plus": "keyword.operator.quantifier.regexp: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
@@ -5382,8 +5382,8 @@
|
||||
"c": "(",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5393,8 +5393,8 @@
|
||||
"c": "[",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "punctuation.character.set.begin.regexp: #CE9178",
|
||||
"light_plus": "punctuation.character.set.begin.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5404,19 +5404,19 @@
|
||||
"c": "A-Za-z",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp constant.character.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "constant.character.set.regexp: #D16969",
|
||||
"light_plus": "constant.character.set.regexp: #811F3F",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "]",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python meta.character.set.regexp punctuation.character.set.end.regexp constant.other.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "punctuation.character.set.end.regexp: #CE9178",
|
||||
"light_plus": "punctuation.character.set.end.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5426,8 +5426,8 @@
|
||||
"c": "+",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D",
|
||||
"light_plus": "keyword.operator.quantifier.regexp: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
@@ -5437,8 +5437,8 @@
|
||||
"c": ")",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5470,8 +5470,8 @@
|
||||
"c": "+",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D",
|
||||
"light_plus": "keyword.operator.quantifier.regexp: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
@@ -5481,8 +5481,8 @@
|
||||
"c": "(",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -5503,8 +5503,8 @@
|
||||
"c": "*",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python keyword.operator.quantifier.regexp",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_plus": "keyword.operator.quantifier.regexp: #D7BA7D",
|
||||
"light_plus": "keyword.operator.quantifier.regexp: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
@@ -5514,8 +5514,8 @@
|
||||
"c": ")",
|
||||
"t": "source.python meta.function-call.python meta.function-call.arguments.python string.regexp.quoted.single.python support.other.parenthesis.regexp punctuation.parenthesis.end.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "support.other.parenthesis.regexp: #CE9178",
|
||||
"light_plus": "support.other.parenthesis.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -6504,8 +6504,8 @@
|
||||
"c": "[",
|
||||
"t": "source.python string.regexp.quoted.multi.python meta.character.set.regexp punctuation.character.set.begin.regexp constant.other.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "punctuation.character.set.begin.regexp: #CE9178",
|
||||
"light_plus": "punctuation.character.set.begin.regexp: #D16969",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
@@ -6515,11 +6515,11 @@
|
||||
"c": "1,2)`` leads to",
|
||||
"t": "source.python string.regexp.quoted.multi.python meta.character.set.regexp constant.character.set.regexp",
|
||||
"r": {
|
||||
"dark_plus": "string.regexp: #D16969",
|
||||
"light_plus": "string.regexp: #811F3F",
|
||||
"dark_plus": "constant.character.set.regexp: #D16969",
|
||||
"light_plus": "constant.character.set.regexp: #811F3F",
|
||||
"dark_vs": "string.regexp: #D16969",
|
||||
"light_vs": "string.regexp: #811F3F",
|
||||
"hc_black": "string.regexp: #D16969"
|
||||
"hc_black": "constant.character: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
|
||||
[{
|
||||
"name": "textmate/r.tmbundle",
|
||||
"name": "Ikuyadeu/vscode-R",
|
||||
"version": "0.0.0",
|
||||
"license": "TextMate Bundle License",
|
||||
"repositoryURL": "https://github.com/textmate/r.tmbundle",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) textmate-r.tmbundle project authors",
|
||||
"",
|
||||
"If not otherwise specified (see below), files in this folder fall under the following license: ",
|
||||
"",
|
||||
"Permission to copy, use, modify, sell and distribute this",
|
||||
"software is granted. This software is provided \"as is\" without",
|
||||
"express or implied warranty, and with no claim as to its",
|
||||
"suitability for any purpose."
|
||||
]
|
||||
"license": "MIT",
|
||||
"repositoryURL": "https://github.com/Ikuyadeu/vscode-R"
|
||||
}]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"publisher": "vscode",
|
||||
"engines": { "vscode": "*" },
|
||||
"scripts": {
|
||||
"update-grammar": "node ../../build/npm/update-grammar.js textmate/r.tmbundle Syntaxes/R.plist ./syntaxes/r.tmLanguage.json"
|
||||
"update-grammar": "node ../../build/npm/update-grammar.js Ikuyadeu/vscode-R syntax/r.json ./syntaxes/r.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,8 +22,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -33,8 +33,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' Add together two numbers.",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": " Add together two numbers.",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -44,8 +44,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -55,8 +55,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "'",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -66,8 +66,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -77,8 +77,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' @param x A number.",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "@param",
|
||||
"t": "source.r comment.line.roxygen.r keyword.other.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -88,8 +99,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": "x",
|
||||
"t": "source.r comment.line.roxygen.r variable.parameter.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " A number.",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -99,8 +121,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' @param y A number.",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -110,8 +132,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -121,8 +143,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' @return The sum of \\code{x} and \\code{y}.",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "@param",
|
||||
"t": "source.r comment.line.roxygen.r keyword.other.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -132,8 +165,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": "y",
|
||||
"t": "source.r comment.line.roxygen.r variable.parameter.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " A number.",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -143,8 +187,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' @examples",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -154,8 +198,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -165,8 +209,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' add(1, 1)",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": "@return",
|
||||
"t": "source.r comment.line.roxygen.r keyword.other.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " The sum of \\code{x} and \\code{y}.",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -176,8 +231,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#",
|
||||
"t": "source.r comment.line.number-sign.r punctuation.definition.comment.r",
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -187,8 +242,63 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "' add(10, 1)",
|
||||
"t": "source.r comment.line.number-sign.r",
|
||||
"c": " ",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "comment: #7CA668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "@examples",
|
||||
"t": "source.r comment.line.roxygen.r keyword.other.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "comment: #7CA668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " add(1, 1)",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "comment: #7CA668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "#'",
|
||||
"t": "source.r comment.line.roxygen.r punctuation.definition.comment.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
"dark_vs": "comment: #608B4E",
|
||||
"light_vs": "comment: #008000",
|
||||
"hc_black": "comment: #7CA668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " add(10, 1)",
|
||||
"t": "source.r comment.line.roxygen.r",
|
||||
"r": {
|
||||
"dark_plus": "comment: #608B4E",
|
||||
"light_plus": "comment: #008000",
|
||||
@@ -243,7 +353,7 @@
|
||||
},
|
||||
{
|
||||
"c": "function",
|
||||
"t": "source.r meta.function.r keyword.control.r",
|
||||
"t": "source.r meta.function.r meta.function.r keyword.control.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword.control: #C586C0",
|
||||
"light_plus": "keyword.control: #AF00DB",
|
||||
@@ -254,7 +364,7 @@
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r",
|
||||
"t": "source.r meta.function.r meta.function.r punctuation.section.parens.begin.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -265,7 +375,7 @@
|
||||
},
|
||||
{
|
||||
"c": "x",
|
||||
"t": "source.r variable.other.r",
|
||||
"t": "source.r meta.function.r meta.function.r meta.function.parameters.r variable.parameter.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@@ -275,8 +385,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ", ",
|
||||
"t": "source.r",
|
||||
"c": ",",
|
||||
"t": "source.r meta.function.r meta.function.r meta.function.parameters.r punctuation.separator.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.function.r meta.function.r meta.function.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -287,7 +408,7 @@
|
||||
},
|
||||
{
|
||||
"c": "y",
|
||||
"t": "source.r variable.other.r",
|
||||
"t": "source.r meta.function.r meta.function.r meta.function.parameters.r variable.parameter.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@@ -297,7 +418,18 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ") ",
|
||||
"c": ")",
|
||||
"t": "source.r meta.function.r meta.function.r punctuation.section.parens.end.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
@@ -309,7 +441,7 @@
|
||||
},
|
||||
{
|
||||
"c": "{",
|
||||
"t": "source.r meta.block.r punctuation.section.block.begin.r",
|
||||
"t": "source.r punctuation.section.braces.begin.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -320,7 +452,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.block.r",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -331,7 +463,7 @@
|
||||
},
|
||||
{
|
||||
"c": "x",
|
||||
"t": "source.r meta.block.r variable.other.r",
|
||||
"t": "source.r variable.other.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
@@ -342,7 +474,7 @@
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.block.r",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -353,83 +485,6 @@
|
||||
},
|
||||
{
|
||||
"c": "+",
|
||||
"t": "source.r meta.block.r keyword.operator.arithmetic.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.block.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "y",
|
||||
"t": "source.r meta.block.r variable.other.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "source.r meta.block.r punctuation.section.block.end.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "add(",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "1",
|
||||
"t": "source.r constant.numeric.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
"dark_vs": "constant.numeric: #B5CEA8",
|
||||
"light_vs": "constant.numeric: #09885A",
|
||||
"hc_black": "constant.numeric: #B5CEA8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ", ",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "-",
|
||||
"t": "source.r keyword.operator.arithmetic.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
@@ -440,8 +495,63 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "2",
|
||||
"t": "source.r constant.numeric.r",
|
||||
"c": " ",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "y",
|
||||
"t": "source.r variable.other.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "}",
|
||||
"t": "source.r punctuation.section.braces.end.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "add",
|
||||
"t": "source.r meta.function-call.r variable.function.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r meta.function-call.r punctuation.section.parens.begin.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "1",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r constant.numeric.float.decimal.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
@@ -451,8 +561,63 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ", ",
|
||||
"t": "source.r",
|
||||
"c": ",",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r punctuation.separator.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "-",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r keyword.operator.arithmetic.r",
|
||||
"r": {
|
||||
"dark_plus": "keyword.operator: #D4D4D4",
|
||||
"light_plus": "keyword.operator: #000000",
|
||||
"dark_vs": "keyword.operator: #D4D4D4",
|
||||
"light_vs": "keyword.operator: #000000",
|
||||
"hc_black": "keyword.operator: #D4D4D4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "2",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r constant.numeric.float.decimal.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
"dark_vs": "constant.numeric: #B5CEA8",
|
||||
"light_vs": "constant.numeric: #09885A",
|
||||
"hc_black": "constant.numeric: #B5CEA8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ",",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r punctuation.separator.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -463,7 +628,7 @@
|
||||
},
|
||||
{
|
||||
"c": "2.0",
|
||||
"t": "source.r constant.numeric.r",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r constant.numeric.float.decimal.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
@@ -474,7 +639,7 @@
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.r",
|
||||
"t": "source.r meta.function-call.r punctuation.definition.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -484,8 +649,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "add(",
|
||||
"t": "source.r",
|
||||
"c": "add",
|
||||
"t": "source.r meta.function-call.r variable.function.r",
|
||||
"r": {
|
||||
"dark_plus": "variable: #9CDCFE",
|
||||
"light_plus": "variable: #001080",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "variable: #9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r meta.function-call.r punctuation.section.parens.begin.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -496,7 +672,7 @@
|
||||
},
|
||||
{
|
||||
"c": "1.0e10",
|
||||
"t": "source.r constant.numeric.r",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r constant.numeric.float.decimal.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
@@ -506,8 +682,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": ", ",
|
||||
"t": "source.r",
|
||||
"c": ",",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r punctuation.separator.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -518,7 +705,7 @@
|
||||
},
|
||||
{
|
||||
"c": "2.0e10",
|
||||
"t": "source.r constant.numeric.r",
|
||||
"t": "source.r meta.function-call.r meta.function-call.arguments.r constant.numeric.float.decimal.r",
|
||||
"r": {
|
||||
"dark_plus": "constant.numeric: #B5CEA8",
|
||||
"light_plus": "constant.numeric: #09885A",
|
||||
@@ -529,7 +716,7 @@
|
||||
},
|
||||
{
|
||||
"c": ")",
|
||||
"t": "source.r",
|
||||
"t": "source.r meta.function-call.r punctuation.definition.parameters.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
@@ -539,7 +726,18 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "paste(",
|
||||
"c": "paste",
|
||||
"t": "source.r support.function.r",
|
||||
"r": {
|
||||
"dark_plus": "support.function: #DCDCAA",
|
||||
"light_plus": "support.function: #795E26",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "support.function: #DCDCAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
@@ -616,7 +814,18 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "paste(",
|
||||
"c": "paste",
|
||||
"t": "source.r support.function.r",
|
||||
"r": {
|
||||
"dark_plus": "support.function: #DCDCAA",
|
||||
"light_plus": "support.function: #795E26",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "support.function: #DCDCAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
@@ -693,7 +902,18 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "paste(",
|
||||
"c": "paste",
|
||||
"t": "source.r support.function.r",
|
||||
"r": {
|
||||
"dark_plus": "support.function: #DCDCAA",
|
||||
"light_plus": "support.function: #795E26",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "support.function: #DCDCAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "(",
|
||||
"t": "source.r",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
test/**
|
||||
@@ -1,22 +0,0 @@
|
||||
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
|
||||
[{
|
||||
"name": "textmate/ruby.tmbundle",
|
||||
"version": "0.0.0",
|
||||
"license": "TextMate Bundle License",
|
||||
"repositoryURL": "https://github.com/textmate/ruby.tmbundle",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) textmate-ruby.tmbundle project authors",
|
||||
"",
|
||||
"If not otherwise specified (see below), files in this folder fall under the following license: ",
|
||||
"",
|
||||
"Permission to copy, use, modify, sell and distribute this",
|
||||
"software is granted. This software is provided \"as is\" without",
|
||||
"express or implied warranty, and with no claim as to its",
|
||||
"suitability for any purpose.",
|
||||
"",
|
||||
"An exception is made for files in readable text which contain their own license information, ",
|
||||
"or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added ",
|
||||
"to the base-name name of the original file, and an extension of txt, html, or similar. For example ",
|
||||
"\"tidy\" is accompanied by \"tidy-license.txt\"."
|
||||
]
|
||||
}]
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"comments": {
|
||||
"lineComment": "#",
|
||||
"blockComment": [ "=begin", "=end" ]
|
||||
},
|
||||
"brackets": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
],
|
||||
"surroundingPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
],
|
||||
"indentationRules": {
|
||||
"increaseIndentPattern": "^\\s*((begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\\sdo\\b))\\b[^\\{;]*$",
|
||||
"decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)"
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "ruby",
|
||||
"version": "0.2.1",
|
||||
"publisher": "vscode",
|
||||
"engines": { "vscode": "*" },
|
||||
"scripts": {
|
||||
"update-grammar": "node ../../build/npm/update-grammar.js textmate/ruby.tmbundle Syntaxes/Ruby.plist ./syntaxes/ruby.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [{
|
||||
"id": "ruby",
|
||||
"extensions": [ ".rb", ".rbx", ".rjs", ".gemspec", ".rake", ".ru", ".erb" ],
|
||||
"filenames": [ "rakefile", "gemfile", "guardfile", "podfile", "capfile" ],
|
||||
"aliases": [ "Ruby", "rb" ],
|
||||
"firstLine": "^#!/.*\\bruby\\b",
|
||||
"configuration": "./language-configuration.json"
|
||||
}],
|
||||
"grammars": [{
|
||||
"language": "ruby",
|
||||
"scopeName": "source.ruby",
|
||||
"path": "./syntaxes/ruby.tmLanguage.json"
|
||||
}]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
# encoding: utf-8
|
||||
# Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
|
||||
# Changes may cause incorrect behavior and will be lost if the code is
|
||||
# regenerated.
|
||||
|
||||
module Azure::ARM::Scheduler
|
||||
#
|
||||
# A service client - single point of access to the REST API.
|
||||
#
|
||||
class SchedulerManagementClient < MsRestAzure::AzureServiceClient
|
||||
include Azure::ARM::Scheduler::Models
|
||||
include MsRestAzure
|
||||
|
||||
# @return job_collections
|
||||
attr_reader :job_collections
|
||||
|
||||
#
|
||||
# Creates initializes a new instance of the SchedulerManagementClient class.
|
||||
# @param credentials [MsRest::ServiceClientCredentials] credentials to authorize HTTP requests made by the service client.
|
||||
# @param base_url [String] the base URI of the service.
|
||||
# @param options [Array] filters to be applied to the HTTP requests.
|
||||
#
|
||||
def initialize(credentials, base_url = nil, options = nil)
|
||||
super(credentials, options)
|
||||
@base_url = base_url || 'https://management.azure.com'
|
||||
|
||||
fail ArgumentError, 'credentials is nil' if credentials.nil?
|
||||
fail ArgumentError, 'invalid type of credentials input parameter' unless credentials.is_a?(MsRest::ServiceClientCredentials)
|
||||
@credentials = credentials
|
||||
|
||||
@job_collections = JobCollections.new(self)
|
||||
@jobs = Jobs.new(self)
|
||||
@api_version = '2016-01-01'
|
||||
@long_running_operation_retry_timeout = 30
|
||||
@generate_client_request_id = true
|
||||
if MacOS.version >= :mavericks
|
||||
version = `#{MAVERICKS_PKG_PATH}/usr/bin/clang --version`
|
||||
else
|
||||
version = `/usr/bin/clang --version`
|
||||
end
|
||||
version = version[/clang-(\d+\.\d+\.\d+(\.\d+)?)/, 1] || "0"
|
||||
version < latest_version
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"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/textmate/shellscript.tmbundle/commit/ba95d7b742caef130911d878f42f66bdd80181e4",
|
||||
"version": "https://github.com/textmate/shellscript.tmbundle/commit/1c0cc0b904bb87b18b6987109e694f9d0058656d",
|
||||
"fileTypes": [
|
||||
"sh",
|
||||
"bash",
|
||||
@@ -771,6 +771,16 @@
|
||||
"match": "\\\\[`\\\\$]",
|
||||
"name": "constant.character.escape.shell"
|
||||
},
|
||||
{
|
||||
"begin": "(?<=^|;|&|\\s|`)(#)(?!\\{)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?=`)|\\n",
|
||||
"name": "comment.line.number-sign.shell"
|
||||
},
|
||||
{
|
||||
"include": "$self"
|
||||
}
|
||||
@@ -791,6 +801,16 @@
|
||||
},
|
||||
"name": "string.interpolated.dollar.shell",
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "(?<=^|;|&|\\s|\\()(#)(?!\\{)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?=\\))|\\n",
|
||||
"name": "comment.line.number-sign.shell"
|
||||
},
|
||||
{
|
||||
"include": "$self"
|
||||
}
|
||||
@@ -848,7 +868,7 @@
|
||||
"name": "keyword.control.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$|\\))",
|
||||
"name": "meta.scope.for-loop.shell",
|
||||
"patterns": [
|
||||
{
|
||||
@@ -866,7 +886,7 @@
|
||||
"name": "variable.other.loop.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$|\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.control.shell"
|
||||
@@ -886,7 +906,7 @@
|
||||
"name": "keyword.control.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$|\\))",
|
||||
"name": "meta.scope.while-loop.shell",
|
||||
"patterns": [
|
||||
{
|
||||
@@ -904,7 +924,7 @@
|
||||
"name": "variable.other.loop.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(done)(?=\\s|;|&|$|\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.control.shell"
|
||||
@@ -924,7 +944,7 @@
|
||||
"name": "keyword.control.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(esac)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(esac)(?=\\s|;|&|$|\\))",
|
||||
"name": "meta.scope.case-block.shell",
|
||||
"patterns": [
|
||||
{
|
||||
@@ -934,7 +954,7 @@
|
||||
"name": "keyword.control.shell"
|
||||
}
|
||||
},
|
||||
"end": "(?<=^|;|&|\\s)(?=(?:esac)(?:\\s|;|&|$))",
|
||||
"end": "(?<=^|;|&|\\s)(?=(?:esac)(?:\\s|;|&|$|\\)))",
|
||||
"name": "meta.scope.case-body.shell",
|
||||
"patterns": [
|
||||
{
|
||||
@@ -961,7 +981,7 @@
|
||||
}
|
||||
},
|
||||
"comment": "Restrict match to avoid matching in lines like `dd if=/dev/sda1 …`",
|
||||
"end": "(?<=^|;|&|\\s)(fi)(?=\\s|;|&|$)",
|
||||
"end": "(?<=^|;|&|\\s)(fi)(?=\\s|;|&|$|\\))",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "keyword.control.shell"
|
||||
|
||||
@@ -1,23 +1,8 @@
|
||||
// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS:
|
||||
|
||||
[{
|
||||
"name": "textmate/sql.tmbundle",
|
||||
"name": "Microsoft/vscode-mssql",
|
||||
"version": "0.0.0",
|
||||
"license": "TextMate Bundle License",
|
||||
"repositoryURL": "https://github.com/textmate/sql.tmbundle",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) textmate-sql.tmbundle project authors",
|
||||
"",
|
||||
"If not otherwise specified (see below), files in this folder fall under the following license: ",
|
||||
"",
|
||||
"Permission to copy, use, modify, sell and distribute this",
|
||||
"software is granted. This software is provided \"as is\" without",
|
||||
"express or implied warranty, and with no claim as to its",
|
||||
"suitability for any purpose.",
|
||||
"",
|
||||
"An exception is made for files in readable text which contain their own license information, ",
|
||||
"or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added ",
|
||||
"to the base-name name of the original file, and an extension of txt, html, or similar. For example ",
|
||||
"\"tidy\" is accompanied by \"tidy-license.txt\"."
|
||||
]
|
||||
"license": "MIT",
|
||||
"repositoryURL": "https://github.com/Microsoft/vscode-mssql"
|
||||
}]
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
"version": "0.1.0",
|
||||
"publisher": "vscode",
|
||||
"engines": { "vscode": "*" },
|
||||
"scripts": {
|
||||
"update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [{
|
||||
"id": "sql",
|
||||
@@ -13,7 +16,7 @@
|
||||
"grammars": [{
|
||||
"language": "sql",
|
||||
"scopeName": "source.sql",
|
||||
"path": "./syntaxes/SQL.plist"
|
||||
"path": "./syntaxes/sql.tmLanguage.json"
|
||||
}]
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"c": "CREATE",
|
||||
"t": "source.sql meta.create.sql keyword.other.create.sql",
|
||||
"t": "source.sql keyword.other.sql",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
@@ -11,51 +11,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.sql meta.create.sql",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "VIEW",
|
||||
"t": "source.sql meta.create.sql keyword.other.sql",
|
||||
"r": {
|
||||
"dark_plus": "keyword: #569CD6",
|
||||
"light_plus": "keyword: #0000FF",
|
||||
"dark_vs": "keyword: #569CD6",
|
||||
"light_vs": "keyword: #0000FF",
|
||||
"hc_black": "keyword: #569CD6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " ",
|
||||
"t": "source.sql meta.create.sql",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
"light_plus": "default: #000000",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "default: #FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": "METRIC_STATS",
|
||||
"t": "source.sql meta.create.sql entity.name.function.sql",
|
||||
"r": {
|
||||
"dark_plus": "entity.name.function: #DCDCAA",
|
||||
"light_plus": "entity.name.function: #795E26",
|
||||
"dark_vs": "default: #D4D4D4",
|
||||
"light_vs": "default: #000000",
|
||||
"hc_black": "entity.name.function: #DCDCAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"c": " (ID, MONTH, TEMP_C, RAIN_C) ",
|
||||
"c": " VIEW METRIC_STATS (ID, MONTH, TEMP_C, RAIN_C) ",
|
||||
"t": "source.sql",
|
||||
"r": {
|
||||
"dark_plus": "default: #D4D4D4",
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"foreground": "#6688cc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.embedded", "source.groovy.embedded"],
|
||||
"settings": {
|
||||
"background": "#000c18",
|
||||
"foreground": "#6688cc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Comment",
|
||||
"scope": "comment",
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "SQL Operations Studio-dark-theme",
|
||||
"type": "dark",
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "SQL Operations Studio-dark-theme",
|
||||
"type": "dark",
|
||||
"colors": {
|
||||
|
||||
// base
|
||||
"foreground": "#fffffe",
|
||||
"focusBorder": "#0E639C",
|
||||
"selection.background": "#3062d6",
|
||||
"selection.background": "#3062d6",
|
||||
|
||||
//text colors
|
||||
"textLinkForeground": "#30B4FF",
|
||||
@@ -42,8 +43,8 @@
|
||||
//List and trees
|
||||
"list.activeSelectionBackground": "#3062d6",
|
||||
"list.hoverBackground": "#444444",
|
||||
"pickerGroup.border": "#00BCF2",
|
||||
"activityBar.background": "#444444",
|
||||
"pickerGroup.border": "#00BCF2",
|
||||
"activityBar.background": "#444444",
|
||||
"sideBar.background": "#333333",
|
||||
"editorGroupHeader.tabsBackground": "#444444",
|
||||
"editor.background": "#212121",
|
||||
@@ -52,11 +53,11 @@
|
||||
"editorLink.activeForeground": "#30B4FF",
|
||||
"editorGroup.border": "#333333",
|
||||
"editorGroup.background": "#212121",
|
||||
"tab.activeBackground": "#212121",
|
||||
"tab.activeBackground": "#212121",
|
||||
"tab.activeForeground": "#ffffff",
|
||||
"tab.inactiveBackground": "#444444",
|
||||
"tab.inactiveForeground": "#888888",
|
||||
"tab.border": "#3c3c3c",
|
||||
"tab.border": "#3c3c3c",
|
||||
"panel.background": "#212121",
|
||||
"panel.border": "#515151",
|
||||
"panelTitle.activeForeground": "#ffffff",
|
||||
@@ -65,8 +66,7 @@
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
"foreground": "#ffffffff",
|
||||
"background": "#212121ff"
|
||||
"foreground": "#ffffffff"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "SQL Operations Studio-light-theme",
|
||||
"type": "light",
|
||||
"colors": {
|
||||
@@ -34,7 +35,7 @@
|
||||
"badge.foreground": "#ffffff",
|
||||
|
||||
//Input Control
|
||||
"input.background": "#EAEAEA00",
|
||||
"input.background": "#fffffe",
|
||||
"input.border": "#c8c8c8",
|
||||
"input.disabled.background": "#dcdcdc",
|
||||
"input.disabled.foreground": "#888888",
|
||||
@@ -56,7 +57,7 @@
|
||||
"editorGroupHeader.tabsBackground": "#f4f4f4",
|
||||
"editor.background": "#fffffe",
|
||||
"editor.foreground": "#212121",
|
||||
"editorWidget.background": "#C8C8C8",
|
||||
"editorWidget.background": "#dcdcdc",
|
||||
"editorLink.activeForeground": "#3062D6",
|
||||
"editorGroup.border": "#f4f4f4",
|
||||
"editorGroup.background": "#fffffe",
|
||||
@@ -77,8 +78,7 @@
|
||||
"tokenColors": [
|
||||
{
|
||||
"settings": {
|
||||
"foreground": "#212121ff",
|
||||
"background": "#fffffeff"
|
||||
"foreground": "#212121ff"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,273 +1,109 @@
|
||||
{
|
||||
"name": "Dark Visual Studio",
|
||||
"settings": [
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dark High Contrast",
|
||||
"include": "./hc_black_defaults.json",
|
||||
"colors": {
|
||||
"selection.background": "#008000",
|
||||
"editor.selectionBackground": "#FFFFFF"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": "emphasis",
|
||||
"name": "Function declarations",
|
||||
"scope": [
|
||||
"entity.name.function",
|
||||
"support.function",
|
||||
"support.constant.handlebars"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
"foreground": "#DCDCAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "strong",
|
||||
"name": "Types declaration and references",
|
||||
"scope": [
|
||||
"meta.return-type",
|
||||
"support.class",
|
||||
"support.type",
|
||||
"entity.name.type",
|
||||
"entity.name.class",
|
||||
"storage.type.cs",
|
||||
"storage.type.generic.cs",
|
||||
"storage.type.modifier.cs",
|
||||
"storage.type.variable.cs",
|
||||
"storage.type.annotation.java",
|
||||
"storage.type.generic.java",
|
||||
"storage.type.java",
|
||||
"storage.type.object.array.java",
|
||||
"storage.type.primitive.array.java",
|
||||
"storage.type.primitive.java",
|
||||
"storage.type.token.java",
|
||||
"storage.type.groovy",
|
||||
"storage.type.annotation.groovy",
|
||||
"storage.type.parameters.groovy",
|
||||
"storage.type.generic.groovy",
|
||||
"storage.type.object.array.groovy",
|
||||
"storage.type.primitive.array.groovy",
|
||||
"storage.type.primitive.groovy"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
"foreground": "#4EC9B0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "header",
|
||||
"name": "Types declaration and references, TS grammar specific",
|
||||
"scope": [
|
||||
"meta.type.cast.expr",
|
||||
"meta.type.new.expr",
|
||||
"support.constant.math",
|
||||
"support.constant.dom",
|
||||
"support.constant.json",
|
||||
"entity.other.inherited-class"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#000080"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"scope": "comment",
|
||||
"settings": {
|
||||
"foreground": "#7ca668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.language",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.numeric",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.regexp",
|
||||
"settings": {
|
||||
"foreground": "#b46695"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.rgb-value",
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.selector",
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.other.attribute-name",
|
||||
"settings": {
|
||||
"foreground": "#9cdcfe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.other.attribute-name.css",
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid",
|
||||
"settings": {
|
||||
"foreground": "#f44747"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.underline",
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.bold",
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.heading",
|
||||
"settings": {
|
||||
"foreground": "#6796e6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.italic",
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.inserted",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.deleted",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.changed",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.selector",
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "brackets of XML/HTML tags",
|
||||
"scope": "punctuation.definition.tag",
|
||||
"settings": {
|
||||
"foreground": "#808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.string",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.numeric",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.structure.dictionary.key.python",
|
||||
"settings": {
|
||||
"foreground": "#9cdcfe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.modifier",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.tag",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.value",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.regexp",
|
||||
"settings": {
|
||||
"foreground": "#d16969"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "JavaScript string interpolation ${}",
|
||||
"scope": "string.template-expression",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.type.property-name",
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
"foreground": "#4EC9B0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Control flow keywords",
|
||||
"scope": "keyword.control",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
"foreground": "#C586C0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.operator",
|
||||
"name": "Variable and parameter name",
|
||||
"scope": [
|
||||
"variable",
|
||||
"meta.definition.variable.name",
|
||||
"support.variable"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
"foreground": "#9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["keyword.operator.new", "keyword.operator.expression"],
|
||||
"name": "Object keys, TS grammar specific",
|
||||
"scope": [
|
||||
"meta.object-literal.key",
|
||||
"meta.object-literal.key entity.name.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
"foreground": "#9CDCFE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.other.unit",
|
||||
"name": "CSS property value",
|
||||
"scope": [
|
||||
"support.constant.property-value",
|
||||
"support.constant.font-name",
|
||||
"support.constant.media-type",
|
||||
"support.constant.media",
|
||||
"constant.other.color.rgb-value",
|
||||
"constant.other.rgb-value",
|
||||
"support.constant.color"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.function.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.sha.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coloring of the Java import and package identifiers",
|
||||
"scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coloring of the TS this",
|
||||
"scope": "variable.this",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
"foreground": "#CE9178"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "High Contrast Default Colors",
|
||||
"colors": {
|
||||
"editor.background": "#000000",
|
||||
"editor.foreground": "#FFFFFF",
|
||||
"editorIndentGuide.background": "#FFFFFF",
|
||||
"sideBarTitle.foreground": "#FFFFFF"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"meta.embedded",
|
||||
"source.groovy.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"background": "#000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "emphasis",
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "strong",
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.diff.header",
|
||||
"settings": {
|
||||
"foreground": "#000080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "comment",
|
||||
"settings": {
|
||||
"foreground": "#7ca668"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.language",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"constant.numeric",
|
||||
"constant.other.color.rgb-value",
|
||||
"constant.other.rgb-value",
|
||||
"support.constant.color"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.regexp",
|
||||
"settings": {
|
||||
"foreground": "#b46695"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.character",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag.css",
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.other.attribute-name",
|
||||
"settings": {
|
||||
"foreground": "#9cdcfe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.other.attribute-name.class.css",
|
||||
"entity.other.attribute-name.class.mixin.css",
|
||||
"entity.other.attribute-name.id.css",
|
||||
"entity.other.attribute-name.parent-selector.css",
|
||||
"entity.other.attribute-name.pseudo-class.css",
|
||||
"entity.other.attribute-name.pseudo-element.css",
|
||||
|
||||
"source.css.less entity.other.attribute-name.id",
|
||||
|
||||
"entity.other.attribute-name.attribute.scss",
|
||||
"entity.other.attribute-name.scss"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "invalid",
|
||||
"settings": {
|
||||
"foreground": "#f44747"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.underline",
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.bold",
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.heading",
|
||||
"settings": {
|
||||
"foreground": "#6796e6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.italic",
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.inserted",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.deleted",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.changed",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.selector",
|
||||
"settings": {
|
||||
"foreground": "#d7ba7d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "brackets of XML/HTML tags",
|
||||
"scope": [
|
||||
"punctuation.definition.tag"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#808080"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.string",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.preprocessor.numeric",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.structure.dictionary.key.python",
|
||||
"settings": {
|
||||
"foreground": "#9cdcfe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.modifier",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.tag",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.value",
|
||||
"settings": {
|
||||
"foreground": "#ce9178"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string.regexp",
|
||||
"settings": {
|
||||
"foreground": "#d16969"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "String interpolation",
|
||||
"scope": [
|
||||
"punctuation.definition.template-expression.begin",
|
||||
"punctuation.definition.template-expression.end",
|
||||
"punctuation.section.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Reset JavaScript string interpolation expression",
|
||||
"scope": [
|
||||
"meta.template.expression"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#ffffff"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"support.type.vendored.property-name",
|
||||
"support.type.property-name",
|
||||
"variable.css",
|
||||
"variable.scss",
|
||||
"variable.other.less",
|
||||
"source.coffee.embedded"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.control",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.operator",
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"keyword.operator.new",
|
||||
"keyword.operator.expression",
|
||||
"keyword.operator.cast",
|
||||
"keyword.operator.sizeof",
|
||||
"keyword.operator.logical.python"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword.other.unit",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.function.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.sha.git-rebase",
|
||||
"settings": {
|
||||
"foreground": "#b5cea8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coloring of the Java import and package identifiers",
|
||||
"scope": [
|
||||
"storage.modifier.import.java",
|
||||
"variable.language.wildcard.java",
|
||||
"storage.modifier.package.java"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#d4d4d4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "coloring of the TS this",
|
||||
"scope": "variable.language.this",
|
||||
"settings": {
|
||||
"foreground": "#569cd6"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -54,6 +54,13 @@
|
||||
"foreground": "#d3af86"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.embedded", "source.groovy.embedded"],
|
||||
"settings": {
|
||||
"background": "#221a0f",
|
||||
"foreground": "#d3af86"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Text",
|
||||
"scope": "variable.parameter.function",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user