mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-12 11:39:57 +01:00
Merge remote-tracking branch 'origin/master' into alex/minimap
This commit is contained in:
Vendored
+10
-3
@@ -7,11 +7,17 @@
|
||||
"name": "Unit Tests",
|
||||
"protocol": "legacy",
|
||||
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"runtimeExecutable": "${workspaceRoot}/.build/electron/Code - OSS.app/Contents/MacOS/Electron",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceRoot}/.build/electron/Code - OSS.exe"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceRoot}/.build/electron/code-oss"
|
||||
},
|
||||
"stopOnEntry": false,
|
||||
"args": [
|
||||
"--timeout",
|
||||
"999999"
|
||||
"2000"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {
|
||||
@@ -20,7 +26,8 @@
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/out/**/*.js"
|
||||
]
|
||||
],
|
||||
"preLaunchTask": "electron"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
|
||||
Vendored
+8
-1
@@ -47,7 +47,7 @@
|
||||
],
|
||||
"severity": "warning",
|
||||
"pattern": {
|
||||
"regexp": "(.*)\\[(\\d+),\\s(\\d+)\\]:\\s(.*)$", // (.*)\[(\d+), (\d+)\]: (.*)
|
||||
"regexp": "(.*)\\[(\\d+),\\s(\\d+)\\]:\\s(.*)$", // (.*)\[(\d+), (\d+)\]: (.*)
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
@@ -62,6 +62,13 @@
|
||||
],
|
||||
"showOutput": "always",
|
||||
"isTestCommand": true
|
||||
},
|
||||
{
|
||||
"taskName": "electron",
|
||||
"args": [
|
||||
"--no-color"
|
||||
],
|
||||
"showOutput": "never"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -40,8 +40,8 @@ const nodeModules = ['electron', 'original-fs']
|
||||
// Build
|
||||
|
||||
const builtInExtensions = [
|
||||
{ name: 'ms-vscode.node-debug', version: '1.10.6' },
|
||||
{ name: 'ms-vscode.node-debug2', version: '1.9.13' }
|
||||
{ name: 'ms-vscode.node-debug', version: '1.10.12' },
|
||||
{ name: 'ms-vscode.node-debug2', version: '1.10.0' }
|
||||
];
|
||||
|
||||
const vscodeEntryPoints = _.flatten([
|
||||
|
||||
@@ -44,6 +44,7 @@ function buildWin32Setup(cb) {
|
||||
NameVersion: product.win32NameVersion,
|
||||
ExeBasename: product.nameShort,
|
||||
RegValueName: product.win32RegValueName,
|
||||
ShellNameShort: product.win32ShellNameShort,
|
||||
AppMutex: product.win32MutexName,
|
||||
AppId: product.win32AppId,
|
||||
AppUserId: product.win32AppUserModelId,
|
||||
|
||||
@@ -772,16 +772,16 @@ Root: HKCR; Subkey: "{#RegValueName}SourceFile\shell\open\command"; ValueType: s
|
||||
|
||||
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\bin"; Tasks: addtopath; Check: NeedsAddPath(ExpandConstant('{app}\bin'))
|
||||
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#NameShort}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#ShellNameShort}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufiles
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\*\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: addcontextmenufiles
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#NameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#NameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\directory\background\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#NameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open with {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\Drive\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders
|
||||
Root: HKCU; Subkey: "SOFTWARE\Classes\Drive\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders
|
||||
|
||||
|
||||
+152
-36
@@ -21,6 +21,15 @@
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "git.init",
|
||||
"title": "%command.init%",
|
||||
"category": "Git",
|
||||
"icon": {
|
||||
"light": "resources/icons/light/git.svg",
|
||||
"dark": "resources/icons/dark/git.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.refresh",
|
||||
"title": "%command.refresh%",
|
||||
@@ -191,189 +200,296 @@
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "git.init",
|
||||
"when": "scmProvider == git && scmProviderState == norepo"
|
||||
},
|
||||
{
|
||||
"command": "git.refresh",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.openFile",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commit",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStaged",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedSigned",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAll",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllSigned",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.undoCommit",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.checkout",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.branch",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pull",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pullRebase",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.push",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pushTo",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.sync",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.publish",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.showOutput",
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
}
|
||||
],
|
||||
"scm/title": [
|
||||
{
|
||||
"command": "git.init",
|
||||
"group": "navigation",
|
||||
"when": "scmProvider == git && scmProviderState == norepo"
|
||||
},
|
||||
{
|
||||
"command": "git.commit",
|
||||
"group": "navigation",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.refresh",
|
||||
"group": "navigation",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.sync",
|
||||
"group": "1_sync",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pull",
|
||||
"group": "1_sync",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pullRebase",
|
||||
"group": "1_sync",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.push",
|
||||
"group": "1_sync",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.pushTo",
|
||||
"group": "1_sync",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.publish",
|
||||
"group": "2_publish",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStaged",
|
||||
"group": "3_commit",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStagedSigned",
|
||||
"group": "3_commit",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAll",
|
||||
"group": "3_commit",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.commitAllSigned",
|
||||
"group": "3_commit",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.undoCommit",
|
||||
"group": "3_commit",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"group": "4_stage",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
"group": "4_stage",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
},
|
||||
{
|
||||
"command": "git.showOutput",
|
||||
"group": "5_output",
|
||||
"when": "scmProvider == git"
|
||||
"when": "scmProvider == git && scmProviderState == idle"
|
||||
}
|
||||
],
|
||||
"scm/resourceGroup/context": [
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.unstageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.cleanAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.stageAll",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
}
|
||||
],
|
||||
"scm/resource/context": [
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == merge",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == merge",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "git.openFile",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.unstage",
|
||||
"when": "scmProvider == git && scmResourceGroup == index",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == index",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.openChange",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "git.openFile",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "1_modification"
|
||||
},
|
||||
{
|
||||
"command": "git.clean",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "git.stage",
|
||||
"when": "scmProvider == git && scmResourceGroup == workingTree",
|
||||
"when": "scmProvider == git && scmProviderState == idle && scmResourceGroup == workingTree",
|
||||
"group": "inline"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"command.init": "Initialize Git Repository",
|
||||
"command.refresh": "Refresh",
|
||||
"command.openChange": "Open Change",
|
||||
"command.openFile": "Open File",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M27.459 14.902l-10.439-10.439c-.296-.294-.672-.452-1.089-.452-.417 0-.793.157-1.089.452l-2.248 2.247 2.549 2.549c.249-.112.522-.177.813-.177 1.106 0 2.002.896 2.002 2.002 0 .291-.064.565-.176.814l2.311 2.336c.25-.111.633-.234.923-.234 1.106 0 2 .911 2 2.016s-.894 1.969-2 1.969c-1.105-.001-2.016-.751-2.016-1.985 0-.28.016-.462.119-.704l-2.373-2.374-.023.007v6.274c.747.295 1.277 1.026 1.277 1.875 0 1.105-.878 2.016-1.984 2.016-1.104 0-2.031-.926-2.031-2.031 0-.846.535-1.564 1.28-1.857l.001-6.25c-.762-.282-1.309-1.009-1.309-1.871 0-.28.059-.546.162-.788l-2.555-2.557-7.115 7.114c-.599.601-.601 1.576.001 2.178l10.44 10.518c.296.295.671.45 1.089.45.415 0 .796-.159 1.089-.45l10.391-10.471c.601-.599.599-1.576 0-2.177z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 812 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><defs><clipPath><path d="M.06 91.886h91.828v-91.886h-91.828v91.886z"/></clipPath><clipPath id="a"><path d="M0 0h92v92h-92v-92z"/></clipPath></defs><path d="M28.497 14.84l-11.354-11.353c-.653-.654-1.714-.654-2.368 0l-2.357 2.358 2.99 2.991c.695-.235 1.492-.077 2.046.477.557.558.713 1.361.473 2.059l2.882 2.882c.698-.241 1.502-.085 2.059.473.778.778.778 2.039 0 2.818-.779.779-2.04.779-2.819 0-.586-.586-.73-1.446-.434-2.167l-2.688-2.688v7.074c.19.094.369.219.527.377.778.778.778 2.039 0 2.819-.778.778-2.04.778-2.818 0-.778-.779-.778-2.04 0-2.819.192-.192.415-.338.653-.435v-7.14c-.237-.097-.46-.241-.653-.435-.589-.589-.731-1.455-.429-2.179l-2.948-2.949-7.785 7.785c-.654.655-.654 1.715 0 2.369l11.354 11.353c.654.654 1.714.654 2.369 0l11.3-11.301c.654-.654.654-1.715 0-2.369" fill="#424242" clip-path="url(#a)"/></svg>
|
||||
|
After Width: | Height: | Size: 883 B |
@@ -113,13 +113,13 @@ export class CommandCenter {
|
||||
const right = this.getRightResource(resource);
|
||||
const title = this.getTitle(resource);
|
||||
|
||||
if (!left) {
|
||||
if (!right) {
|
||||
// TODO
|
||||
console.error('oh no');
|
||||
return;
|
||||
}
|
||||
if (!right) {
|
||||
// TODO
|
||||
console.error('oh no');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!left) {
|
||||
return await commands.executeCommand<void>('vscode.open', right);
|
||||
}
|
||||
|
||||
@@ -130,11 +130,11 @@ export class CommandCenter {
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_RENAMED:
|
||||
return resource.uri.with({ scheme: 'git', query: 'HEAD' });
|
||||
return resource.original.with({ scheme: 'git', query: 'HEAD' });
|
||||
|
||||
case Status.MODIFIED:
|
||||
const uriString = resource.uri.toString();
|
||||
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.uri.toString() === uriString);
|
||||
const uriString = resource.original.toString();
|
||||
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.original.toString() === uriString);
|
||||
|
||||
if (indexStatus) {
|
||||
return resource.uri.with({ scheme: 'git' });
|
||||
@@ -149,6 +149,8 @@ export class CommandCenter {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_ADDED:
|
||||
case Status.INDEX_COPIED:
|
||||
return resource.uri.with({ scheme: 'git' });
|
||||
|
||||
case Status.INDEX_RENAMED:
|
||||
return resource.uri.with({ scheme: 'git' });
|
||||
|
||||
@@ -159,6 +161,15 @@ export class CommandCenter {
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
const uriString = resource.uri.toString();
|
||||
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.uri.toString() === uriString);
|
||||
|
||||
if (indexStatus && indexStatus.rename) {
|
||||
return indexStatus.rename;
|
||||
}
|
||||
|
||||
return resource.uri;
|
||||
|
||||
case Status.BOTH_MODIFIED:
|
||||
return resource.uri;
|
||||
}
|
||||
@@ -179,6 +190,11 @@ export class CommandCenter {
|
||||
return '';
|
||||
}
|
||||
|
||||
@command('git.init')
|
||||
async init(): Promise<void> {
|
||||
await this.model.init();
|
||||
}
|
||||
|
||||
@command('git.openFile')
|
||||
async openFile(uri: Uri): Promise<void> {
|
||||
const scmResource = resolveGitResource(uri);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
'use strict';
|
||||
|
||||
import { workspace, window, languages, Disposable, Uri, HoverProvider, Hover, TextEditor, Position, TextDocument, Range, TextEditorDecorationType, WorkspaceEdit } from 'vscode';
|
||||
import { Model } from './model';
|
||||
import { filterEvent } from './util';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
@@ -22,7 +21,7 @@ interface Diagnostic {
|
||||
message: string;
|
||||
}
|
||||
|
||||
// TODO@Joao: hover dissapears if editor is scrolled
|
||||
// TODO@Joao: hover disappears if editor is scrolled
|
||||
export class CommitController implements HoverProvider {
|
||||
|
||||
private visibleTextEditorsDisposable: Disposable;
|
||||
@@ -53,7 +52,7 @@ export class CommitController implements HoverProvider {
|
||||
workspace.applyEdit(edit);
|
||||
}
|
||||
|
||||
constructor(private model: Model) {
|
||||
constructor() {
|
||||
this.visibleTextEditorsDisposable = window.onDidChangeVisibleTextEditors(this.onVisibleTextEditors, this);
|
||||
this.onVisibleTextEditors(window.visibleTextEditors);
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
import { workspace, Uri, Disposable, Event, EventEmitter } from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { Git } from './git';
|
||||
import { Model } from './model';
|
||||
|
||||
export class GitContentProvider {
|
||||
|
||||
@@ -18,7 +17,7 @@ export class GitContentProvider {
|
||||
|
||||
private uris = new Set<Uri>();
|
||||
|
||||
constructor(private git: Git, private rootPath: string, onGitChange: Event<Uri>) {
|
||||
constructor(private model: Model, onGitChange: Event<Uri>) {
|
||||
this.disposables.push(
|
||||
onGitChange(this.fireChangeEvents, this),
|
||||
workspace.registerTextDocumentContentProvider('git', this)
|
||||
@@ -32,19 +31,10 @@ export class GitContentProvider {
|
||||
}
|
||||
|
||||
async provideTextDocumentContent(uri: Uri): Promise<string> {
|
||||
const treeish = uri.query;
|
||||
const relativePath = path.relative(this.rootPath, uri.fsPath).replace(/\\/g, '/');
|
||||
|
||||
try {
|
||||
const result = await this.git.exec(this.rootPath, ['show', `${treeish}:${relativePath}`]);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
this.uris.delete(uri);
|
||||
return '';
|
||||
}
|
||||
|
||||
const result = await this.model.show(uri.query, uri);
|
||||
this.uris.add(uri);
|
||||
return result.stdout;
|
||||
return result;
|
||||
} catch (err) {
|
||||
this.uris.delete(uri);
|
||||
return '';
|
||||
|
||||
+11
-11
@@ -289,6 +289,11 @@ export class Git {
|
||||
return new Repository(this, repository, env);
|
||||
}
|
||||
|
||||
async getRepositoryRoot(path: string): Promise<string> {
|
||||
const result = await this.exec(path, ['rev-parse', '--show-toplevel']);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
|
||||
async exec(cwd: string, args: string[], options: any = {}): Promise<IExecutionResult> {
|
||||
options = assign({ cwd }, options || {});
|
||||
return await this._exec(args, options);
|
||||
@@ -380,7 +385,7 @@ export class Repository {
|
||||
|
||||
constructor(
|
||||
private _git: Git,
|
||||
private repository: string,
|
||||
private repositoryRoot: string,
|
||||
private env: any = {}
|
||||
) { }
|
||||
|
||||
@@ -388,8 +393,8 @@ export class Repository {
|
||||
return this._git;
|
||||
}
|
||||
|
||||
get path(): string {
|
||||
return this.repository;
|
||||
get root(): string {
|
||||
return this.repositoryRoot;
|
||||
}
|
||||
|
||||
// TODO@Joao: rename to exec
|
||||
@@ -397,14 +402,14 @@ export class Repository {
|
||||
options.env = assign({}, options.env || {});
|
||||
options.env = assign(options.env, this.env);
|
||||
|
||||
return await this.git.exec(this.repository, args, options);
|
||||
return await this.git.exec(this.repositoryRoot, args, options);
|
||||
}
|
||||
|
||||
stream(args: string[], options: any = {}): cp.ChildProcess {
|
||||
options.env = assign({}, options.env || {});
|
||||
options.env = assign(options.env, this.env);
|
||||
|
||||
return this.git.stream(this.repository, args, options);
|
||||
return this.git.stream(this.repositoryRoot, args, options);
|
||||
}
|
||||
|
||||
spawn(args: string[], options: any = {}): cp.ChildProcess {
|
||||
@@ -709,11 +714,6 @@ export class Repository {
|
||||
await this.push();
|
||||
}
|
||||
|
||||
async getRoot(): Promise<string> {
|
||||
const result = await this.run(['rev-parse', '--show-toplevel']);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
|
||||
async getStatus(): Promise<IFileStatus[]> {
|
||||
const executionResult = await this.run(['status', '-z', '-u']);
|
||||
const status = executionResult.stdout;
|
||||
@@ -861,7 +861,7 @@ export class Repository {
|
||||
.replace(/^~([^\/]*)\//, (_, user) => `${user ? path.join(path.dirname(homedir), user) : homedir}/`);
|
||||
|
||||
if (!path.isAbsolute(templatePath)) {
|
||||
templatePath = path.join(this.repository, templatePath);
|
||||
templatePath = path.join(this.repositoryRoot, templatePath);
|
||||
}
|
||||
|
||||
const raw = await readfile(templatePath, 'utf8');
|
||||
|
||||
@@ -41,17 +41,15 @@ async function init(disposables: Disposable[]): Promise<void> {
|
||||
const pathHint = workspace.getConfiguration('git').get<string>('path');
|
||||
const info = await findGit(pathHint);
|
||||
const git = new Git({ gitPath: info.path, version: info.version });
|
||||
const repository = git.open(rootPath);
|
||||
const repositoryRoot = await repository.getRoot();
|
||||
const model = new Model(repositoryRoot, repository, onWorkspaceChange);
|
||||
const model = new Model(git, rootPath, onWorkspaceChange);
|
||||
|
||||
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
|
||||
git.onOutput(str => outputChannel.append(str), null, disposables);
|
||||
|
||||
const commitHandler = new CommitController(model);
|
||||
const commitHandler = new CommitController();
|
||||
const commandCenter = new CommandCenter(model, outputChannel);
|
||||
const provider = new GitSCMProvider(model, commandCenter);
|
||||
const contentProvider = new GitContentProvider(git, rootPath, onGitChange);
|
||||
const contentProvider = new GitContentProvider(model, onGitChange);
|
||||
const checkoutStatusBar = new CheckoutStatusBar(model);
|
||||
const syncStatusBar = new SyncStatusBar(model);
|
||||
const autoFetcher = new AutoFetcher(model);
|
||||
@@ -66,7 +64,8 @@ async function init(disposables: Disposable[]): Promise<void> {
|
||||
checkoutStatusBar,
|
||||
syncStatusBar,
|
||||
autoFetcher,
|
||||
mergeDecorator
|
||||
mergeDecorator,
|
||||
model
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+145
-51
@@ -6,8 +6,8 @@
|
||||
'use strict';
|
||||
|
||||
import { Uri, EventEmitter, Event, SCMResource, SCMResourceDecorations, SCMResourceGroup, Disposable, window, workspace } from 'vscode';
|
||||
import { Repository, Ref, Branch, Remote, PushOptions, Commit } from './git';
|
||||
import { anyEvent, eventToPromise, filterEvent, mapEvent } from './util';
|
||||
import { Git, Repository, Ref, Branch, Remote, PushOptions, Commit, GitErrorCodes, GitError } from './git';
|
||||
import { anyEvent, eventToPromise, filterEvent, mapEvent, EmptyDisposable, combinedDisposable } from './util';
|
||||
import { memoize, throttle, debounce } from './decorators';
|
||||
import { watch } from './watch';
|
||||
import * as path from 'path';
|
||||
@@ -20,6 +20,12 @@ function getIconUri(iconName: string, theme: string): Uri {
|
||||
return Uri.file(path.join(iconsRootPath, theme, `${iconName}.svg`));
|
||||
}
|
||||
|
||||
export enum State {
|
||||
Uninitialized,
|
||||
Idle,
|
||||
NotAGitRepository
|
||||
}
|
||||
|
||||
export enum Status {
|
||||
INDEX_MODIFIED,
|
||||
INDEX_ADDED,
|
||||
@@ -43,8 +49,17 @@ export enum Status {
|
||||
|
||||
export class Resource implements SCMResource {
|
||||
|
||||
get uri(): Uri { return this._uri; }
|
||||
get uri(): Uri {
|
||||
if (this.rename && (this._type === Status.MODIFIED || this._type === Status.DELETED || this._type === Status.INDEX_RENAMED)) {
|
||||
return this.rename;
|
||||
}
|
||||
|
||||
return this._uri;
|
||||
}
|
||||
|
||||
get type(): Status { return this._type; }
|
||||
get original(): Uri { return this._uri; }
|
||||
get rename(): Uri | undefined { return this._rename; }
|
||||
|
||||
private static Icons = {
|
||||
light: {
|
||||
@@ -110,8 +125,8 @@ export class Resource implements SCMResource {
|
||||
return { strikeThrough: this.strikeThrough, light, dark };
|
||||
}
|
||||
|
||||
constructor(private _uri: Uri, private _type: Status) {
|
||||
|
||||
constructor(private _uri: Uri, private _type: Status, private _rename?: Uri) {
|
||||
// console.log(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +145,7 @@ export class MergeGroup extends ResourceGroup {
|
||||
|
||||
static readonly ID = 'merge';
|
||||
|
||||
constructor(resources: Resource[]) {
|
||||
constructor(resources: Resource[] = []) {
|
||||
super(MergeGroup.ID, localize('merge changes', "Merge Changes"), resources);
|
||||
}
|
||||
}
|
||||
@@ -139,7 +154,7 @@ export class IndexGroup extends ResourceGroup {
|
||||
|
||||
static readonly ID = 'index';
|
||||
|
||||
constructor(resources: Resource[]) {
|
||||
constructor(resources: Resource[] = []) {
|
||||
super(IndexGroup.ID, localize('staged changes', "Staged Changes"), resources);
|
||||
}
|
||||
}
|
||||
@@ -148,7 +163,7 @@ export class WorkingTreeGroup extends ResourceGroup {
|
||||
|
||||
static readonly ID = 'workingTree';
|
||||
|
||||
constructor(resources: Resource[]) {
|
||||
constructor(resources: Resource[] = []) {
|
||||
super(WorkingTreeGroup.ID, localize('changes', "Changes"), resources);
|
||||
}
|
||||
}
|
||||
@@ -166,6 +181,8 @@ export enum Operation {
|
||||
Pull = 1 << 9,
|
||||
Push = 1 << 10,
|
||||
Sync = 1 << 11,
|
||||
Init = 1 << 12,
|
||||
Show = 1 << 13
|
||||
}
|
||||
|
||||
export interface Operations {
|
||||
@@ -202,10 +219,18 @@ export interface CommitOptions {
|
||||
signoff?: boolean;
|
||||
}
|
||||
|
||||
export class Model {
|
||||
export class Model implements Disposable {
|
||||
|
||||
private _onDidChange = new EventEmitter<SCMResourceGroup[]>();
|
||||
readonly onDidChange: Event<SCMResourceGroup[]> = this._onDidChange.event;
|
||||
private _onDidChangeState = new EventEmitter<State>();
|
||||
readonly onDidChangeState: Event<State> = this._onDidChangeState.event;
|
||||
|
||||
private _onDidChangeResources = new EventEmitter<SCMResourceGroup[]>();
|
||||
readonly onDidChangeResources: Event<SCMResourceGroup[]> = this._onDidChangeResources.event;
|
||||
|
||||
@memoize
|
||||
get onDidChange(): Event<void> {
|
||||
return anyEvent<any>(this.onDidChangeState, this.onDidChangeResources);
|
||||
}
|
||||
|
||||
private _onRunOperation = new EventEmitter<Operation>();
|
||||
readonly onRunOperation: Event<Operation> = this._onRunOperation.event;
|
||||
@@ -243,38 +268,6 @@ export class Model {
|
||||
return result;
|
||||
}
|
||||
|
||||
private _operations = new OperationsImpl();
|
||||
get operations(): Operations { return this._operations; }
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(
|
||||
private _repositoryRoot: string,
|
||||
private repository: Repository,
|
||||
onWorkspaceChange: Event<Uri>
|
||||
) {
|
||||
/* We use the native Node `watch` for faster, non debounced events.
|
||||
* That way we hopefully get the events during the operations we're
|
||||
* performing, thus sparing useless `git status` calls to refresh
|
||||
* the model's state.
|
||||
*/
|
||||
const gitPath = path.join(_repositoryRoot, '.git');
|
||||
const { event, disposable } = watch(gitPath);
|
||||
const onGitChange = mapEvent(event, ({ filename }) => Uri.file(path.join(gitPath, filename)));
|
||||
const onRelevantGitChange = filterEvent(onGitChange, uri => !/\/\.git\/index\.lock$/.test(uri.fsPath));
|
||||
onRelevantGitChange(this.onFSChange, this, this.disposables);
|
||||
this.disposables.push(disposable);
|
||||
|
||||
const onNonGitChange = filterEvent(onWorkspaceChange, uri => !/\/\.git\//.test(uri.fsPath));
|
||||
onNonGitChange(this.onFSChange, this, this.disposables);
|
||||
|
||||
this.status();
|
||||
}
|
||||
|
||||
get repositoryRoot(): string {
|
||||
return this._repositoryRoot;
|
||||
}
|
||||
|
||||
private _HEAD: Branch | undefined;
|
||||
get HEAD(): Branch | undefined {
|
||||
return this._HEAD;
|
||||
@@ -290,6 +283,46 @@ export class Model {
|
||||
return this._remotes;
|
||||
}
|
||||
|
||||
private _operations = new OperationsImpl();
|
||||
get operations(): Operations { return this._operations; }
|
||||
|
||||
private repository: Repository;
|
||||
|
||||
private _state = State.Uninitialized;
|
||||
get state(): State { return this._state; }
|
||||
set state(state: State) {
|
||||
this._state = state;
|
||||
this._onDidChangeState.fire(state);
|
||||
|
||||
this._HEAD = undefined;
|
||||
this._refs = [];
|
||||
this._remotes = [];
|
||||
this._mergeGroup = new MergeGroup();
|
||||
this._indexGroup = new IndexGroup();
|
||||
this._workingTreeGroup = new WorkingTreeGroup();
|
||||
this._onDidChangeResources.fire(this.resources);
|
||||
}
|
||||
|
||||
private repositoryDisposable: Disposable = EmptyDisposable;
|
||||
|
||||
constructor(
|
||||
private git: Git,
|
||||
private rootPath: string,
|
||||
private onWorkspaceChange: Event<Uri>
|
||||
) {
|
||||
this.status();
|
||||
}
|
||||
|
||||
@throttle
|
||||
async init(): Promise<void> {
|
||||
if (this.state !== State.NotAGitRepository) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.repository.init();
|
||||
await this.status();
|
||||
}
|
||||
|
||||
@throttle
|
||||
async status(): Promise<void> {
|
||||
await this.run(Operation.Status);
|
||||
@@ -389,14 +422,40 @@ export class Model {
|
||||
await this.run(Operation.Sync, () => this.repository.sync());
|
||||
}
|
||||
|
||||
private async run(operation: Operation, fn: () => Promise<void> = () => Promise.resolve()): Promise<void> {
|
||||
@throttle
|
||||
async show(ref: string, uri: Uri): Promise<string> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const relativePath = path.relative(this.repository.root, uri.fsPath).replace(/\\/g, '/');
|
||||
const result = await this.repository.git.exec(this.repository.root, ['show', `${ref}:${relativePath}`]);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
throw new GitError({
|
||||
message: localize('cantshow', "Could not show object"),
|
||||
exitCode: result.exitCode
|
||||
});
|
||||
}
|
||||
|
||||
return result.stdout;
|
||||
});
|
||||
}
|
||||
|
||||
private async run<T>(operation: Operation, runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
|
||||
return window.withScmProgress(async () => {
|
||||
this._operations = this._operations.start(operation);
|
||||
this._onRunOperation.fire(operation);
|
||||
|
||||
try {
|
||||
await fn();
|
||||
await this.assertIdleState();
|
||||
const result = await runOperation();
|
||||
await this.update();
|
||||
return result;
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
|
||||
this.repositoryDisposable.dispose();
|
||||
this.state = State.NotAGitRepository;
|
||||
}
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
this._operations = this._operations.end(operation);
|
||||
this._onDidRunOperation.fire(operation);
|
||||
@@ -404,6 +463,37 @@ export class Model {
|
||||
});
|
||||
}
|
||||
|
||||
/* We use the native Node `watch` for faster, non debounced events.
|
||||
* That way we hopefully get the events during the operations we're
|
||||
* performing, thus sparing useless `git status` calls to refresh
|
||||
* the model's state.
|
||||
*/
|
||||
private async assertIdleState(): Promise<void> {
|
||||
if (this.state === State.Idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.repositoryDisposable.dispose();
|
||||
|
||||
const disposables: Disposable[] = [];
|
||||
const repositoryRoot = await this.git.getRepositoryRoot(this.rootPath);
|
||||
this.repository = this.git.open(repositoryRoot);
|
||||
|
||||
const dotGitPath = path.join(repositoryRoot, '.git');
|
||||
const { event, disposable: watcher } = watch(dotGitPath);
|
||||
disposables.push(watcher);
|
||||
|
||||
const onGitChange = mapEvent(event, ({ filename }) => Uri.file(path.join(dotGitPath, filename)));
|
||||
const onRelevantGitChange = filterEvent(onGitChange, uri => !/\/\.git\/index\.lock$/.test(uri.fsPath));
|
||||
onRelevantGitChange(this.onFSChange, this, disposables);
|
||||
|
||||
const onNonGitChange = filterEvent(this.onWorkspaceChange, uri => !/\/\.git\//.test(uri.fsPath));
|
||||
onNonGitChange(this.onFSChange, this, disposables);
|
||||
|
||||
this.repositoryDisposable = combinedDisposable(disposables);
|
||||
this.state = State.Idle;
|
||||
}
|
||||
|
||||
@throttle
|
||||
private async update(): Promise<void> {
|
||||
const status = await this.repository.getStatus();
|
||||
@@ -434,7 +524,8 @@ export class Model {
|
||||
const merge: Resource[] = [];
|
||||
|
||||
status.forEach(raw => {
|
||||
const uri = Uri.file(path.join(this.repositoryRoot, raw.path));
|
||||
const uri = Uri.file(path.join(this.repository.root, raw.path));
|
||||
const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined;
|
||||
|
||||
switch (raw.x + raw.y) {
|
||||
case '??': return workingTree.push(new Resource(uri, Status.UNTRACKED));
|
||||
@@ -454,21 +545,20 @@ export class Model {
|
||||
case 'M': index.push(new Resource(uri, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break;
|
||||
case 'A': index.push(new Resource(uri, Status.INDEX_ADDED)); break;
|
||||
case 'D': index.push(new Resource(uri, Status.INDEX_DELETED)); break;
|
||||
case 'R': index.push(new Resource(uri, Status.INDEX_RENAMED/*, raw.rename*/)); break;
|
||||
case 'R': index.push(new Resource(uri, Status.INDEX_RENAMED, renameUri)); break;
|
||||
case 'C': index.push(new Resource(uri, Status.INDEX_COPIED)); break;
|
||||
}
|
||||
|
||||
switch (raw.y) {
|
||||
case 'M': workingTree.push(new Resource(uri, Status.MODIFIED/*, raw.rename*/)); break;
|
||||
case 'D': workingTree.push(new Resource(uri, Status.DELETED/*, raw.rename*/)); break;
|
||||
case 'M': workingTree.push(new Resource(uri, Status.MODIFIED, renameUri)); break;
|
||||
case 'D': workingTree.push(new Resource(uri, Status.DELETED, renameUri)); break;
|
||||
}
|
||||
});
|
||||
|
||||
this._mergeGroup = new MergeGroup(merge);
|
||||
this._indexGroup = new IndexGroup(index);
|
||||
this._workingTreeGroup = new WorkingTreeGroup(workingTree);
|
||||
|
||||
this._onDidChange.fire(this.resources);
|
||||
this._onDidChangeResources.fire(this.resources);
|
||||
}
|
||||
|
||||
private onFSChange(uri: Uri): void {
|
||||
@@ -503,4 +593,8 @@ export class Model {
|
||||
await eventToPromise(this.onDidRunOperation);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.repositoryDisposable.dispose();
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,31 @@
|
||||
'use strict';
|
||||
|
||||
import { scm, Uri, Disposable, SCMProvider, SCMResourceGroup, Event, ProviderResult, workspace } from 'vscode';
|
||||
import { Model, Resource, ResourceGroup } from './model';
|
||||
import { Model, Resource, ResourceGroup, State } from './model';
|
||||
import { CommandCenter } from './commands';
|
||||
import { mapEvent } from './util';
|
||||
|
||||
export class GitSCMProvider implements SCMProvider {
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
get resources(): SCMResourceGroup[] { return this.model.resources; }
|
||||
get onDidChange(): Event<SCMResourceGroup[]> { return this.model.onDidChange; }
|
||||
|
||||
get onDidChange(): Event<SCMResourceGroup[]> {
|
||||
return mapEvent(this.model.onDidChange, () => this.model.resources);
|
||||
}
|
||||
|
||||
get label(): string { return 'Git'; }
|
||||
|
||||
get state(): string {
|
||||
switch (this.model.state) {
|
||||
case State.Uninitialized: return 'uninitialized';
|
||||
case State.Idle: return 'idle';
|
||||
case State.NotAGitRepository: return 'norepo';
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
||||
get count(): number {
|
||||
const countBadge = workspace.getConfiguration('git').get<string>('countBadge');
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ export class CheckoutStatusBar {
|
||||
const HEAD = this.model.HEAD;
|
||||
|
||||
if (!HEAD) {
|
||||
this.raw.command = '';
|
||||
this.raw.color = 'rgb(100, 100, 100)';
|
||||
this.raw.text = 'unknown';
|
||||
this.raw.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,6 +46,7 @@ export class CheckoutStatusBar {
|
||||
(this.model.workingTreeGroup.resources.length > 0 ? '*' : '') +
|
||||
(this.model.indexGroup.resources.length > 0 ? '+' : '') +
|
||||
(this.model.mergeGroup.resources.length > 0 ? '!' : '');
|
||||
this.raw.show();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -28,6 +28,8 @@ export function combinedDisposable(disposables: IDisposable[]): IDisposable {
|
||||
return toDisposable(() => dispose(disposables));
|
||||
}
|
||||
|
||||
export const EmptyDisposable = toDisposable(() => null);
|
||||
|
||||
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export function activate(context: ExtensionContext) {
|
||||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions, true);
|
||||
let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions);
|
||||
let disposable = client.start();
|
||||
context.subscriptions.push(disposable);
|
||||
client.onReady().then(() => {
|
||||
|
||||
@@ -17,7 +17,6 @@ import URI from './utils/uri';
|
||||
import * as URL from 'url';
|
||||
import Strings = require('./utils/strings');
|
||||
import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService } from 'vscode-json-languageservice';
|
||||
import { ProjectJSONContribution } from './jsoncontributions/projectJSONContribution';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
@@ -119,9 +118,7 @@ let schemaRequestService = (uri: string): Thenable<string> => {
|
||||
let languageService = getLanguageService({
|
||||
schemaRequestService,
|
||||
workspaceContext,
|
||||
contributions: [
|
||||
new ProjectJSONContribution()
|
||||
]
|
||||
contributions: []
|
||||
});
|
||||
|
||||
// The settings interface describes the server relevant settings part
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { MarkedString, CompletionItemKind, CompletionItem, InsertTextFormat } from 'vscode-languageserver';
|
||||
import Strings = require('../utils/strings');
|
||||
import { XHRResponse, getErrorStatusDescription, xhr } from 'request-light';
|
||||
import { JSONWorkerContribution, JSONPath, CompletionsCollector } from 'vscode-json-languageservice';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
||||
const FEED_INDEX_URL = 'https://api.nuget.org/v3/index.json';
|
||||
const LIMIT = 30;
|
||||
const RESOLVE_ID = 'ProjectJSONContribution-';
|
||||
|
||||
const CACHE_EXPIRY = 1000 * 60 * 5; // 5 minutes
|
||||
|
||||
interface NugetServices {
|
||||
'SearchQueryService'?: string;
|
||||
'SearchAutocompleteService'?: string;
|
||||
'PackageBaseAddress/3.0.0'?: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export class ProjectJSONContribution implements JSONWorkerContribution {
|
||||
|
||||
private cachedProjects: { [id: string]: { version: string, description: string, time: number } } = {};
|
||||
private cacheSize: number = 0;
|
||||
private nugetIndexPromise: Thenable<NugetServices>;
|
||||
|
||||
public constructor() {
|
||||
}
|
||||
|
||||
private isProjectJSONFile(resource: string): boolean {
|
||||
return Strings.endsWith(resource, '/project.json');
|
||||
}
|
||||
|
||||
private completeWithCache(id: string, item: CompletionItem): boolean {
|
||||
let entry = this.cachedProjects[id];
|
||||
if (entry) {
|
||||
if (new Date().getTime() - entry.time > CACHE_EXPIRY) {
|
||||
delete this.cachedProjects[id];
|
||||
this.cacheSize--;
|
||||
return false;
|
||||
}
|
||||
let insertTextValue = item.insertText;
|
||||
item.detail = entry.version;
|
||||
item.documentation = entry.description;
|
||||
item.insertText = insertTextValue.replace(/\$1/, '${1:' + entry.version + '}');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private addCached(id: string, version: string, description: string) {
|
||||
this.cachedProjects[id] = { version, description, time: new Date().getTime() };
|
||||
this.cacheSize++;
|
||||
if (this.cacheSize > 50) {
|
||||
let currentTime = new Date().getTime();
|
||||
for (let id in this.cachedProjects) {
|
||||
let entry = this.cachedProjects[id];
|
||||
if (currentTime - entry.time > CACHE_EXPIRY) {
|
||||
delete this.cachedProjects[id];
|
||||
this.cacheSize--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getNugetIndex(): Thenable<NugetServices> {
|
||||
if (!this.nugetIndexPromise) {
|
||||
this.nugetIndexPromise = this.makeJSONRequest<any>(FEED_INDEX_URL).then(indexContent => {
|
||||
let services: NugetServices = {};
|
||||
if (indexContent && Array.isArray(indexContent.resources)) {
|
||||
let resources = <any[]>indexContent.resources;
|
||||
for (let i = resources.length - 1; i >= 0; i--) {
|
||||
let type = resources[i]['@type'];
|
||||
let id = resources[i]['@id'];
|
||||
if (type && id) {
|
||||
services[type] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return services;
|
||||
});
|
||||
}
|
||||
return this.nugetIndexPromise;
|
||||
}
|
||||
|
||||
private getNugetService(serviceType: string): Thenable<string> {
|
||||
return this.getNugetIndex().then(services => {
|
||||
let serviceURL = services[serviceType];
|
||||
if (!serviceURL) {
|
||||
return Promise.reject<string>(localize('json.nugget.error.missingservice', 'NuGet index document is missing service {0}', serviceType));
|
||||
}
|
||||
return serviceURL;
|
||||
});
|
||||
}
|
||||
|
||||
public collectDefaultCompletions(resource: string, result: CompletionsCollector): Thenable<any> {
|
||||
if (this.isProjectJSONFile(resource)) {
|
||||
let insertText = JSON.stringify({
|
||||
'version': '${1:1.0.0-*}',
|
||||
'dependencies': {},
|
||||
'frameworks': {
|
||||
'net461': {},
|
||||
'netcoreapp1.0': {}
|
||||
}
|
||||
}, null, '\t');
|
||||
result.add({ kind: CompletionItemKind.Class, label: localize('json.project.default', 'Default project.json'), insertText, insertTextFormat: InsertTextFormat.Snippet, documentation: '' });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private makeJSONRequest<T>(url: string): Thenable<T> {
|
||||
return xhr({
|
||||
url: url
|
||||
}).then(success => {
|
||||
if (success.status === 200) {
|
||||
try {
|
||||
return <T>JSON.parse(success.responseText);
|
||||
} catch (e) {
|
||||
return Promise.reject<T>(localize('json.nugget.error.invalidformat', '{0} is not a valid JSON document', url));
|
||||
}
|
||||
}
|
||||
return Promise.reject<T>(localize('json.nugget.error.indexaccess', 'Request to {0} failed: {1}', url, success.responseText));
|
||||
}, (error: XHRResponse) => {
|
||||
return Promise.reject<T>(localize('json.nugget.error.access', 'Request to {0} failed: {1}', url, getErrorStatusDescription(error.status)));
|
||||
});
|
||||
}
|
||||
|
||||
public collectPropertyCompletions(resource: string, location: JSONPath, currentWord: string, addValue: boolean, isLast: boolean, result: CompletionsCollector): Thenable<any> {
|
||||
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies']) || matches(location, ['frameworks', '*', 'dependencies']) || matches(location, ['frameworks', '*', 'frameworkAssemblies']))) {
|
||||
|
||||
return this.getNugetService('SearchAutocompleteService').then(service => {
|
||||
let queryUrl: string;
|
||||
if (currentWord.length > 0) {
|
||||
queryUrl = service + '?q=' + encodeURIComponent(currentWord) + '&take=' + LIMIT;
|
||||
} else {
|
||||
queryUrl = service + '?take=' + LIMIT;
|
||||
}
|
||||
return this.makeJSONRequest<any>(queryUrl).then(resultObj => {
|
||||
if (Array.isArray(resultObj.data)) {
|
||||
let results = <any[]>resultObj.data;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let name = results[i];
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "$1"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
let item: CompletionItem = { kind: CompletionItemKind.Property, label: name, insertText: insertText, insertTextFormat: InsertTextFormat.Snippet, filterText: JSON.stringify(name) };
|
||||
if (!this.completeWithCache(name, item)) {
|
||||
item.data = RESOLVE_ID + name;
|
||||
}
|
||||
result.add(item);
|
||||
}
|
||||
if (results.length === LIMIT) {
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
}, error => {
|
||||
result.error(error);
|
||||
});
|
||||
}, error => {
|
||||
result.error(error);
|
||||
});
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectValueCompletions(resource: string, location: JSONPath, currentKey: string, result: CompletionsCollector): Thenable<any> {
|
||||
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies']) || matches(location, ['frameworks', '*', 'dependencies']) || matches(location, ['frameworks', '*', 'frameworkAssemblies']))) {
|
||||
return this.getNugetService('PackageBaseAddress/3.0.0').then(service => {
|
||||
let queryUrl = service + currentKey + '/index.json';
|
||||
return this.makeJSONRequest<any>(queryUrl).then(obj => {
|
||||
if (Array.isArray(obj.versions)) {
|
||||
let results = <any[]>obj.versions;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let curr = results[i];
|
||||
let name = JSON.stringify(curr);
|
||||
let label = name;
|
||||
let documentation = '';
|
||||
result.add({ kind: CompletionItemKind.Class, label: label, insertText: name, documentation: documentation });
|
||||
}
|
||||
if (results.length === LIMIT) {
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
}, error => {
|
||||
result.error(error);
|
||||
});
|
||||
}, error => {
|
||||
result.error(error);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getInfoContribution(resource: string, location: JSONPath): Thenable<MarkedString[]> {
|
||||
if (this.isProjectJSONFile(resource) && (matches(location, ['dependencies', '*']) || matches(location, ['frameworks', '*', 'dependencies', '*']) || matches(location, ['frameworks', '*', 'frameworkAssemblies', '*']))) {
|
||||
let pack = <string>location[location.length - 1];
|
||||
|
||||
return this.getNugetService('SearchQueryService').then(service => {
|
||||
let queryUrl = service + '?q=' + encodeURIComponent(pack) + '&take=' + 5;
|
||||
return this.makeJSONRequest<any>(queryUrl).then(resultObj => {
|
||||
let htmlContent: MarkedString[] = [];
|
||||
htmlContent.push(localize('json.nugget.package.hover', '{0}', pack));
|
||||
if (Array.isArray(resultObj.data)) {
|
||||
let results = <any[]>resultObj.data;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let res = results[i];
|
||||
this.addCached(res.id, res.version, res.description);
|
||||
if (res.id === pack) {
|
||||
if (res.description) {
|
||||
htmlContent.push(MarkedString.fromPlainText(res.description));
|
||||
}
|
||||
if (res.version) {
|
||||
htmlContent.push(MarkedString.fromPlainText(localize('json.nugget.version.hover', 'Latest version: {0}', res.version)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return htmlContent;
|
||||
}, (error) => {
|
||||
return null;
|
||||
});
|
||||
}, (error) => {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public resolveSuggestion(item: CompletionItem): Thenable<CompletionItem> {
|
||||
if (item.data && Strings.startsWith(item.data, RESOLVE_ID)) {
|
||||
let pack = item.data.substring(RESOLVE_ID.length);
|
||||
if (this.completeWithCache(pack, item)) {
|
||||
return Promise.resolve(item);
|
||||
}
|
||||
return this.getNugetService('SearchQueryService').then(service => {
|
||||
let queryUrl = service + '?q=' + encodeURIComponent(pack) + '&take=' + 10;
|
||||
return this.makeJSONRequest<CompletionItem>(queryUrl).then(resultObj => {
|
||||
let itemResolved = false;
|
||||
if (Array.isArray(resultObj.data)) {
|
||||
let results = <any[]>resultObj.data;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let curr = results[i];
|
||||
this.addCached(curr.id, curr.version, curr.description);
|
||||
if (curr.id === pack) {
|
||||
this.completeWithCache(pack, item);
|
||||
itemResolved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemResolved ? item : null;
|
||||
});
|
||||
});
|
||||
};
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function matches(segments: JSONPath, pattern: string[]) {
|
||||
let k = 0;
|
||||
for (let i = 0; k < pattern.length && i < segments.length; i++) {
|
||||
if (pattern[k] === segments[i] || pattern[k] === '*') {
|
||||
k++;
|
||||
} else if (pattern[k] !== '**') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return k === pattern.length;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdown.preview.doubleClickToSwitchToEditor.desc": "Enable double clicking in the markdown preview switches to the editor.",
|
||||
"markdown.preview.doubleClickToSwitchToEditor.desc": "Double click in the markdown preview to switch to the editor.",
|
||||
"markdown.preview.fontFamily.desc": "Controls the font family used in the markdown preview.",
|
||||
"markdown.preview.fontSize.desc": "Controls the font size in pixels used in the markdown preview.",
|
||||
"markdown.preview.lineHeight.desc": "Controls the line height used in the markdown preview. This number is relative to the font size.",
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { MarkdownEngine } from './markdownEngine';
|
||||
import { TableOfContentProvider } from './tableOfContentsProvider';
|
||||
import { TableOfContentsProvider } from './tableOfContentsProvider';
|
||||
|
||||
export default class MDDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
||||
|
||||
constructor(private engine: MarkdownEngine) { }
|
||||
|
||||
provideDocumentSymbols(document: vscode.TextDocument): vscode.ProviderResult<vscode.SymbolInformation[]> {
|
||||
const toc = new TableOfContentProvider(this.engine, document);
|
||||
const toc = new TableOfContentsProvider(this.engine, document);
|
||||
return toc.getToc().map(entry => {
|
||||
return new vscode.SymbolInformation(entry.text, vscode.SymbolKind.Module, '', entry.location);
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import { MarkdownEngine } from './markdownEngine';
|
||||
import DocumentLinkProvider from './documentLinkProvider';
|
||||
import MDDocumentSymbolProvider from './documentSymbolProvider';
|
||||
import { MDDocumentContentProvider, getMarkdownUri, isMarkdownFile } from './previewContentProvider';
|
||||
import { TableOfContentProvider } from './tableOfContentsProvider';
|
||||
import { TableOfContentsProvider } from './tableOfContentsProvider';
|
||||
|
||||
interface IPackageInfo {
|
||||
name: string;
|
||||
@@ -78,7 +78,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(vscode.commands.registerCommand('_markdown.openDocumentLink', (args: OpenDocumentLinkArgs) => {
|
||||
const tryRevealLine = (editor: vscode.TextEditor) => {
|
||||
if (editor && args.fragment) {
|
||||
const toc = new TableOfContentProvider(engine, editor.document);
|
||||
const toc = new TableOfContentsProvider(engine, editor.document);
|
||||
const line = toc.lookup(args.fragment);
|
||||
if (!isNaN(line)) {
|
||||
return editor.revealRange(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { TableOfContentsProvider } from './tableOfContentsProvider';
|
||||
|
||||
export interface IToken {
|
||||
type: string;
|
||||
@@ -44,7 +45,9 @@ export class MarkdownEngine {
|
||||
}
|
||||
return `<pre class="hljs"><code><div>${this.engine.utils.escapeHtml(str)}</div></code></pre>`;
|
||||
}
|
||||
}).use(mdnh, {});
|
||||
}).use(mdnh, {
|
||||
slugify: (header: string) => TableOfContentsProvider.slugify(header)
|
||||
});
|
||||
|
||||
for (const renderName of ['paragraph_open', 'heading_open', 'image', 'code_block', 'blockquote_open', 'list_item_open']) {
|
||||
this.addLineNumberRenderer(this.md, renderName);
|
||||
|
||||
@@ -20,14 +20,12 @@ export function getMarkdownUri(uri: vscode.Uri) {
|
||||
|
||||
export class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
|
||||
private _onDidChange = new vscode.EventEmitter<vscode.Uri>();
|
||||
private _waiting: boolean;
|
||||
private _waiting: boolean = false;
|
||||
|
||||
constructor(
|
||||
private engine: MarkdownEngine,
|
||||
private context: vscode.ExtensionContext
|
||||
) {
|
||||
this._waiting = false;
|
||||
}
|
||||
) { }
|
||||
|
||||
private getMediaPath(mediaFile: string): string {
|
||||
return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))).toString();
|
||||
@@ -38,27 +36,28 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv
|
||||
}
|
||||
|
||||
private fixHref(resource: vscode.Uri, href: string): string {
|
||||
if (href) {
|
||||
// Use href if it is already an URL
|
||||
if (vscode.Uri.parse(href).scheme) {
|
||||
return href;
|
||||
}
|
||||
|
||||
// Use href as file URI if it is absolute
|
||||
if (this.isAbsolute(href)) {
|
||||
return vscode.Uri.file(href).toString();
|
||||
}
|
||||
|
||||
// use a workspace relative path if there is a workspace
|
||||
let rootPath = vscode.workspace.rootPath;
|
||||
if (rootPath) {
|
||||
return vscode.Uri.file(path.join(rootPath, href)).toString();
|
||||
}
|
||||
|
||||
// otherwise look relative to the markdown file
|
||||
return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)).toString();
|
||||
if (!href) {
|
||||
return href;
|
||||
}
|
||||
return href;
|
||||
|
||||
// Use href if it is already an URL
|
||||
if (vscode.Uri.parse(href).scheme) {
|
||||
return href;
|
||||
}
|
||||
|
||||
// Use href as file URI if it is absolute
|
||||
if (this.isAbsolute(href)) {
|
||||
return vscode.Uri.file(href).toString();
|
||||
}
|
||||
|
||||
// use a workspace relative path if there is a workspace
|
||||
let rootPath = vscode.workspace.rootPath;
|
||||
if (rootPath) {
|
||||
return vscode.Uri.file(path.join(rootPath, href)).toString();
|
||||
}
|
||||
|
||||
// otherwise look relative to the markdown file
|
||||
return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)).toString();
|
||||
}
|
||||
|
||||
private computeCustomStyleSheetIncludes(uri: vscode.Uri): string {
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface TocEntry {
|
||||
location: vscode.Location;
|
||||
}
|
||||
|
||||
export class TableOfContentProvider {
|
||||
export class TableOfContentsProvider {
|
||||
private toc: TocEntry[];
|
||||
|
||||
public constructor(
|
||||
@@ -35,7 +35,7 @@ export class TableOfContentProvider {
|
||||
}
|
||||
|
||||
public lookup(fragment: string): number {
|
||||
const slug = TableOfContentProvider.slugify(fragment);
|
||||
const slug = TableOfContentsProvider.slugify(fragment);
|
||||
for (const entry of this.getToc()) {
|
||||
if (entry.slug === slug) {
|
||||
return entry.line;
|
||||
@@ -51,11 +51,11 @@ export class TableOfContentProvider {
|
||||
for (const heading of tokens.filter(token => token.type === 'heading_open')) {
|
||||
const lineNumber = heading.map[0];
|
||||
const line = document.lineAt(lineNumber);
|
||||
const href = TableOfContentProvider.slugify(line.text);
|
||||
const href = TableOfContentsProvider.slugify(line.text);
|
||||
if (href) {
|
||||
toc.push({
|
||||
slug: href,
|
||||
text: TableOfContentProvider.getHeaderText(line.text),
|
||||
text: TableOfContentsProvider.getHeaderText(line.text),
|
||||
line: lineNumber,
|
||||
location: new vscode.Location(document.uri, line.range)
|
||||
});
|
||||
@@ -69,9 +69,12 @@ export class TableOfContentProvider {
|
||||
}
|
||||
|
||||
public static slugify(header: string): string {
|
||||
return encodeURI(TableOfContentProvider.getHeaderText(header)
|
||||
return encodeURI(header.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-'));
|
||||
.replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/^\-+/, '')
|
||||
.replace(/\-+$/, ''));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "TextMate Bundle License",
|
||||
"repositoryURL": "https://github.com/textmate/perl.tmbundle",
|
||||
"description": "The files syntaxes/perl.tmLanguage.json and syntaxes/perl6.tmLanguage.json were derived from Perl.plist and Perl 6.tmLanguage from https://github.com/textmate/perl.tmbundle.",
|
||||
"licenseDetail": [
|
||||
"Copyright (c) textmate-perl.tmbundle project authors",
|
||||
"",
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
"version": "0.1.0",
|
||||
"publisher": "vscode",
|
||||
"engines": { "vscode": "*" },
|
||||
"scripts": {
|
||||
"update-grammar": "node ../../build/npm/update-grammar.js textmate/perl.tmbundle Syntaxes/Perl.plist ./syntaxes/perl.tmLanguage.json Syntaxes/Perl%206.tmLanguage ./syntaxes/perl6.tmLanguage.json"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [{
|
||||
"id": "perl",
|
||||
@@ -20,11 +23,11 @@
|
||||
"grammars": [{
|
||||
"language": "perl",
|
||||
"scopeName": "source.perl",
|
||||
"path": "./syntaxes/Perl.plist"
|
||||
"path": "./syntaxes/perl.tmLanguage.json"
|
||||
}, {
|
||||
"language": "perl6",
|
||||
"scopeName": "source.perl.6",
|
||||
"path": "./syntaxes/Perl 6.tmLanguage"
|
||||
"path": "./syntaxes/perl6.tmLanguage.json"
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -1,490 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>fileTypes</key>
|
||||
<array>
|
||||
<string>p6</string>
|
||||
<string>pl6</string>
|
||||
<string>pm6</string>
|
||||
<string>nqp</string>
|
||||
</array>
|
||||
<key>firstLineMatch</key>
|
||||
<string>(^#!.*\b(perl6|nqp)\b)|use\s+v6</string>
|
||||
<key>keyEquivalent</key>
|
||||
<string>^~P</string>
|
||||
<key>name</key>
|
||||
<string>Perl 6</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>^=begin</string>
|
||||
<key>end</key>
|
||||
<string>^=end</string>
|
||||
<key>name</key>
|
||||
<string>comment.block.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(^[ \t]+)?(?=#)</string>
|
||||
<key>beginCaptures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.whitespace.comment.leading.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>end</key>
|
||||
<string>(?!\G)</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>#</string>
|
||||
<key>beginCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.comment.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>end</key>
|
||||
<string>\n</string>
|
||||
<key>name</key>
|
||||
<string>comment.line.number-sign.perl</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>captures</key>
|
||||
<dict>
|
||||
<key>1</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>storage.type.class.perl.6</string>
|
||||
</dict>
|
||||
<key>3</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>entity.name.type.class.perl.6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>match</key>
|
||||
<string>(class|enum|grammar|knowhow|module|package|role|slang|subset)(\s+)(((?:::|')?(?:([a-zA-Z_\x{C0}-\x{FF}\$])([a-zA-Z0-9_\x{C0}-\x{FF}\\$]|[\-'][a-zA-Z0-9_\x{C0}-\x{FF}\$])*))+)</string>
|
||||
<key>name</key>
|
||||
<string>meta.class.perl.6</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(?<=\s)'</string>
|
||||
<key>beginCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.begin.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>end</key>
|
||||
<string>'</string>
|
||||
<key>endCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.end.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\\['\\]</string>
|
||||
<key>name</key>
|
||||
<string>constant.character.escape.perl</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>"</string>
|
||||
<key>beginCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.begin.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>end</key>
|
||||
<string>"</string>
|
||||
<key>endCaptures</key>
|
||||
<dict>
|
||||
<key>0</key>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>punctuation.definition.string.end.perl</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>string.quoted.double.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\\[abtnfre"\\]</string>
|
||||
<key>name</key>
|
||||
<string>constant.character.escape.perl</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>q(q|to|heredoc)*\s*:?(q|to|heredoc)*\s*/(.+)/</string>
|
||||
<key>end</key>
|
||||
<string>\3</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*{{</string>
|
||||
<key>end</key>
|
||||
<string>}}</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.double.heredoc.brace.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_brace_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*\(\(</string>
|
||||
<key>end</key>
|
||||
<string>\)\)</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.double.heredoc.paren.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_paren_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*\[\[</string>
|
||||
<key>end</key>
|
||||
<string>\]\]</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.double.heredoc.bracket.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_bracket_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*{</string>
|
||||
<key>end</key>
|
||||
<string>}</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.brace.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_brace_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*/</string>
|
||||
<key>end</key>
|
||||
<string>/</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.slash.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_slash_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*\(</string>
|
||||
<key>end</key>
|
||||
<string>\)</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.paren.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_paren_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*\[</string>
|
||||
<key>end</key>
|
||||
<string>\]</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.bracket.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_bracket_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*'</string>
|
||||
<key>end</key>
|
||||
<string>'</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.single.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_single_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\s*"</string>
|
||||
<key>end</key>
|
||||
<string>"</string>
|
||||
<key>name</key>
|
||||
<string>string.quoted.single.heredoc.double.perl</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_double_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b\$\w+\b</string>
|
||||
<key>name</key>
|
||||
<string>variable.other.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(macro|sub|submethod|method|multi|proto|only|rule|token|regex|category)\b</string>
|
||||
<key>name</key>
|
||||
<string>storage.type.declare.routine.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(self)\b</string>
|
||||
<key>name</key>
|
||||
<string>variable.language.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(use|require)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.other.include.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(if|else|elsif|unless)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.control.conditional.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(let|my|our|state|temp|has|constant)\b</string>
|
||||
<key>name</key>
|
||||
<string>storage.type.variable.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(for|loop|repeat|while|until|gather|given)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.control.repeat.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(take|do|when|next|last|redo|return|contend|maybe|defer|default|exit|make|continue|break|goto|leave|async|lift)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.control.flowcontrol.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(is|as|but|trusts|of|returns|handles|where|augment|supersede)\b</string>
|
||||
<key>name</key>
|
||||
<string>storage.modifier.type.constraints.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(BEGIN|CHECK|INIT|START|FIRST|ENTER|LEAVE|KEEP|UNDO|NEXT|LAST|PRE|POST|END|CATCH|CONTROL|TEMP)\b</string>
|
||||
<key>name</key>
|
||||
<string>meta.function.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(die|fail|try|warn)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.control.control-handlers.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(prec|irs|ofs|ors|export|deep|binary|unary|reparsed|rw|parsed|cached|readonly|defequiv|will|ref|copy|inline|tighter|looser|equiv|assoc|required)\b</string>
|
||||
<key>name</key>
|
||||
<string>storage.modifier.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(NaN|Inf)\b</string>
|
||||
<key>name</key>
|
||||
<string>constant.numeric.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(oo|fatal)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.other.pragma.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(Object|Any|Junction|Whatever|Capture|MatchSignature|Proxy|Matcher|Package|Module|ClassGrammar|Scalar|Array|Hash|KeyHash|KeySet|KeyBagPair|List|Seq|Range|Set|Bag|Mapping|Void|UndefFailure|Exception|Code|Block|Routine|Sub|MacroMethod|Submethod|Regex|Str|str|Blob|Char|ByteCodepoint|Grapheme|StrPos|StrLen|Version|NumComplex|num|complex|Bit|bit|bool|True|FalseIncreasing|Decreasing|Ordered|Callable|AnyCharPositional|Associative|Ordering|KeyExtractorComparator|OrderingPair|IO|KitchenSink|RoleInt|int|int1|int2|int4|int8|int16|int32|int64Rat|rat|rat1|rat2|rat4|rat8|rat16|rat32|rat64Buf|buf|buf1|buf2|buf4|buf8|buf16|buf32|buf64UInt|uint|uint1|uint2|uint4|uint8|uint16|uint32uint64|Abstraction|utf8|utf16|utf32)\b</string>
|
||||
<key>name</key>
|
||||
<string>support.type.perl6</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(div|xx|x|mod|also|leg|cmp|before|after|eq|ne|le|lt|not|gt|ge|eqv|ff|fff|and|andthen|or|xor|orelse|extra|lcm|gcd)\b</string>
|
||||
<key>name</key>
|
||||
<string>keyword.operator.perl</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>(\$|@|%|&)(\*|:|!|\^|~|=|\?|(<(?=.+>)))?([a-zA-Z_\x{C0}-\x{FF}\$])([a-zA-Z0-9_\x{C0}-\x{FF}\$]|[\-'][a-zA-Z0-9_\x{C0}-\x{FF}\$])*</string>
|
||||
<key>name</key>
|
||||
<string>variable.other.identifier.perl.6</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>match</key>
|
||||
<string>\b(eager|hyper|substr|index|rindex|grep|map|sort|join|lines|hints|chmod|split|reduce|min|max|reverse|truncate|zip|cat|roundrobin|classify|first|sum|keys|values|pairs|defined|delete|exists|elems|end|kv|any|all|one|wrap|shape|key|value|name|pop|push|shift|splice|unshift|floor|ceiling|abs|exp|log|log10|rand|sign|sqrt|sin|cos|tan|round|strand|roots|cis|unpolar|polar|atan2|pick|chop|p5chop|chomp|p5chomp|lc|lcfirst|uc|ucfirst|capitalize|normalize|pack|unpack|quotemeta|comb|samecase|sameaccent|chars|nfd|nfc|nfkd|nfkc|printf|sprintf|caller|evalfile|run|runinstead|nothing|want|bless|chr|ord|gmtime|time|eof|localtime|gethost|getpw|chroot|getlogin|getpeername|kill|fork|wait|perl|graphs|codes|bytes|clone|print|open|read|write|readline|say|seek|close|opendir|readdir|slurp|spurt|shell|run|pos|fmt|vec|link|unlink|symlink|uniq|pair|asin|atan|sec|cosec|cotan|asec|acosec|acotan|sinh|cosh|tanh|asinh|done|acos|acosh|atanh|sech|cosech|cotanh|sech|acosech|acotanh|asech|ok|nok|plan_ok|dies_ok|lives_ok|skip|todo|pass|flunk|force_todo|use_ok|isa_ok|diag|is_deeply|isnt|like|skip_rest|unlike|cmp_ok|eval_dies_ok|nok_error|eval_lives_ok|approx|is_approx|throws_ok|version_lt|plan|EVAL|succ|pred|times|nonce|once|signature|new|connect|operator|undef|undefine|sleep|from|to|infix|postfix|prefix|circumfix|postcircumfix|minmax|lazy|count|unwrap|getc|pi|e|context|void|quasi|body|each|contains|rewinddir|subst|can|isa|flush|arity|assuming|rewind|callwith|callsame|nextwith|nextsame|attr|eval_elsewhere|none|srand|trim|trim_start|trim_end|lastcall|WHAT|WHERE|HOW|WHICH|VAR|WHO|WHENCE|ACCEPTS|REJECTS|not|true|iterator|by|re|im|invert|flip|gist|flat|tree|is-prime|throws_like|trans)\b</string>
|
||||
<key>name</key>
|
||||
<string>support.function.perl</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>repository</key>
|
||||
<dict>
|
||||
<key>qq_brace_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>{</string>
|
||||
<key>end</key>
|
||||
<string>}</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_brace_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>qq_bracket_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>\[</string>
|
||||
<key>end</key>
|
||||
<string>\]</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_bracket_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>qq_double_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>"</string>
|
||||
<key>end</key>
|
||||
<string>"</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_double_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>qq_paren_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>\(</string>
|
||||
<key>end</key>
|
||||
<string>\)</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_paren_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>qq_single_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>'</string>
|
||||
<key>end</key>
|
||||
<string>'</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_single_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>qq_slash_string_content</key>
|
||||
<dict>
|
||||
<key>begin</key>
|
||||
<string>\\/</string>
|
||||
<key>end</key>
|
||||
<string>\\/</string>
|
||||
<key>patterns</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>include</key>
|
||||
<string>#qq_slash_string_content</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>scopeName</key>
|
||||
<string>source.perl.6</string>
|
||||
<key>uuid</key>
|
||||
<string>E685440C-0E20-4424-9693-864D5240A269</string>
|
||||
</dict>
|
||||
</plist>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,319 @@
|
||||
{
|
||||
"fileTypes": [
|
||||
"p6",
|
||||
"pl6",
|
||||
"pm6",
|
||||
"nqp"
|
||||
],
|
||||
"firstLineMatch": "(?x)\n# Hashbang\n^\\#!.*(?:\\s|\\/|(?<=!)\\b)(?:perl6|nqp)(?:$|\\s)\n|\n# Perl 6 pragma\n\\buse\\s+v6\\b\n|\n# Modeline\n(?i:\n # Emacs\n -\\*-(?:(?:(?!mode\\s*:)[^:;]+:[^:;]+;)*\\s*mode\\s*:)?\\s*\n\tperl6\n \\s*(?:;[^:;]+:[^:;]+?)*;?\\s*-\\*-\n |\n # Vim\n (?:(?:\\s|^)vi(?:m[<=>]?\\d+|m)?|(?!^)\\sex)(?=:(?=\\s*set?\\s[^\\n:]+:)|:(?!\\s*set?\\s))(?:(?:\\s|\\s*:\\s*)\\w*(?:\\s*=(?:[^\\n\\\\\\s]|\\\\.)*)?)*[\\s:](?:filetype|ft|syntax)\\s*=\n\tperl6\n (?=\\s|:|$)\n)",
|
||||
"keyEquivalent": "^~P",
|
||||
"name": "Perl 6",
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "^=begin",
|
||||
"end": "^=end",
|
||||
"name": "comment.block.perl"
|
||||
},
|
||||
{
|
||||
"begin": "(^[ \\t]+)?(?=#)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.whitespace.comment.leading.perl"
|
||||
}
|
||||
},
|
||||
"end": "(?!\\G)",
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "#",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.perl"
|
||||
}
|
||||
},
|
||||
"end": "\\n",
|
||||
"name": "comment.line.number-sign.perl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.class.perl.6"
|
||||
},
|
||||
"3": {
|
||||
"name": "entity.name.type.class.perl.6"
|
||||
}
|
||||
},
|
||||
"match": "(class|enum|grammar|knowhow|module|package|role|slang|subset)(\\s+)(((?:::|')?(?:([a-zA-Z_\\x{C0}-\\x{FF}\\$])([a-zA-Z0-9_\\x{C0}-\\x{FF}\\\\$]|[\\-'][a-zA-Z0-9_\\x{C0}-\\x{FF}\\$])*))+)",
|
||||
"name": "meta.class.perl.6"
|
||||
},
|
||||
{
|
||||
"begin": "(?<=\\s)'",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.perl"
|
||||
}
|
||||
},
|
||||
"end": "'",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.perl"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.single.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\\\['\\\\]",
|
||||
"name": "constant.character.escape.perl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.perl"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.perl"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.double.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"match": "\\\\[abtnfre\"\\\\]",
|
||||
"name": "constant.character.escape.perl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "q(q|to|heredoc)*\\s*:?(q|to|heredoc)*\\s*/(.+)/",
|
||||
"end": "\\3",
|
||||
"name": "string.quoted.single.heredoc.perl"
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*{{",
|
||||
"end": "}}",
|
||||
"name": "string.quoted.double.heredoc.brace.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_brace_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*\\(\\(",
|
||||
"end": "\\)\\)",
|
||||
"name": "string.quoted.double.heredoc.paren.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_paren_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*\\[\\[",
|
||||
"end": "\\]\\]",
|
||||
"name": "string.quoted.double.heredoc.bracket.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_bracket_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*{",
|
||||
"end": "}",
|
||||
"name": "string.quoted.single.heredoc.brace.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_brace_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*/",
|
||||
"end": "/",
|
||||
"name": "string.quoted.single.heredoc.slash.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_slash_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*\\(",
|
||||
"end": "\\)",
|
||||
"name": "string.quoted.single.heredoc.paren.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_paren_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*\\[",
|
||||
"end": "\\]",
|
||||
"name": "string.quoted.single.heredoc.bracket.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_bracket_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*'",
|
||||
"end": "'",
|
||||
"name": "string.quoted.single.heredoc.single.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_single_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "(q|Q)(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*:?(x|exec|w|words|ww|quotewords|v|val|q|single|qq|double|s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash|regexp|substr|trans|codes|p|path)*\\s*\"",
|
||||
"end": "\"",
|
||||
"name": "string.quoted.single.heredoc.double.perl",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_double_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": "\\b\\$\\w+\\b",
|
||||
"name": "variable.other.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(macro|sub|submethod|method|multi|proto|only|rule|token|regex|category)\\b",
|
||||
"name": "storage.type.declare.routine.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(self)\\b",
|
||||
"name": "variable.language.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(use|require)\\b",
|
||||
"name": "keyword.other.include.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(if|else|elsif|unless)\\b",
|
||||
"name": "keyword.control.conditional.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(let|my|our|state|temp|has|constant)\\b",
|
||||
"name": "storage.type.variable.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(for|loop|repeat|while|until|gather|given)\\b",
|
||||
"name": "keyword.control.repeat.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(take|do|when|next|last|redo|return|contend|maybe|defer|default|exit|make|continue|break|goto|leave|async|lift)\\b",
|
||||
"name": "keyword.control.flowcontrol.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(is|as|but|trusts|of|returns|handles|where|augment|supersede)\\b",
|
||||
"name": "storage.modifier.type.constraints.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(BEGIN|CHECK|INIT|START|FIRST|ENTER|LEAVE|KEEP|UNDO|NEXT|LAST|PRE|POST|END|CATCH|CONTROL|TEMP)\\b",
|
||||
"name": "meta.function.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(die|fail|try|warn)\\b",
|
||||
"name": "keyword.control.control-handlers.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(prec|irs|ofs|ors|export|deep|binary|unary|reparsed|rw|parsed|cached|readonly|defequiv|will|ref|copy|inline|tighter|looser|equiv|assoc|required)\\b",
|
||||
"name": "storage.modifier.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(NaN|Inf)\\b",
|
||||
"name": "constant.numeric.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(oo|fatal)\\b",
|
||||
"name": "keyword.other.pragma.perl"
|
||||
},
|
||||
{
|
||||
"match": "\\b(Object|Any|Junction|Whatever|Capture|MatchSignature|Proxy|Matcher|Package|Module|ClassGrammar|Scalar|Array|Hash|KeyHash|KeySet|KeyBagPair|List|Seq|Range|Set|Bag|Mapping|Void|UndefFailure|Exception|Code|Block|Routine|Sub|MacroMethod|Submethod|Regex|Str|str|Blob|Char|ByteCodepoint|Grapheme|StrPos|StrLen|Version|NumComplex|num|complex|Bit|bit|bool|True|FalseIncreasing|Decreasing|Ordered|Callable|AnyCharPositional|Associative|Ordering|KeyExtractorComparator|OrderingPair|IO|KitchenSink|RoleInt|int|int1|int2|int4|int8|int16|int32|int64Rat|rat|rat1|rat2|rat4|rat8|rat16|rat32|rat64Buf|buf|buf1|buf2|buf4|buf8|buf16|buf32|buf64UInt|uint|uint1|uint2|uint4|uint8|uint16|uint32uint64|Abstraction|utf8|utf16|utf32)\\b",
|
||||
"name": "support.type.perl6"
|
||||
},
|
||||
{
|
||||
"match": "\\b(div|xx|x|mod|also|leg|cmp|before|after|eq|ne|le|lt|not|gt|ge|eqv|ff|fff|and|andthen|or|xor|orelse|extra|lcm|gcd)\\b",
|
||||
"name": "keyword.operator.perl"
|
||||
},
|
||||
{
|
||||
"match": "(\\$|@|%|&)(\\*|:|!|\\^|~|=|\\?|(<(?=.+>)))?([a-zA-Z_\\x{C0}-\\x{FF}\\$])([a-zA-Z0-9_\\x{C0}-\\x{FF}\\$]|[\\-'][a-zA-Z0-9_\\x{C0}-\\x{FF}\\$])*",
|
||||
"name": "variable.other.identifier.perl.6"
|
||||
},
|
||||
{
|
||||
"match": "\\b(eager|hyper|substr|index|rindex|grep|map|sort|join|lines|hints|chmod|split|reduce|min|max|reverse|truncate|zip|cat|roundrobin|classify|first|sum|keys|values|pairs|defined|delete|exists|elems|end|kv|any|all|one|wrap|shape|key|value|name|pop|push|shift|splice|unshift|floor|ceiling|abs|exp|log|log10|rand|sign|sqrt|sin|cos|tan|round|strand|roots|cis|unpolar|polar|atan2|pick|chop|p5chop|chomp|p5chomp|lc|lcfirst|uc|ucfirst|capitalize|normalize|pack|unpack|quotemeta|comb|samecase|sameaccent|chars|nfd|nfc|nfkd|nfkc|printf|sprintf|caller|evalfile|run|runinstead|nothing|want|bless|chr|ord|gmtime|time|eof|localtime|gethost|getpw|chroot|getlogin|getpeername|kill|fork|wait|perl|graphs|codes|bytes|clone|print|open|read|write|readline|say|seek|close|opendir|readdir|slurp|spurt|shell|run|pos|fmt|vec|link|unlink|symlink|uniq|pair|asin|atan|sec|cosec|cotan|asec|acosec|acotan|sinh|cosh|tanh|asinh|done|acos|acosh|atanh|sech|cosech|cotanh|sech|acosech|acotanh|asech|ok|nok|plan_ok|dies_ok|lives_ok|skip|todo|pass|flunk|force_todo|use_ok|isa_ok|diag|is_deeply|isnt|like|skip_rest|unlike|cmp_ok|eval_dies_ok|nok_error|eval_lives_ok|approx|is_approx|throws_ok|version_lt|plan|EVAL|succ|pred|times|nonce|once|signature|new|connect|operator|undef|undefine|sleep|from|to|infix|postfix|prefix|circumfix|postcircumfix|minmax|lazy|count|unwrap|getc|pi|e|context|void|quasi|body|each|contains|rewinddir|subst|can|isa|flush|arity|assuming|rewind|callwith|callsame|nextwith|nextsame|attr|eval_elsewhere|none|srand|trim|trim_start|trim_end|lastcall|WHAT|WHERE|HOW|WHICH|VAR|WHO|WHENCE|ACCEPTS|REJECTS|not|true|iterator|by|re|im|invert|flip|gist|flat|tree|is-prime|throws_like|trans)\\b",
|
||||
"name": "support.function.perl"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"qq_brace_string_content": {
|
||||
"begin": "{",
|
||||
"end": "}",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_brace_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
"qq_bracket_string_content": {
|
||||
"begin": "\\[",
|
||||
"end": "\\]",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_bracket_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
"qq_double_string_content": {
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_double_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
"qq_paren_string_content": {
|
||||
"begin": "\\(",
|
||||
"end": "\\)",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_paren_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
"qq_single_string_content": {
|
||||
"begin": "'",
|
||||
"end": "'",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_single_string_content"
|
||||
}
|
||||
]
|
||||
},
|
||||
"qq_slash_string_content": {
|
||||
"begin": "\\\\/",
|
||||
"end": "\\\\/",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#qq_slash_string_content"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scopeName": "source.perl.6",
|
||||
"uuid": "E685440C-0E20-4424-9693-864D5240A269",
|
||||
"version": "https://github.com/textmate/perl.tmbundle/commit/d9841a0878239fa43f88c640f8d458590f97e8f5"
|
||||
}
|
||||
@@ -9,26 +9,31 @@
|
||||
"contributes": {
|
||||
"themes": [
|
||||
{
|
||||
"id": "Default Dark+",
|
||||
"label": "Dark+ (default dark)",
|
||||
"uiTheme": "vs-dark",
|
||||
"path": "./themes/dark_plus.json"
|
||||
},
|
||||
{
|
||||
"id": "Default Light+",
|
||||
"label": "Light+ (default light)",
|
||||
"uiTheme": "vs",
|
||||
"path": "./themes/light_plus.json"
|
||||
},
|
||||
{
|
||||
"id": "Visual Studio Dark",
|
||||
"label": "Dark (Visual Studio)",
|
||||
"uiTheme": "vs-dark",
|
||||
"path": "./themes/dark_vs.json"
|
||||
},
|
||||
{
|
||||
"id": "Visual Studio Light",
|
||||
"label": "Light (Visual Studio)",
|
||||
"uiTheme": "vs",
|
||||
"path": "./themes/light_vs.json"
|
||||
},
|
||||
{
|
||||
"id": "Default High Contrast",
|
||||
"label": "High Contrast",
|
||||
"uiTheme": "hc-black",
|
||||
"path": "./themes/hc_black.json"
|
||||
|
||||
+3
-3
@@ -13,9 +13,9 @@
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
|
||||
},
|
||||
"typescript": {
|
||||
"version": "typescript@2.2.1-insiders.20170209",
|
||||
"from": "typescript@typescript@2.2.1-insiders.20170209",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.2.1-insiders.20170209.tgz"
|
||||
"version": "typescript@2.2.1-insiders.20170216",
|
||||
"from": "typescript@typescript@2.2.1-insiders.20170216",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.2.1-insiders.20170216.tgz"
|
||||
},
|
||||
"vscode-extension-telemetry": {
|
||||
"version": "0.0.5",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"semver": "4.3.6",
|
||||
"vscode-extension-telemetry": "^0.0.5",
|
||||
"vscode-nls": "^2.0.1",
|
||||
"typescript": "typescript@2.2.1-insiders.20170209"
|
||||
"typescript": "typescript@2.2.1-insiders.20170216"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^7.0.4",
|
||||
@@ -33,7 +33,12 @@
|
||||
"onLanguage:jsx-tags",
|
||||
"onCommand:typescript.reloadProjects",
|
||||
"onCommand:javascript.reloadProjects",
|
||||
"onCommand:typescript.selectTypeScriptVersion"
|
||||
"onCommand:typescript.selectTypeScriptVersion",
|
||||
"onCommand:javascript.goToProjectConfig",
|
||||
"onCommand:typescript.goToProjectConfig",
|
||||
"onCommand:_typescript.tryCompleteJsDoc",
|
||||
"workspaceContains:jsconfig.json",
|
||||
"workspaceContains:tsconfig.json"
|
||||
],
|
||||
"main": "./out/typescriptMain",
|
||||
"enableProposedApi": true,
|
||||
@@ -79,6 +84,18 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"key": "enter",
|
||||
"command": "_typescript.tryCompleteJsDoc",
|
||||
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'typescript'"
|
||||
},
|
||||
{
|
||||
"key": "enter",
|
||||
"command": "_typescript.tryCompleteJsDoc",
|
||||
"when": "editorTextFocus && !suggestWidgetVisible && editorLangId == 'javascript'"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "%configuration.typescript%",
|
||||
@@ -257,15 +274,28 @@
|
||||
"commands": [
|
||||
{
|
||||
"command": "typescript.reloadProjects",
|
||||
"title": "%typescript.reloadProjects.title%"
|
||||
"title": "%typescript.reloadProjects.title%",
|
||||
"category": "TypeScript"
|
||||
},
|
||||
{
|
||||
"command": "javascript.reloadProjects",
|
||||
"title": "%javascript.reloadProjects.title%"
|
||||
"title": "%javascript.reloadProjects.title%",
|
||||
"category": "JavaScript"
|
||||
},
|
||||
{
|
||||
"command": "typescript.selectTypeScriptVersion",
|
||||
"title": "%typescript.selectTypeScriptVersion.title%"
|
||||
"title": "%typescript.selectTypeScriptVersion.title%",
|
||||
"category": "TypeScript"
|
||||
},
|
||||
{
|
||||
"command": "typescript.goToProjectConfig",
|
||||
"title": "%typescript.goToProjectConfig.title%",
|
||||
"category": "TypeScript"
|
||||
},
|
||||
{
|
||||
"command": "javascript.goToProjectConfig",
|
||||
"title": "%javascript.goToProjectConfig.title%",
|
||||
"category": "JavaScript"
|
||||
}
|
||||
],
|
||||
"breakpoints": [
|
||||
@@ -301,4 +331,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"typescript.reloadProjects.title": "Reload TypeScript Project",
|
||||
"javascript.reloadProjects.title": "Reload JavaScript Project",
|
||||
"typescript.reloadProjects.title": "Reload Project",
|
||||
"javascript.reloadProjects.title": "Reload Project",
|
||||
"configuration.typescript": "TypeScript",
|
||||
"typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete functions with their parameter signature.",
|
||||
"typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use.",
|
||||
@@ -24,6 +24,8 @@
|
||||
"format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.",
|
||||
"format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.",
|
||||
"javascript.validate.enable": "Enable/disable JavaScript validation.",
|
||||
"typescript.referencesCodeLens.enabled": "Enable/disable the references code lens.",
|
||||
"typescript.selectTypeScriptVersion.title": "Select TypeScript version."
|
||||
"typescript.goToProjectConfig.title": "Go to Project Configuration",
|
||||
"javascript.goToProjectConfig.title": "Go to Project Configuration",
|
||||
"typescript.referencesCodeLens.enabled": "Enable/disable references CodeLens.",
|
||||
"typescript.selectTypeScriptVersion.title": "Select TypeScript Version"
|
||||
}
|
||||
@@ -153,8 +153,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
||||
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise<CompletionItem[]> {
|
||||
if (this.typingsStatus.isAcquiringTypings) {
|
||||
return Promise.reject<CompletionItem[]>({
|
||||
label: localize('acquiringTypingsLabel', 'Acquiring typings...'),
|
||||
detail: localize('acquiringTypingsDetail', 'Acquiring typings definitions for IntelliSense.')
|
||||
label: localize(
|
||||
{ key: 'acquiringTypingsLabel', comment: ['Typings refers to the *.d.ts typings files that power our IntelliSense. It should not be localized'] },
|
||||
'Acquiring typings...'),
|
||||
detail: localize(
|
||||
{ key: 'acquiringTypingsDetail', comment: ['Typings refers to the *.d.ts typings files that power our IntelliSense. It should not be localized'] },
|
||||
'Acquiring typings definitions for IntelliSense.')
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
|
||||
import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, DocumentFilter, Disposable, Uri } from 'vscode';
|
||||
import { env, languages, commands, workspace, window, ExtensionContext, Memento, IndentAction, Diagnostic, DiagnosticCollection, Range, DocumentFilter, Disposable, Uri, MessageItem, TextEditor } from 'vscode';
|
||||
|
||||
// This must be the first statement otherwise modules might got loaded with
|
||||
// the wrong locale.
|
||||
import * as nls from 'vscode-nls';
|
||||
nls.config({ locale: env.language });
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
@@ -39,6 +40,7 @@ import WorkspaceSymbolProvider from './features/workspaceSymbolProvider';
|
||||
import CodeActionProvider from './features/codeActionProvider';
|
||||
import ReferenceCodeLensProvider from './features/referencesCodeLensProvider';
|
||||
|
||||
import JsDocCompletionHelper from './utils/JsDocCompletionHelper';
|
||||
import * as BuildStatus from './utils/buildStatus';
|
||||
import * as ProjectStatus from './utils/projectStatus';
|
||||
import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus';
|
||||
@@ -52,6 +54,16 @@ interface LanguageDescription {
|
||||
configFile: string;
|
||||
}
|
||||
|
||||
enum ProjectConfigAction {
|
||||
None,
|
||||
CreateConfig,
|
||||
LearnMore
|
||||
}
|
||||
|
||||
interface ProjectConfigMessageItem extends MessageItem {
|
||||
id: ProjectConfigAction;
|
||||
}
|
||||
|
||||
export function activate(context: ExtensionContext): void {
|
||||
const MODE_ID_TS = 'typescript';
|
||||
const MODE_ID_TSX = 'typescriptreact';
|
||||
@@ -89,6 +101,29 @@ export function activate(context: ExtensionContext): void {
|
||||
client.onVersionStatusClicked();
|
||||
}));
|
||||
|
||||
const jsDocCompletionHelper = new JsDocCompletionHelper(client);
|
||||
context.subscriptions.push(commands.registerCommand('_typescript.tryCompleteJsDoc', () => {
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor || !editor.selection.isEmpty) {
|
||||
return commands.executeCommand('type', { text: '\n' });
|
||||
}
|
||||
return jsDocCompletionHelper.tryCompleteJsDoc(editor, editor.selection.active).then(didCompleteComment => {
|
||||
if (didCompleteComment) {
|
||||
return;
|
||||
}
|
||||
return commands.executeCommand('type', { text: '\n' });
|
||||
});
|
||||
}));
|
||||
|
||||
const goToProjectConfig = (isTypeScript: boolean) => {
|
||||
const editor = window.activeTextEditor;
|
||||
if (editor) {
|
||||
clientHost.goToProjectConfig(isTypeScript, editor.document.uri, editor.document.languageId);
|
||||
}
|
||||
};
|
||||
context.subscriptions.push(commands.registerCommand('typescript.goToProjectConfig', goToProjectConfig.bind(null, true)));
|
||||
context.subscriptions.push(commands.registerCommand('javascript.goToProjectConfig', goToProjectConfig.bind(null, false)));
|
||||
|
||||
window.onDidChangeActiveTextEditor(VersionStatus.showHideStatus, null, context.subscriptions);
|
||||
client.onReady().then(() => {
|
||||
context.subscriptions.push(ProjectStatus.create(client,
|
||||
@@ -378,6 +413,76 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
|
||||
return !!this.findLanguage(file);
|
||||
}
|
||||
|
||||
public goToProjectConfig(
|
||||
isTypeScriptProject: boolean,
|
||||
resource: Uri,
|
||||
languageId: string
|
||||
): Thenable<TextEditor> | undefined {
|
||||
const rootPath = workspace.rootPath;
|
||||
if (!rootPath) {
|
||||
window.showInformationMessage(
|
||||
localize(
|
||||
'typescript.projectConfigNoWorkspace',
|
||||
'Please open a folder in VS Code to use a TypeScript or JavaScript project'));
|
||||
return;
|
||||
}
|
||||
|
||||
const file = this.client.normalizePath(resource);
|
||||
// TODO: TSServer errors when 'projectInfo' is invoked on a non js/ts file
|
||||
if (!file || !this.languagePerId[languageId]) {
|
||||
window.showWarningMessage(
|
||||
localize(
|
||||
'typescript.projectConfigUnsupportedFile',
|
||||
'Could not determine TypeScript or JavaScript project. Unsupported file type'));
|
||||
return;
|
||||
}
|
||||
|
||||
return this.client.execute('projectInfo', { file, needFileNameList: false }).then(res => {
|
||||
if (!res || !res.body) {
|
||||
return window.showWarningMessage(localize('typescript.projectConfigCouldNotGetInfo', 'Could not determine TypeScript or JavaScript project'));
|
||||
}
|
||||
|
||||
const { configFileName } = res.body;
|
||||
if (configFileName && configFileName.indexOf('/dev/null/') !== 0) {
|
||||
return workspace.openTextDocument(configFileName)
|
||||
.then(window.showTextDocument);
|
||||
}
|
||||
|
||||
return window.showInformationMessage<ProjectConfigMessageItem>(
|
||||
(isTypeScriptProject
|
||||
? localize('typescript.noTypeScriptProjectConfig', 'File is not part of a TypeScript project')
|
||||
: localize('typescript.noJavaScriptProjectConfig', 'File is not part of a JavaScript project')
|
||||
), {
|
||||
title: isTypeScriptProject
|
||||
? localize('typescript.configureTsconfigQuickPick', 'Configure tsconfig.json')
|
||||
: localize('typescript.configureJsconfigQuickPick', 'Configure jsconfig.json'),
|
||||
id: ProjectConfigAction.CreateConfig
|
||||
}, {
|
||||
title: localize('typescript.projectConfigLearnMore', 'Learn More'),
|
||||
id: ProjectConfigAction.LearnMore
|
||||
}).then(selected => {
|
||||
switch (selected && selected.id) {
|
||||
case ProjectConfigAction.CreateConfig:
|
||||
const configFile = Uri.file(path.join(rootPath, isTypeScriptProject ? 'tsconfig.json' : 'jsconfig.json'));
|
||||
return workspace.openTextDocument(configFile)
|
||||
.then(undefined, _ => workspace.openTextDocument(configFile.with({ scheme: 'untitled' })))
|
||||
.then(window.showTextDocument);
|
||||
|
||||
case ProjectConfigAction.LearnMore:
|
||||
if (isTypeScriptProject) {
|
||||
commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=841896'));
|
||||
} else {
|
||||
commands.executeCommand('vscode.open', Uri.parse('https://go.microsoft.com/fwlink/?linkid=759670'));
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private findLanguage(file: string): LanguageProvider | null {
|
||||
for (let i = 0; i < this.languages.length; i++) {
|
||||
let language = this.languages[i];
|
||||
|
||||
@@ -103,6 +103,7 @@ export interface ITypescriptServiceClient {
|
||||
execute(command: 'navtree', args: Proto.FileRequestArgs, token?: CancellationToken): Promise<Proto.NavTreeResponse>;
|
||||
execute(command: 'getCodeFixes', args: Proto.CodeFixRequestArgs, token?: CancellationToken): Promise<Proto.GetCodeFixesResponse>;
|
||||
execute(command: 'getSupportedCodeFixes', args: null, token?: CancellationToken): Promise<Proto.GetSupportedCodeFixesResponse>;
|
||||
execute(command: 'docCommentTemplate', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DocCommandTemplateResponse>;
|
||||
// execute(command: 'compileOnSaveAffectedFileList', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise<Proto.CompileOnSaveAffectedFileListResponse>;
|
||||
// execute(command: 'compileOnSaveEmitFile', args: Proto.CompileOnSaveEmitFileRequestArgs, token?: CancellationToken): Promise<any>;
|
||||
execute(command: string, args: any, expectedResult: boolean | CancellationToken, token?: CancellationToken): Promise<any>;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TextEditor, Position, Range, Selection } from 'vscode';
|
||||
|
||||
import { ITypescriptServiceClient } from '../typescriptService';
|
||||
|
||||
import { FileLocationRequestArgs, DocCommandTemplateResponse } from '../protocol';
|
||||
|
||||
export default class JsDocCompletionHelper {
|
||||
|
||||
constructor(
|
||||
private client: ITypescriptServiceClient,
|
||||
) { }
|
||||
|
||||
public tryCompleteJsDoc(editor: TextEditor, position: Position): Thenable<boolean> {
|
||||
const file = this.client.normalizePath(editor.document.uri);
|
||||
if (!file) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
const line = editor.document.lineAt(position.line).text;
|
||||
|
||||
// Ensure line starts with '/**' then cursor
|
||||
const prefix = line.slice(0, position.character).match(/^\s*(\/\*\*+)$/);
|
||||
if (!prefix) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
// Ensure there is no content after the cursor besides possibly the end of the comment
|
||||
const suffix = line.slice(position.character).match(/^\s*\**\/?$/);
|
||||
if (!suffix) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
const start = position.translate(0, -prefix[1].length);
|
||||
return editor.edit(
|
||||
edits => {
|
||||
edits.delete(new Range(start, new Position(start.line, line.length)));
|
||||
}, {
|
||||
undoStopBefore: true,
|
||||
undoStopAfter: false
|
||||
}
|
||||
).then(removedComment => {
|
||||
if (!removedComment) {
|
||||
// Edit failed, nothing to revert.
|
||||
return false;
|
||||
}
|
||||
|
||||
const args: FileLocationRequestArgs = {
|
||||
file: file,
|
||||
line: start.line + 1,
|
||||
offset: start.character + 1
|
||||
};
|
||||
|
||||
return Promise.race([
|
||||
this.client.execute('docCommentTemplate', args),
|
||||
new Promise((_, reject) => {
|
||||
setTimeout(reject, 250);
|
||||
})
|
||||
]).then((res: DocCommandTemplateResponse) => {
|
||||
if (!res || !res.body) {
|
||||
return false;
|
||||
}
|
||||
const commentText = res.body.newText;
|
||||
return editor.edit(
|
||||
edits => edits.insert(start, commentText),
|
||||
{ undoStopBefore: false, undoStopAfter: true });
|
||||
}, () => {
|
||||
return false;
|
||||
}).then(didInsertComment => {
|
||||
if (didInsertComment) {
|
||||
const newCursorPosition = new Position(start.line + 1, editor.document.lineAt(start.line + 1).text.length);
|
||||
editor.selection = new Selection(newCursorPosition, newCursorPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Revert to the original line content and restore position
|
||||
return editor.edit(
|
||||
edits => {
|
||||
edits.insert(start, prefix[1] + suffix[0]);
|
||||
}, {
|
||||
undoStopBefore: false,
|
||||
undoStopAfter: true
|
||||
}
|
||||
).then(() => {
|
||||
editor.selection = new Selection(position, position);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Generated
+8
-13
@@ -333,19 +333,14 @@
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz"
|
||||
},
|
||||
"node-pty": {
|
||||
"version": "0.6.1",
|
||||
"from": "node-pty@0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.6.1.tgz",
|
||||
"version": "0.6.2",
|
||||
"from": "node-pty@0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.6.2.tgz",
|
||||
"dependencies": {
|
||||
"extend": {
|
||||
"version": "1.2.1",
|
||||
"from": "extend@>=1.2.1 <1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.2.1",
|
||||
"from": "nan@2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz"
|
||||
"version": "2.5.0",
|
||||
"from": "nan@2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.5.0.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -430,9 +425,9 @@
|
||||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz"
|
||||
},
|
||||
"xterm": {
|
||||
"version": "2.2.3",
|
||||
"version": "2.3.0",
|
||||
"from": "Tyriar/xterm.js#vscode-release/1.10",
|
||||
"resolved": "git+https://github.com/Tyriar/xterm.js.git#90cd66bf353b86ad52d7b650760d8d879dd1c7b8"
|
||||
"resolved": "git+https://github.com/Tyriar/xterm.js.git#5513303451202b0135601a2f026602ed391b3906"
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.3.1",
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.10.0",
|
||||
"electronVersion": "1.4.6",
|
||||
"distro": "0edfcc54d5e8654b41e73aacb85adeda2461dcfe",
|
||||
"distro": "fdc80c6b4d95e5f961bd3f85b927693915550942",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -31,7 +31,7 @@
|
||||
"iconv-lite": "0.4.15",
|
||||
"minimist": "1.2.0",
|
||||
"native-keymap": "0.3.0",
|
||||
"node-pty": "0.6.1",
|
||||
"node-pty": "0.6.2",
|
||||
"semver": "4.3.6",
|
||||
"vscode-debugprotocol": "1.16.0",
|
||||
"vscode-textmate": "3.1.0",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"win32RegValueName": "CodeOSS",
|
||||
"win32AppId": "{{E34003BB-9E10-4501-8C11-BE3FAA83F23F}",
|
||||
"win32AppUserModelId": "Microsoft.CodeOSS",
|
||||
"win32ShellNameShort": "C&ode - OSS",
|
||||
"darwinBundleIdentifier": "com.visualstudio.code.oss",
|
||||
"reportIssueUrl": "https://github.com/Microsoft/vscode/issues/new",
|
||||
"urlProtocol": "code-oss"
|
||||
|
||||
@@ -30,10 +30,9 @@ if [ "@@NAME@@" != "code-oss" ]; then
|
||||
|
||||
APT_DIR=$(get_apt_config_value Dir)
|
||||
APT_ETC=$APT_DIR$(get_apt_config_value Dir::Etc)
|
||||
APT_SOURCE_PARTS=$APT_ETC$(get_apt_config_value Dir::Etc::sourceparts)
|
||||
CODE_SOURCE_LIST=$APT_SOURCE_PARTS/visual-studio-@@NAME@@.list
|
||||
APT_SOURCE_PARTS=$APT_ETC/$(get_apt_config_value Dir::Etc::sourceparts)
|
||||
CODE_SOURCE_LIST=$APT_SOURCE_PARTS/vscode.list
|
||||
|
||||
rm -f $CODE_SOURCE_LIST
|
||||
# TODO: #2973: Enable once the apt repository is signed
|
||||
#echo "deb @@UPDATEURL@@/api/deb/@@QUALITY@@/@@ARCHITECTURE@@/ /" > $CODE_SOURCE_LIST
|
||||
# echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > $CODE_SOURCE_LIST
|
||||
fi
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
@@ -19,7 +18,7 @@ else
|
||||
fi
|
||||
|
||||
INTENDED_VERSION="v`node -p "require('./package.json').electronVersion"`"
|
||||
INSTALLED_VERSION=`cat .build/electron/version 2> /dev/null`
|
||||
INSTALLED_VERSION=$(cat .build/electron/version 2> /dev/null)
|
||||
|
||||
# Node modules
|
||||
test -d node_modules || ./scripts/npm.sh install
|
||||
|
||||
@@ -21,17 +21,12 @@ export interface IListElementEvent<T, E> {
|
||||
event: E;
|
||||
}
|
||||
|
||||
export interface IListEvent<T> {
|
||||
elements: T[];
|
||||
indexes: number[];
|
||||
}
|
||||
|
||||
export interface IListMouseEvent<T> extends MouseEvent {
|
||||
element: T;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface IFocusChangeEvent<T> {
|
||||
elements: T[];
|
||||
indexes: number[];
|
||||
}
|
||||
|
||||
export interface ISelectionChangeEvent<T> {
|
||||
elements: T[];
|
||||
indexes: number[];
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./list';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { IDelegate, IRenderer, IFocusChangeEvent, ISelectionChangeEvent } from './list';
|
||||
import { IDelegate, IRenderer, IListEvent } from './list';
|
||||
import { List, IListOptions } from './listWidget';
|
||||
import { IPagedModel } from 'vs/base/common/paging';
|
||||
import Event, { mapEvent } from 'vs/base/common/event';
|
||||
@@ -67,7 +67,7 @@ export class PagedList<T> {
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<number>,
|
||||
renderers: IPagedRenderer<T, any>[],
|
||||
options: IListOptions = {}
|
||||
options: IListOptions<any> = {} // TODO@Joao: should be IListOptions<T>
|
||||
) {
|
||||
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
|
||||
this.list = new List(container, delegate, pagedRenderers, options);
|
||||
@@ -77,11 +77,11 @@ export class PagedList<T> {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
get onFocusChange(): Event<IFocusChangeEvent<T>> {
|
||||
get onFocusChange(): Event<IListEvent<T>> {
|
||||
return mapEvent(this.list.onFocusChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
|
||||
}
|
||||
|
||||
get onSelectionChange(): Event<ISelectionChangeEvent<T>> {
|
||||
get onSelectionChange(): Event<IListEvent<T>> {
|
||||
return mapEvent(this.list.onSelectionChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,26 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import Event, { Emitter, EventBufferer, chain, mapEvent, fromCallback } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list';
|
||||
import { IDelegate, IRenderer, IListEvent, IListMouseEvent } from './list';
|
||||
import { ListView, IListViewOptions } from './listView';
|
||||
|
||||
export interface IIdentityProvider<T> {
|
||||
(element: T): string;
|
||||
}
|
||||
|
||||
export interface ISpliceable<T> {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void;
|
||||
}
|
||||
|
||||
class CombinedSpliceable<T> implements ISpliceable<T> {
|
||||
|
||||
constructor(private spliceables: ISpliceable<T>[]) { }
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
this.spliceables.forEach(s => s.splice(start, deleteCount, elements));
|
||||
}
|
||||
}
|
||||
|
||||
interface ITraitTemplateData<D> {
|
||||
container: HTMLElement;
|
||||
data: D;
|
||||
@@ -52,7 +69,7 @@ class TraitRenderer<T, D> implements IRenderer<T, ITraitTemplateData<D>>
|
||||
}
|
||||
}
|
||||
|
||||
class Trait<T> implements IDisposable {
|
||||
class Trait<T> implements ISpliceable<boolean>, IDisposable {
|
||||
|
||||
private indexes: number[];
|
||||
|
||||
@@ -63,21 +80,16 @@ class Trait<T> implements IDisposable {
|
||||
this.indexes = [];
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, insertCount: number): void {
|
||||
const diff = insertCount - deleteCount;
|
||||
splice(start: number, deleteCount: number, elements: boolean[]): void {
|
||||
const diff = elements.length - deleteCount;
|
||||
const end = start + deleteCount;
|
||||
const indexes: number[] = [];
|
||||
const indexes = [
|
||||
...this.indexes.filter(i => i < start),
|
||||
...elements.reduce((r, hasTrait, i) => hasTrait ? [...r, i + start] : r, []),
|
||||
...this.indexes.filter(i => i >= end).map(i => i + diff)
|
||||
];
|
||||
|
||||
for (let index of indexes) {
|
||||
if (index >= start && index < end) {
|
||||
continue;
|
||||
}
|
||||
|
||||
indexes.push(index > start ? index + diff : index);
|
||||
}
|
||||
|
||||
this.indexes = indexes;
|
||||
this._onChange.fire({ indexes });
|
||||
this.set(indexes);
|
||||
}
|
||||
|
||||
renderElement(element: T, index: number, container: HTMLElement): void {
|
||||
@@ -111,14 +123,41 @@ class Trait<T> implements IDisposable {
|
||||
|
||||
class FocusTrait<T> extends Trait<T> {
|
||||
|
||||
constructor(private getElementId: (number: number) => string) {
|
||||
constructor(
|
||||
private getDomId: IIdentityProvider<number>
|
||||
) {
|
||||
super('focused');
|
||||
}
|
||||
|
||||
renderElement(element: T, index: number, container: HTMLElement): void {
|
||||
super.renderElement(element, index, container);
|
||||
container.setAttribute('role', 'treeitem');
|
||||
container.setAttribute('id', this.getElementId(index));
|
||||
container.setAttribute('id', this.getDomId(index));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The TraitSpliceable is used as a util class to be able
|
||||
* to preserve traits across splice calls, given an identity
|
||||
* provider.
|
||||
*/
|
||||
class TraitSpliceable<T> implements ISpliceable<T> {
|
||||
|
||||
constructor(
|
||||
private trait: Trait<T>,
|
||||
private view: ListView<T>,
|
||||
private getId?: IIdentityProvider<T>
|
||||
) { }
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
if (!this.getId) {
|
||||
return this.trait.splice(start, deleteCount, elements.map(e => false));
|
||||
}
|
||||
|
||||
const pastElementsWithTrait = this.trait.get().map(i => this.getId(this.view.element(i)));
|
||||
const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.getId(e)) > -1);
|
||||
|
||||
this.trait.splice(start, deleteCount, elementsWithTrait);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +183,7 @@ class KeyboardController<T> implements IDisposable {
|
||||
private onEnter(e: StandardKeyboardEvent): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.list.setSelection(this.list.getFocus());
|
||||
this.list.open(this.list.getFocus());
|
||||
}
|
||||
|
||||
private onUpArrow(e: StandardKeyboardEvent): void {
|
||||
@@ -185,6 +224,7 @@ class KeyboardController<T> implements IDisposable {
|
||||
}
|
||||
|
||||
class MouseController<T> implements IDisposable {
|
||||
|
||||
private disposables: IDisposable[];
|
||||
|
||||
constructor(
|
||||
@@ -207,7 +247,7 @@ class MouseController<T> implements IDisposable {
|
||||
e.stopPropagation();
|
||||
this.view.domNode.focus();
|
||||
this.list.setFocus([e.index]);
|
||||
this.list.setSelection([e.index]);
|
||||
this.list.open([e.index]);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -215,18 +255,19 @@ class MouseController<T> implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
export interface IListOptions extends IListViewOptions {
|
||||
export interface IListOptions<T> extends IListViewOptions {
|
||||
identityProvider?: IIdentityProvider<T>;
|
||||
ariaLabel?: string;
|
||||
mouseSupport?: boolean;
|
||||
keyboardSupport?: boolean;
|
||||
}
|
||||
|
||||
const DefaultOptions: IListOptions = {
|
||||
const DefaultOptions: IListOptions<any> = {
|
||||
keyboardSupport: true,
|
||||
mouseSupport: true
|
||||
};
|
||||
|
||||
export class List<T> implements IDisposable {
|
||||
export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
private static InstanceCount = 0;
|
||||
private idPrefix = `list_id_${++List.InstanceCount}`;
|
||||
@@ -235,25 +276,26 @@ export class List<T> implements IDisposable {
|
||||
private selection: Trait<T>;
|
||||
private eventBufferer: EventBufferer;
|
||||
private view: ListView<T>;
|
||||
private mouseController: MouseController<T>;
|
||||
private keyboardController: KeyboardController<T>;
|
||||
private spliceable: ISpliceable<T>;
|
||||
private disposables: IDisposable[];
|
||||
|
||||
@memoize
|
||||
get onFocusChange(): Event<IFocusChangeEvent<T>> {
|
||||
return this.eventBufferer.wrapEvent(mapEvent(this.focus.onChange, e => this.toListEvent(e)));
|
||||
@memoize get onFocusChange(): Event<IListEvent<T>> {
|
||||
return mapEvent(this.eventBufferer.wrapEvent(this.focus.onChange), e => this.toListEvent(e));
|
||||
}
|
||||
|
||||
@memoize
|
||||
get onSelectionChange(): Event<ISelectionChangeEvent<T>> {
|
||||
return this.eventBufferer.wrapEvent(mapEvent(this.selection.onChange, e => this.toListEvent(e)));
|
||||
@memoize get onSelectionChange(): Event<IListEvent<T>> {
|
||||
return mapEvent(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e));
|
||||
}
|
||||
|
||||
@memoize
|
||||
get onContextMenu(): Event<IListMouseEvent<T>> {
|
||||
@memoize get onContextMenu(): Event<IListMouseEvent<T>> {
|
||||
return fromCallback(handler => this.view.addListener('contextmenu', handler));
|
||||
}
|
||||
|
||||
private _onOpen = new Emitter<number[]>();
|
||||
@memoize get onOpen(): Event<IListEvent<T>> {
|
||||
return mapEvent(this._onOpen.event, indexes => this.toListEvent({ indexes }));
|
||||
}
|
||||
|
||||
private _onDOMFocus = new Emitter<void>();
|
||||
get onDOMFocus(): Event<void> { return this._onDOMFocus.event; }
|
||||
|
||||
@@ -267,9 +309,9 @@ export class List<T> implements IDisposable {
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<T>,
|
||||
renderers: IRenderer<T, any>[],
|
||||
options: IListOptions = DefaultOptions
|
||||
options: IListOptions<T> = DefaultOptions
|
||||
) {
|
||||
this.focus = new FocusTrait(i => this.getElementId(i));
|
||||
this.focus = new FocusTrait(i => this.getElementDomId(i));
|
||||
this.selection = new Trait('selected');
|
||||
this.eventBufferer = new EventBufferer();
|
||||
|
||||
@@ -283,6 +325,12 @@ export class List<T> implements IDisposable {
|
||||
this.view.domNode.setAttribute('role', 'tree');
|
||||
this.view.domNode.tabIndex = 0;
|
||||
|
||||
this.spliceable = new CombinedSpliceable([
|
||||
new TraitSpliceable(this.focus, this.view, options.identityProvider),
|
||||
new TraitSpliceable(this.selection, this.view, options.identityProvider),
|
||||
this.view
|
||||
]);
|
||||
|
||||
this.disposables = [this.focus, this.selection, this.view, this._onDispose];
|
||||
|
||||
const tracker = DOM.trackFocus(this.view.domNode);
|
||||
@@ -290,13 +338,11 @@ export class List<T> implements IDisposable {
|
||||
this.disposables.push(tracker.addBlurListener(() => this._onDOMBlur.fire()));
|
||||
|
||||
if (typeof options.keyboardSupport !== 'boolean' || options.keyboardSupport) {
|
||||
this.keyboardController = new KeyboardController(this, this.view);
|
||||
this.disposables.push(this.keyboardController);
|
||||
this.disposables.push(new KeyboardController(this, this.view));
|
||||
}
|
||||
|
||||
if (typeof options.mouseSupport !== 'boolean' || options.mouseSupport) {
|
||||
this.mouseController = new MouseController(this, this.view);
|
||||
this.disposables.push(this.mouseController);
|
||||
this.disposables.push(new MouseController(this, this.view));
|
||||
}
|
||||
|
||||
this.onFocusChange(this._onFocusChange, this, this.disposables);
|
||||
@@ -307,11 +353,7 @@ export class List<T> implements IDisposable {
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[] = []): void {
|
||||
this.eventBufferer.bufferEvents(() => {
|
||||
this.focus.splice(start, deleteCount, elements.length);
|
||||
this.selection.splice(start, deleteCount, elements.length);
|
||||
this.view.splice(start, deleteCount, elements);
|
||||
});
|
||||
this.eventBufferer.bufferEvents(() => this.spliceable.splice(start, deleteCount, elements));
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
@@ -461,7 +503,7 @@ export class List<T> implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
getElementId(index: number): string {
|
||||
private getElementDomId(index: number): string {
|
||||
return `${this.idPrefix}_${index}`;
|
||||
}
|
||||
|
||||
@@ -473,6 +515,11 @@ export class List<T> implements IDisposable {
|
||||
return this.view.domNode;
|
||||
}
|
||||
|
||||
open(indexes: number[]): void {
|
||||
this.setSelection(indexes);
|
||||
this._onOpen.fire(indexes);
|
||||
}
|
||||
|
||||
private toListEvent({ indexes }: ITraitChangeEvent) {
|
||||
return { indexes, elements: indexes.map(i => this.view.element(i)) };
|
||||
}
|
||||
@@ -481,7 +528,7 @@ export class List<T> implements IDisposable {
|
||||
const focus = this.focus.get();
|
||||
|
||||
if (focus.length > 0) {
|
||||
this.view.domNode.setAttribute('aria-activedescendant', this.getElementId(focus[0]));
|
||||
this.view.domNode.setAttribute('aria-activedescendant', this.getElementDomId(focus[0]));
|
||||
} else {
|
||||
this.view.domNode.removeAttribute('aria-activedescendant');
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IEventEmitter, EventEmitter } from 'vs/base/common/eventEmitter';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as Events from 'vs/base/common/events';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
export interface IAction extends IDisposable {
|
||||
id: string;
|
||||
@@ -202,7 +203,7 @@ export class Action implements IAction {
|
||||
this._order = value;
|
||||
}
|
||||
|
||||
public run(event?: any): TPromise<any> {
|
||||
public run(event?: any, data?: ITelemetryData): TPromise<any> {
|
||||
if (this._actionCallback !== void 0) {
|
||||
return this._actionCallback(event);
|
||||
}
|
||||
|
||||
@@ -99,6 +99,17 @@ function hsla2rgba(hsla: HSLA): RGBA {
|
||||
return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), a };
|
||||
}
|
||||
|
||||
export function hexToCSS(hex: string) {
|
||||
if (hex.length === 9) {
|
||||
return toCSSColor(hex2rgba(hex));
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
function toCSSColor(rgba: RGBA): string {
|
||||
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${+rgba.a.toFixed(2)})`;
|
||||
}
|
||||
|
||||
export class Color {
|
||||
|
||||
private rgba: RGBA;
|
||||
@@ -194,8 +205,7 @@ export class Color {
|
||||
|
||||
public toString(): string {
|
||||
if (!this.str) {
|
||||
let p = this.rgba;
|
||||
this.str = `rgba(${p.r}, ${p.g}, ${p.b}, ${+p.a.toFixed(2)})`;
|
||||
this.str = toCSSColor(this.rgba);
|
||||
}
|
||||
return this.str;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export function setProperty(text: string, path: JSONPath, value: any, formatting
|
||||
}
|
||||
} else {
|
||||
if (value === void 0) { // delete
|
||||
throw new Error(`Property ${lastSegment} does not exist.`);
|
||||
return []; // property does not exist, nothing to do
|
||||
}
|
||||
let newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
|
||||
let index = getInsertionIndex ? getInsertionIndex(parent.children.map(p => p.children[0].value)) : parent.children.length;
|
||||
|
||||
@@ -21,6 +21,7 @@ import { getCommonHTTPHeaders } from 'vs/platform/environment/node/http';
|
||||
import { IWindowSettings, MenuBarVisibility } from 'vs/platform/windows/common/windows';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
||||
export interface IWindowState {
|
||||
width?: number;
|
||||
height?: number;
|
||||
@@ -78,6 +79,7 @@ export interface IWindowConfiguration extends ParsedArgs {
|
||||
zoomLevel?: number;
|
||||
fullscreen?: boolean;
|
||||
highContrast?: boolean;
|
||||
baseTheme?: string;
|
||||
accessibilitySupport?: boolean;
|
||||
|
||||
isInitialStartup?: boolean;
|
||||
@@ -134,7 +136,7 @@ export interface IVSCodeWindow {
|
||||
|
||||
export class VSCodeWindow implements IVSCodeWindow {
|
||||
|
||||
public static colorThemeStorageKey = 'theme';
|
||||
public static themeStorageKey = 'theme';
|
||||
|
||||
private static MIN_WIDTH = 200;
|
||||
private static MIN_HEIGHT = 120;
|
||||
@@ -177,9 +179,9 @@ export class VSCodeWindow implements IVSCodeWindow {
|
||||
this.restoreWindowState(config.state);
|
||||
|
||||
// For VS theme we can show directly because background is white
|
||||
const themeId = this.storageService.getItem<string>(VSCodeWindow.colorThemeStorageKey);
|
||||
const usesLightTheme = /vs($| )/.test(themeId);
|
||||
const usesHighContrastTheme = /hc-black($| )/.test(themeId) || (platform.isWindows && systemPreferences.isInvertedColorScheme());
|
||||
const baseTheme = this.getBaseTheme();
|
||||
const usesLightTheme = 'vs' === baseTheme;
|
||||
const usesHighContrastTheme = 'hc-black' === baseTheme || (platform.isWindows && systemPreferences.isInvertedColorScheme());
|
||||
|
||||
// in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below)
|
||||
const isFullscreenOrMaximized = (this.currentWindowMode === WindowMode.Maximized || this.currentWindowMode === WindowMode.Fullscreen);
|
||||
@@ -505,6 +507,9 @@ export class VSCodeWindow implements IVSCodeWindow {
|
||||
windowConfiguration.highContrast = platform.isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast);
|
||||
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
|
||||
|
||||
// Theme
|
||||
windowConfiguration.baseTheme = this.getBaseTheme();
|
||||
|
||||
// Perf Counters
|
||||
windowConfiguration.perfStartTime = global.perfStartTime;
|
||||
windowConfiguration.perfAppReady = global.perfAppReady;
|
||||
@@ -524,6 +529,11 @@ export class VSCodeWindow implements IVSCodeWindow {
|
||||
return url;
|
||||
}
|
||||
|
||||
private getBaseTheme(): string {
|
||||
const theme = this.storageService.getItem<string>(VSCodeWindow.themeStorageKey, 'vs-dark');
|
||||
return theme.split(' ')[0];
|
||||
}
|
||||
|
||||
public serializeWindowState(): IWindowState {
|
||||
if (this.win.isFullScreen()) {
|
||||
return {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { ILogService } from 'vs/code/electron-main/log';
|
||||
import { getPathLabel } from 'vs/base/common/labels';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWindowSettings } from 'vs/platform/windows/common/windows';
|
||||
import { getLastActiveWindow, OpenContext as OriginalOpenContext, findBestWindowOrFolder } from 'vs/code/node/windowsUtils';
|
||||
import CommonEvent, { Emitter } from 'vs/base/common/event';
|
||||
import product from 'vs/platform/node/product';
|
||||
|
||||
@@ -34,26 +35,8 @@ enum WindowError {
|
||||
CRASHED
|
||||
}
|
||||
|
||||
export enum OpenContext {
|
||||
|
||||
// opening when running from the command line
|
||||
CLI,
|
||||
|
||||
// macOS only: opening from the dock (also when opening files to a running instance from desktop)
|
||||
DOCK,
|
||||
|
||||
// opening from the main application window
|
||||
MENU,
|
||||
|
||||
// opening from a file or folder dialog
|
||||
DIALOG,
|
||||
|
||||
// opening from the OS's UI
|
||||
DESKTOP,
|
||||
|
||||
// opening through the API
|
||||
API
|
||||
}
|
||||
export const OpenContext = OriginalOpenContext;
|
||||
export type OpenContext = OriginalOpenContext;
|
||||
|
||||
export interface IOpenConfiguration {
|
||||
context: OpenContext;
|
||||
@@ -292,10 +275,9 @@ export class WindowsManager implements IWindowsMainService {
|
||||
|
||||
// Theme changes
|
||||
if (event === 'vscode:changeColorTheme' && typeof payload === 'string') {
|
||||
this.storageService.setItem(VSCodeWindow.colorThemeStorageKey, payload);
|
||||
this.storageService.setItem(VSCodeWindow.themeStorageKey, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public reload(win: VSCodeWindow, cli?: ParsedArgs): void {
|
||||
|
||||
// Only reload when the window has not vetoed this
|
||||
@@ -409,20 +391,28 @@ export class WindowsManager implements IWindowsMainService {
|
||||
}
|
||||
|
||||
// Open Files in last instance if any and flag tells us so
|
||||
let bestWindow;
|
||||
if (!openFilesInNewWindow && (bestWindow = this.findBestWindow(openConfig.context, [...filesToOpen, ...filesToCreate, ...filesToDiff]))) {
|
||||
bestWindow.focus();
|
||||
const fileToCheck = filesToOpen[0] || filesToCreate[0] || filesToDiff[0];
|
||||
const windowOrFolder = findBestWindowOrFolder({
|
||||
windows: WindowsManager.WINDOWS,
|
||||
newWindow: openFilesInNewWindow,
|
||||
reuseWindow: openConfig.forceReuseWindow,
|
||||
context: openConfig.context,
|
||||
filePath: fileToCheck && fileToCheck.filePath,
|
||||
userHome: this.environmentService.userHome
|
||||
});
|
||||
if (windowOrFolder instanceof VSCodeWindow) {
|
||||
windowOrFolder.focus();
|
||||
const files = { filesToOpen, filesToCreate, filesToDiff }; // copy to object because they get reset shortly after
|
||||
bestWindow.ready().then(readyWindow => {
|
||||
windowOrFolder.ready().then(readyWindow => {
|
||||
readyWindow.send('vscode:openFiles', files);
|
||||
});
|
||||
|
||||
usedWindows.push(bestWindow);
|
||||
usedWindows.push(windowOrFolder);
|
||||
}
|
||||
|
||||
// Otherwise open instance with files
|
||||
else {
|
||||
const configuration = this.toConfiguration(openConfig, null, filesToOpen, filesToCreate, filesToDiff);
|
||||
const configuration = this.toConfiguration(openConfig, windowOrFolder, filesToOpen, filesToCreate, filesToDiff);
|
||||
const browserWindow = this.openInBrowserWindow(configuration, true /* new window */);
|
||||
usedWindows.push(browserWindow);
|
||||
|
||||
@@ -530,7 +520,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
|
||||
const mru = this.getRecentPathsList();
|
||||
paths.forEach(p => {
|
||||
const {path, isFile} = p;
|
||||
const { path, isFile } = p;
|
||||
|
||||
if (isFile) {
|
||||
mru.files.unshift(path);
|
||||
@@ -1026,31 +1016,8 @@ export class WindowsManager implements IWindowsMainService {
|
||||
return res && res[0];
|
||||
}
|
||||
|
||||
private findBestWindow(context: OpenContext, filePaths: IPath[]): VSCodeWindow {
|
||||
const findContainer = context === OpenContext.DESKTOP || context === OpenContext.CLI;
|
||||
return (findContainer && this.findContainingWindow(filePaths)) || this.getLastActiveWindow();
|
||||
}
|
||||
|
||||
private findContainingWindow(filePaths: IPath[]): VSCodeWindow {
|
||||
for (const filePath of filePaths) {
|
||||
const windows = WindowsManager.WINDOWS.filter(window => typeof window.openedWorkspacePath === 'string' && paths.isEqualOrParent(filePath.filePath, window.openedWorkspacePath));
|
||||
if (windows.length) {
|
||||
return windows.sort((a, b) => -(a.openedWorkspacePath.length - b.openedWorkspacePath.length))[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getLastActiveWindow(): VSCodeWindow {
|
||||
if (WindowsManager.WINDOWS.length) {
|
||||
const lastFocussedDate = Math.max.apply(Math, WindowsManager.WINDOWS.map(w => w.lastFocusTime));
|
||||
const res = WindowsManager.WINDOWS.filter(w => w.lastFocusTime === lastFocussedDate);
|
||||
if (res && res.length) {
|
||||
return res[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return getLastActiveWindow(WindowsManager.WINDOWS);
|
||||
}
|
||||
|
||||
public findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): VSCodeWindow {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'original-fs';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
|
||||
export enum OpenContext {
|
||||
|
||||
// opening when running from the command line
|
||||
CLI,
|
||||
|
||||
// macOS only: opening from the dock (also when opening files to a running instance from desktop)
|
||||
DOCK,
|
||||
|
||||
// opening from the main application window
|
||||
MENU,
|
||||
|
||||
// opening from a file or folder dialog
|
||||
DIALOG,
|
||||
|
||||
// opening from the OS's UI
|
||||
DESKTOP,
|
||||
|
||||
// opening through the API
|
||||
API
|
||||
}
|
||||
|
||||
/**
|
||||
* Exported subset of VSCodeWindow for testing.
|
||||
*/
|
||||
export interface ISimpleWindow {
|
||||
openedWorkspacePath: string;
|
||||
lastFocusTime: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exported for testing.
|
||||
*/
|
||||
export interface IBestWindowOrFolderOptions<WINDOW> {
|
||||
windows: WINDOW[];
|
||||
newWindow: boolean;
|
||||
reuseWindow: boolean;
|
||||
context: OpenContext;
|
||||
filePath?: string;
|
||||
userHome?: string;
|
||||
vscodeFolder?: string;
|
||||
}
|
||||
|
||||
export function findBestWindowOrFolder<WINDOW extends ISimpleWindow>({ windows, newWindow, reuseWindow, context, filePath, userHome, vscodeFolder }: IBestWindowOrFolderOptions<WINDOW>): WINDOW | string {
|
||||
// OpenContext.DOCK implies newWindow unless overwritten by settings.
|
||||
const findBest = filePath && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK);
|
||||
const bestWindow = !newWindow && findBest && findBestWindow(windows, filePath);
|
||||
const bestFolder = !newWindow && !reuseWindow && findBest && findBestFolder(filePath, userHome, vscodeFolder);
|
||||
if (bestWindow && !(bestFolder && bestFolder.length > bestWindow.openedWorkspacePath.length)) {
|
||||
return bestWindow;
|
||||
} else if (bestFolder) {
|
||||
return bestFolder;
|
||||
}
|
||||
return !newWindow ? getLastActiveWindow(windows) : null;
|
||||
}
|
||||
|
||||
function findBestWindow<WINDOW extends ISimpleWindow>(windows: WINDOW[], filePath: string): WINDOW {
|
||||
const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && paths.isEqualOrParent(filePath, window.openedWorkspacePath));
|
||||
if (containers.length) {
|
||||
return containers.sort((a, b) => -(a.openedWorkspacePath.length - b.openedWorkspacePath.length))[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findBestFolder(filePath: string, userHome?: string, vscodeFolder?: string): string {
|
||||
let folder = path.dirname(paths.normalize(filePath, true));
|
||||
let homeFolder = userHome && paths.normalize(userHome, true);
|
||||
if (!platform.isLinux) {
|
||||
homeFolder = homeFolder && homeFolder.toLowerCase();
|
||||
}
|
||||
let previous = null;
|
||||
try {
|
||||
while (folder !== previous) {
|
||||
if (isProjectFolder(folder, homeFolder, vscodeFolder)) {
|
||||
return folder;
|
||||
}
|
||||
previous = folder;
|
||||
folder = path.dirname(folder);
|
||||
}
|
||||
} catch (err) {
|
||||
// assume impossible to access
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isProjectFolder(folder: string, normalizedUserHome?: string, vscodeFolder = '.vscode') {
|
||||
try {
|
||||
if ((platform.isLinux ? folder : folder.toLowerCase()) === normalizedUserHome) {
|
||||
// ~/.vscode/extensions is used for extensions
|
||||
return fs.statSync(path.join(folder, vscodeFolder, 'settings.json')).isFile();
|
||||
} else {
|
||||
return fs.statSync(path.join(folder, vscodeFolder)).isDirectory();
|
||||
}
|
||||
} catch (err) {
|
||||
if (!(err && err.code === 'ENOENT')) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getLastActiveWindow<WINDOW extends ISimpleWindow>(windows: WINDOW[]): WINDOW {
|
||||
if (windows.length) {
|
||||
const lastFocussedDate = Math.max.apply(Math, windows.map(w => w.lastFocusTime));
|
||||
const res = windows.filter(w => w.lastFocusTime === lastFocussedDate);
|
||||
if (res && res.length) {
|
||||
return res[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import assert = require('assert');
|
||||
import path = require('path');
|
||||
import { findBestWindowOrFolder, OpenContext, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsUtils';
|
||||
|
||||
const fixturesFolder = require.toUrl('./fixtures');
|
||||
|
||||
function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): IBestWindowOrFolderOptions<ISimpleWindow> {
|
||||
return {
|
||||
windows: [],
|
||||
newWindow: false,
|
||||
reuseWindow: false,
|
||||
context: OpenContext.CLI,
|
||||
vscodeFolder: '_vscode',
|
||||
...custom
|
||||
};
|
||||
}
|
||||
|
||||
const vscodeFolderWindow = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder') };
|
||||
const lastActiveWindow = { lastFocusTime: 3, openedWorkspacePath: null };
|
||||
const noVscodeFolderWindow = { lastFocusTime: 2, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder') };
|
||||
const windows = [
|
||||
vscodeFolderWindow,
|
||||
lastActiveWindow,
|
||||
noVscodeFolderWindow,
|
||||
];
|
||||
|
||||
suite('WindowsUtils', () => {
|
||||
|
||||
test('New window without folder when no windows exist', () => {
|
||||
assert.equal(findBestWindowOrFolder(options()), null);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'file.txt')
|
||||
})), null);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt'),
|
||||
newWindow: true // We assume this implies 'editor' work mode, might need separate CLI option later.
|
||||
})), null);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt'),
|
||||
reuseWindow: true // We assume this implies 'editor' work mode, might need separate CLI option later.
|
||||
})), null);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt'),
|
||||
context: OpenContext.API
|
||||
})), null);
|
||||
});
|
||||
|
||||
test('New window with folder when no windows exist', () => {
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt')
|
||||
})), path.join(fixturesFolder, 'vscode_folder'));
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'new_folder', 'new_file.txt')
|
||||
})), path.join(fixturesFolder, 'vscode_folder'));
|
||||
});
|
||||
|
||||
test('New window without folder when windows exist', () => {
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows,
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'file.txt'),
|
||||
newWindow: true
|
||||
})), null);
|
||||
});
|
||||
|
||||
test('Last active window', () => {
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows
|
||||
})), lastActiveWindow);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows,
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder2', 'file.txt')
|
||||
})), lastActiveWindow);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [lastActiveWindow, noVscodeFolderWindow],
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt'),
|
||||
reuseWindow: true
|
||||
})), lastActiveWindow);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows,
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'file.txt'),
|
||||
context: OpenContext.API
|
||||
})), lastActiveWindow);
|
||||
});
|
||||
|
||||
test('Existing window with folder', () => {
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows,
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'file.txt')
|
||||
})), noVscodeFolderWindow);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows,
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt')
|
||||
})), vscodeFolderWindow);
|
||||
});
|
||||
|
||||
test('Existing window wins over vscode folder if more specific', () => {
|
||||
const window = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder') };
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [window],
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt')
|
||||
})), window);
|
||||
// check
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [window],
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder2', 'subfolder', 'file.txt')
|
||||
})), path.join(fixturesFolder, 'vscode_folder'));
|
||||
});
|
||||
|
||||
test('More specific existing window wins', () => {
|
||||
const window = { lastFocusTime: 2, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder') };
|
||||
const nestedFolderWindow = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder') };
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [window, nestedFolderWindow],
|
||||
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt')
|
||||
})), nestedFolderWindow);
|
||||
});
|
||||
|
||||
test('VSCode folder wins over existing window if more specific', () => {
|
||||
const window = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder') };
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [window],
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_vscode_folder', 'subfolder', 'file.txt')
|
||||
})), path.join(fixturesFolder, 'vscode_folder', 'nested_vscode_folder'));
|
||||
// check
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
windows: [window],
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt')
|
||||
})), window);
|
||||
});
|
||||
|
||||
test('More specific VSCode folder wins', () => {
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_vscode_folder', 'subfolder', 'file.txt')
|
||||
})), path.join(fixturesFolder, 'vscode_folder', 'nested_vscode_folder'));
|
||||
});
|
||||
|
||||
test('VSCode folder in home folder needs settings.json', () => {
|
||||
// Because ~/.vscode/extensions is used for extensions, ~/.vscode is not enough as a hint.
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_folder', 'file.txt'),
|
||||
userHome: path.join(fixturesFolder, 'vscode_folder')
|
||||
})), null);
|
||||
assert.equal(findBestWindowOrFolder(options({
|
||||
filePath: path.join(fixturesFolder, 'vscode_home_folder', 'file.txt'),
|
||||
userHome: path.join(fixturesFolder, 'vscode_home_folder')
|
||||
})), path.join(fixturesFolder, 'vscode_home_folder'));
|
||||
});
|
||||
});
|
||||
@@ -29,9 +29,12 @@ class ClipboardEventWrapper implements IClipboardEvent {
|
||||
return false;
|
||||
}
|
||||
|
||||
public setTextData(text: string): void {
|
||||
public setTextData(text: string, richText: string): void {
|
||||
if (this._event.clipboardData) {
|
||||
this._event.clipboardData.setData('text/plain', text);
|
||||
if (richText !== null) {
|
||||
this._event.clipboardData.setData('text/html', richText);
|
||||
}
|
||||
this._event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ import { IDisposable, IReference, ImmortalReference, combinedDisposable } from '
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { MenuId, MenuRegistry, ICommandAction, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { Menu } from 'vs/platform/actions/common/menu';
|
||||
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
@@ -428,10 +427,6 @@ export class SimpleMenuService implements IMenuService {
|
||||
public createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
|
||||
return new Menu(id, TPromise.as(true), this._commandService, contextKeyService);
|
||||
}
|
||||
|
||||
public getCommandActions(): ICommandAction[] {
|
||||
return values(MenuRegistry.commands);
|
||||
}
|
||||
}
|
||||
|
||||
export class StandaloneTelemetryService implements ITelemetryService {
|
||||
|
||||
@@ -1006,6 +1006,10 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom
|
||||
protected abstract _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void;
|
||||
protected abstract _removeDecorationType(key: string): void;
|
||||
protected abstract _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions;
|
||||
|
||||
public getTelemetryData(): { [key: string]: any; } {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class EditorContextKeysManager extends Disposable {
|
||||
|
||||
@@ -11,8 +11,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IClipboardEvent, ICompositionEvent, IKeyboardEventWrapper, ISimpleModel, ITextAreaWrapper, ITypeData, TextAreaState, TextAreaStrategy, createTextAreaState } from 'vs/editor/common/controller/textAreaState';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
|
||||
import { InternalEditorOptions } from 'vs/editor/common/editorCommon';
|
||||
|
||||
const enum ReadFromTextArea {
|
||||
Type,
|
||||
@@ -324,9 +323,13 @@ export class TextAreaHandler extends Disposable {
|
||||
// ------------- Clipboard operations
|
||||
|
||||
private _ensureClipboardGetsEditorSelection(e: IClipboardEvent): void {
|
||||
let whatToCopy = this._getPlainTextToCopy();
|
||||
let whatToCopy = this.model.getPlainTextToCopy(this.selections, this.Browser.enableEmptySelectionClipboard);
|
||||
if (e.canUseTextData()) {
|
||||
e.setTextData(whatToCopy);
|
||||
let whatHTMLToCopy = null;
|
||||
if (!this.Browser.isEdgeOrIE && (whatToCopy.length < 65536 || InternalEditorOptions.forceCopyWithSyntaxHighlighting)) {
|
||||
whatHTMLToCopy = this.model.getHTMLToCopy(this.selections, this.Browser.enableEmptySelectionClipboard);
|
||||
}
|
||||
e.setTextData(whatToCopy, whatHTMLToCopy);
|
||||
} else {
|
||||
this.setTextAreaState('copy or cut', this.textAreaState.fromText(whatToCopy), false);
|
||||
}
|
||||
@@ -344,31 +347,4 @@ export class TextAreaHandler extends Disposable {
|
||||
this.lastCopiedValueIsFromEmptySelection = (selections.length === 1 && selections[0].isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
private _getPlainTextToCopy(): string {
|
||||
let newLineCharacter = this.model.getEOL();
|
||||
let selections = this.selections;
|
||||
|
||||
if (selections.length === 1) {
|
||||
let range: Range = selections[0];
|
||||
if (range.isEmpty()) {
|
||||
if (this.Browser.enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.model.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
return this.model.getModelLineContent(modelLineNumber) + newLineCharacter;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return this.model.getValueInRange(range, EndOfLinePreference.TextDefined);
|
||||
} else {
|
||||
selections = selections.slice(0).sort(Range.compareRangesUsingStarts);
|
||||
let result: string[] = [];
|
||||
for (let i = 0; i < selections.length; i++) {
|
||||
result.push(this.model.getValueInRange(selections[i], EndOfLinePreference.TextDefined));
|
||||
}
|
||||
|
||||
return result.join(newLineCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import { Constants } from 'vs/editor/common/core/uint';
|
||||
|
||||
export interface IClipboardEvent {
|
||||
canUseTextData(): boolean;
|
||||
setTextData(text: string): void;
|
||||
setTextData(text: string, richText: string): void;
|
||||
getTextData(): string;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ export interface ISimpleModel {
|
||||
getValueInRange(range: Range, eol: EndOfLinePreference): string;
|
||||
getModelLineContent(lineNumber: number): string;
|
||||
getLineCount(): number;
|
||||
getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
|
||||
coordinatesConverter: {
|
||||
convertViewPositionToModelPosition(viewPosition: Position): Position;
|
||||
|
||||
@@ -1057,6 +1057,10 @@ export class EditorContribOptions {
|
||||
* Internal configuration options (transformed or computed) for the editor.
|
||||
*/
|
||||
export class InternalEditorOptions {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
static forceCopyWithSyntaxHighlighting: boolean = false;
|
||||
readonly _internalEditorOptionsBrand: void;
|
||||
|
||||
readonly lineHeight: number; // todo: move to fontInfo
|
||||
@@ -4122,6 +4126,11 @@ export interface ICommonCodeEditor extends IEditor {
|
||||
* Get the layout info for the editor.
|
||||
*/
|
||||
getLayoutInfo(): EditorLayoutInfo;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getTelemetryData(): { [key: string]: any; };
|
||||
}
|
||||
|
||||
export interface ICommonDiffEditor extends IEditor {
|
||||
|
||||
@@ -62,12 +62,12 @@ export abstract class EditorAction extends ConfigEditorCommand {
|
||||
}
|
||||
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void> {
|
||||
this.reportTelemetry(accessor);
|
||||
this.reportTelemetry(accessor, editor);
|
||||
return this.run(accessor, editor, args);
|
||||
}
|
||||
|
||||
protected reportTelemetry(accessor: ServicesAccessor) {
|
||||
accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id });
|
||||
protected reportTelemetry(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor) {
|
||||
accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() });
|
||||
}
|
||||
|
||||
public abstract run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void>;
|
||||
|
||||
@@ -8,11 +8,101 @@ import * as strings from 'vs/base/common/strings';
|
||||
import { IState, ITokenizationSupport, TokenizationRegistry, LanguageId } from 'vs/editor/common/modes';
|
||||
import { NULL_STATE, nullTokenize2 } from 'vs/editor/common/modes/nullMode';
|
||||
import { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
|
||||
|
||||
export function tokenizeToString(text: string, languageId: string): string {
|
||||
return _tokenizeToString(text, _getSafeTokenizationSupport(languageId));
|
||||
}
|
||||
|
||||
export function tokenizeLineToHTML(text: string, viewLineTokens: ViewLineToken[], rules: { [key: string]: string }, options: { startOffset: number, endOffset: number, tabSize: number }): string {
|
||||
let tabSize = options.tabSize;
|
||||
let result = `<div>`;
|
||||
let charIndex = options.startOffset;
|
||||
let tabsCharDelta = 0;
|
||||
|
||||
for (let tokenIndex = 0, lenJ = viewLineTokens.length; tokenIndex < lenJ; tokenIndex++) {
|
||||
const token = viewLineTokens[tokenIndex];
|
||||
const tokenEndIndex = token.endIndex;
|
||||
|
||||
if (token.endIndex < options.startOffset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const tokenType = token.type;
|
||||
let partContentCnt = 0;
|
||||
let partContent = '';
|
||||
|
||||
for (; charIndex < tokenEndIndex && charIndex < options.endOffset; charIndex++) {
|
||||
const charCode = text.charCodeAt(charIndex);
|
||||
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
let insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;
|
||||
tabsCharDelta += insertSpacesCount - 1;
|
||||
while (insertSpacesCount > 0) {
|
||||
partContent += ' ';
|
||||
partContentCnt++;
|
||||
insertSpacesCount--;
|
||||
}
|
||||
break;
|
||||
|
||||
case CharCode.Space:
|
||||
partContent += ' ';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.LessThan:
|
||||
partContent += '<';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.GreaterThan:
|
||||
partContent += '>';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.Ampersand:
|
||||
partContent += '&';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.Null:
|
||||
partContent += '�';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.UTF8_BOM:
|
||||
case CharCode.LINE_SEPARATOR_2028:
|
||||
partContent += '\ufffd';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
case CharCode.CarriageReturn:
|
||||
// zero width space, because carriage return would introduce a line break
|
||||
partContent += '​';
|
||||
partContentCnt++;
|
||||
break;
|
||||
|
||||
default:
|
||||
partContent += String.fromCharCode(charCode);
|
||||
partContentCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: adopt new view line tokens.
|
||||
let style = tokenType.split(' ').map(type => rules[type]).join('');
|
||||
result += `<span style="${style}">${partContent}</span>`;
|
||||
|
||||
if (token.endIndex > options.endOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result += `</div>`;
|
||||
return result;
|
||||
}
|
||||
|
||||
function _getSafeTokenizationSupport(languageId: string): ITokenizationSupport {
|
||||
let tokenizationSupport = TokenizationRegistry.get(languageId);
|
||||
if (tokenizationSupport) {
|
||||
|
||||
@@ -88,6 +88,9 @@ export interface IViewModel extends IEventEmitter {
|
||||
getModelLineContent(modelLineNumber: number): string;
|
||||
getModelLineMaxColumn(modelLineNumber: number): number;
|
||||
validateModelPosition(modelPosition: IPosition): Position;
|
||||
|
||||
getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string;
|
||||
}
|
||||
|
||||
export class MinimapLinesRenderingData {
|
||||
|
||||
@@ -11,6 +11,8 @@ import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
|
||||
import { ViewModelCursors } from 'vs/editor/common/viewModel/viewModelCursors';
|
||||
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
|
||||
import { MinimapLinesRenderingData, ViewLineRenderingData, ViewModelDecoration, IViewModel, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
@@ -566,4 +568,99 @@ export class ViewModel extends EventEmitter implements IViewModel {
|
||||
public validateModelPosition(position: editorCommon.IPosition): Position {
|
||||
return this.model.validatePosition(position);
|
||||
}
|
||||
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
let newLineCharacter = this.getEOL();
|
||||
|
||||
if (ranges.length === 1) {
|
||||
let range: Range = ranges[0];
|
||||
if (range.isEmpty()) {
|
||||
if (enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
return this.getModelLineContent(modelLineNumber) + newLineCharacter;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return this.getValueInRange(range, editorCommon.EndOfLinePreference.TextDefined);
|
||||
} else {
|
||||
ranges = ranges.slice(0).sort(Range.compareRangesUsingStarts);
|
||||
let result: string[] = [];
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
result.push(this.getValueInRange(ranges[i], editorCommon.EndOfLinePreference.TextDefined));
|
||||
}
|
||||
|
||||
return result.join(newLineCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
// TODO: adopt new view line tokens.
|
||||
let rules: { [key: string]: string } = {};
|
||||
let colorMap = TokenizationRegistry.getColorMap();
|
||||
for (let i = 1, len = colorMap.length; i < len; i++) {
|
||||
let color = colorMap[i];
|
||||
if (/^(?:[0-9a-fA-F]{3}){1,2}$/.test(color)) {
|
||||
color = '#' + color;
|
||||
}
|
||||
rules[`mtk${i}`] = `color: ${color};`;
|
||||
}
|
||||
rules['mtki'] = 'font-style: italic;';
|
||||
rules['mtkb'] = 'font-weight: bold;';
|
||||
rules['mtku'] = 'text-decoration: underline;';
|
||||
|
||||
let defaultForegroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[1]) ? '#' + colorMap[1] : colorMap[1];
|
||||
let defaultBackgroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[2]) ? '#' + colorMap[2] : colorMap[2];
|
||||
|
||||
let fontInfo = this.configuration.editor.fontInfo;
|
||||
|
||||
let output = `<div style="color: ${defaultForegroundColor}; background-color: ${defaultBackgroundColor};` +
|
||||
`font-family: ${fontInfo.fontFamily}; font-weight: ${fontInfo.fontWeight}; font-size: ${fontInfo.fontSize}px; line-height: ${fontInfo.lineHeight}px">`;
|
||||
|
||||
if (ranges.length === 1) {
|
||||
let range: Range = ranges[0];
|
||||
|
||||
if (range.isEmpty()) {
|
||||
if (enableEmptySelectionClipboard) {
|
||||
let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
|
||||
let viewLineStart = new Position(range.startLineNumber, 1);
|
||||
let viewLineEnd = new Position(range.startLineNumber, this.getLineMaxColumn(range.startLineNumber));
|
||||
let startOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineStart).column - 1;
|
||||
let endOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineEnd).column - 1;
|
||||
let viewLineRenderingData = this.getViewLineRenderingData(new Range(viewLineStart.lineNumber, viewLineStart.column, viewLineEnd.lineNumber, viewLineEnd.column), modelLineNumber);
|
||||
let html = tokenizeLineToHTML(this.getModelLineContent(modelLineNumber),
|
||||
viewLineRenderingData.tokens,
|
||||
rules,
|
||||
{
|
||||
startOffset: startOffset,
|
||||
endOffset: endOffset,
|
||||
tabSize: this.getTabSize()
|
||||
});
|
||||
output += `${html}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
for (let i = 0, lineCount = range.endLineNumber - range.startLineNumber; i <= lineCount; i++) {
|
||||
let viewLineRenderingData = this.getViewLineRenderingData(range, range.startLineNumber + i);
|
||||
let lineContent = viewLineRenderingData.content;
|
||||
let startOffset = i === 0 ? range.startColumn - 1 : 0;
|
||||
let endOffset = i === lineCount ? range.endColumn - 1 : lineContent.length;
|
||||
|
||||
let html = tokenizeLineToHTML(lineContent, viewLineRenderingData.tokens, rules,
|
||||
{
|
||||
startOffset: startOffset,
|
||||
endOffset: endOffset,
|
||||
tabSize: this.getTabSize()
|
||||
});
|
||||
output += `${html}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output += '</div>';
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,14 @@ function conditionalEditorAction(testCommand: string) {
|
||||
return editorAction;
|
||||
}
|
||||
|
||||
function conditionalCopyWithSyntaxHighlighting() {
|
||||
if (browser.isEdgeOrIE || !browser.supportsExecCommand('copy')) {
|
||||
return () => { };
|
||||
}
|
||||
|
||||
return editorAction;
|
||||
}
|
||||
|
||||
abstract class ExecCommandAction extends EditorAction {
|
||||
|
||||
private browserCommand: string;
|
||||
@@ -136,3 +144,36 @@ class ExecCommandPasteAction extends ExecCommandAction {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@conditionalCopyWithSyntaxHighlighting()
|
||||
class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
super('copy', {
|
||||
id: 'editor.action.clipboardCopyWithSyntaxHighlightingAction',
|
||||
label: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', "Copy With Syntax Highlighting"),
|
||||
alias: 'Copy With Syntax Highlighting',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.TextFocus,
|
||||
primary: null
|
||||
},
|
||||
menuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
|
||||
var enableEmptySelectionClipboard = editor.getConfiguration().contribInfo.emptySelectionClipboard && browser.enableEmptySelectionClipboard;
|
||||
|
||||
if (!enableEmptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
editorCommon.InternalEditorOptions.forceCopyWithSyntaxHighlighting = true;
|
||||
super.run(accessor, editor);
|
||||
editorCommon.InternalEditorOptions.forceCopyWithSyntaxHighlighting = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ abstract class FoldingAction<T> extends EditorAction {
|
||||
if (!foldingController) {
|
||||
return;
|
||||
}
|
||||
this.reportTelemetry(accessor);
|
||||
this.reportTelemetry(accessor, editor);
|
||||
this.invoke(foldingController, editor, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,27 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .message {
|
||||
padding: 1px 4px;
|
||||
background: #1382CE;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.monaco-editor .monaco-editor-overlaymessage .anchor {
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
z-index: 1000;
|
||||
border-width: 8px;
|
||||
border-top-color: #1382CE;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor,
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor-background,
|
||||
.monaco-editor .preview-zone-widget.preview .monaco-editor .line-numbers,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import 'vs/css!./goToDeclaration';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Throttler } from 'vs/base/common/async';
|
||||
import { any, filterEvent } from 'vs/base/common/event';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { MarkedString } from 'vs/base/common/htmlContent';
|
||||
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
|
||||
@@ -24,7 +25,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, IActionOptions, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IEditorMouseEvent, IMouseTarget, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
|
||||
import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController';
|
||||
@@ -34,16 +35,90 @@ import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
import * as corePosition from 'vs/editor/common/core/position';
|
||||
|
||||
import ModeContextKeys = editorCommon.ModeContextKeys;
|
||||
import EditorContextKeys = editorCommon.EditorContextKeys;
|
||||
|
||||
class MessageOverlay implements IContentWidget {
|
||||
|
||||
private static _last: IDisposable;
|
||||
|
||||
static show(editor: ICodeEditor, pos: editorCommon.IPosition, message: string): void {
|
||||
|
||||
dispose(MessageOverlay._last);
|
||||
|
||||
const widget = new MessageOverlay(message, pos.lineNumber, editor.getOffsetForColumn(pos.lineNumber, pos.column));
|
||||
const remove = () => editor.removeContentWidget(widget);
|
||||
editor.addContentWidget(widget);
|
||||
|
||||
const listener = any<any>(
|
||||
filterEvent(editor.onMouseMove, e => {
|
||||
const { position } = e.target;
|
||||
return Math.abs(position.lineNumber - pos.lineNumber) > 1
|
||||
|| Math.abs(position.column - pos.column) > 10;
|
||||
}),
|
||||
editor.onDidChangeCursorPosition,
|
||||
editor.onDidBlurEditorText,
|
||||
editor.onDidDispose,
|
||||
editor.onDidChangeModel
|
||||
)(_ => {
|
||||
listener.dispose();
|
||||
remove();
|
||||
});
|
||||
|
||||
|
||||
MessageOverlay._last = {
|
||||
dispose() {
|
||||
listener.dispose();
|
||||
remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
readonly allowEditorOverflow = true;
|
||||
readonly suppressMouseDown = false;
|
||||
|
||||
private _position: editorCommon.IPosition;
|
||||
private _domNode: HTMLDivElement;
|
||||
|
||||
constructor(text: string, lineNumber: number, horizontalOffset: number) {
|
||||
this._position = { lineNumber, column: 1 };
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.style.paddingLeft = `${horizontalOffset - 6}px`;
|
||||
this._domNode.classList.add('monaco-editor-overlaymessage');
|
||||
|
||||
|
||||
const message = document.createElement('div');
|
||||
message.classList.add('message');
|
||||
message.textContent = text;
|
||||
this._domNode.appendChild(message);
|
||||
|
||||
const anchor = document.createElement('div');
|
||||
anchor.classList.add('anchor');
|
||||
this._domNode.appendChild(anchor);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return 'messageoverlay';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
getPosition(): IContentWidgetPosition {
|
||||
return { position: this._position, preference: [ContentWidgetPositionPreference.ABOVE] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class DefinitionActionConfig {
|
||||
|
||||
constructor(
|
||||
public openToSide = false,
|
||||
public openInPeek = false,
|
||||
public filterCurrent = true
|
||||
public filterCurrent = true,
|
||||
public noResultsMessage = nls.localize('generic.noResults', "Could not find anything")
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -67,10 +142,6 @@ export class DefinitionAction extends EditorAction {
|
||||
|
||||
return this.getDeclarationsAtPosition(model, pos).then(references => {
|
||||
|
||||
if (!references) {
|
||||
return;
|
||||
}
|
||||
|
||||
// * remove falsy references
|
||||
// * remove reference at the current pos
|
||||
// * collapse ranges to start pos
|
||||
@@ -80,7 +151,7 @@ export class DefinitionAction extends EditorAction {
|
||||
if (!reference || !reference.range) {
|
||||
continue;
|
||||
}
|
||||
let {uri, range} = reference;
|
||||
let { uri, range } = reference;
|
||||
if (!this._configuration.filterCurrent
|
||||
|| uri.toString() !== model.uri.toString()
|
||||
|| !Range.containsPosition(range, pos)) {
|
||||
@@ -93,6 +164,7 @@ export class DefinitionAction extends EditorAction {
|
||||
}
|
||||
|
||||
if (result.length === 0) {
|
||||
MessageOverlay.show(<ICodeEditor>editor, pos, this._configuration.noResultsMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,7 +197,7 @@ export class DefinitionAction extends EditorAction {
|
||||
}
|
||||
|
||||
private _openReference(editorService: IEditorService, reference: Location, sideBySide: boolean): TPromise<editorCommon.ICommonCodeEditor> {
|
||||
let {uri, range} = reference;
|
||||
let { uri, range } = reference;
|
||||
return editorService.openEditor({
|
||||
resource: uri,
|
||||
options: {
|
||||
|
||||
@@ -322,7 +322,7 @@ class MarkerNavigationAction extends EditorAction {
|
||||
}
|
||||
|
||||
let model = controller.getOrCreateModel();
|
||||
telemetryService.publicLog('zoneWidgetShown', { mode: 'go to error' });
|
||||
telemetryService.publicLog('zoneWidgetShown', { mode: 'go to error', ...editor.getTelemetryData() });
|
||||
if (model) {
|
||||
if (this._isNext) {
|
||||
model.next();
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { addClass, append, $, hide, removeClass, show, toggleClass } from 'vs/base/browser/dom';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IDelegate, IFocusChangeEvent, IRenderer, ISelectionChangeEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IDelegate, IListEvent, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -407,7 +407,7 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
});
|
||||
}
|
||||
|
||||
private onListSelection(e: ISelectionChangeEvent<ICompletionItem>): void {
|
||||
private onListSelection(e: IListEvent<ICompletionItem>): void {
|
||||
if (!e.elements.length) {
|
||||
return;
|
||||
}
|
||||
@@ -439,7 +439,7 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
}
|
||||
}
|
||||
|
||||
private onListFocus(e: IFocusChangeEvent<ICompletionItem>): void {
|
||||
private onListFocus(e: IListEvent<ICompletionItem>): void {
|
||||
if (!e.elements.length) {
|
||||
if (this.currentSuggestionDetails) {
|
||||
this.currentSuggestionDetails.cancel();
|
||||
@@ -591,9 +591,9 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
this.completionModel = null;
|
||||
|
||||
} else {
|
||||
const {stats} = this.completionModel;
|
||||
const { stats } = this.completionModel;
|
||||
stats['wasAutomaticallyTriggered'] = !!isAuto;
|
||||
this.telemetryService.publicLog('suggestWidget', stats);
|
||||
this.telemetryService.publicLog('suggestWidget', { ...stats, ...this.editor.getTelemetryData() });
|
||||
|
||||
this.list.splice(0, this.list.length, this.completionModel.items);
|
||||
this.list.setFocus([this.completionModel.topScoreIdx]);
|
||||
@@ -694,7 +694,7 @@ export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>
|
||||
|
||||
this.setState(State.Details);
|
||||
this.editor.focus();
|
||||
this.telemetryService.publicLog('suggestWidget:toggleDetails');
|
||||
this.telemetryService.publicLog('suggestWidget:toggleDetails', this.editor.getTelemetryData());
|
||||
}
|
||||
|
||||
private show(): void {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { grammarsExtPoint, IEmbeddedLanguagesMap, ITMSyntaxExtensionPoint } from
|
||||
import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';
|
||||
import { TokenMetadata } from 'vs/editor/common/model/tokensBinaryEncoding';
|
||||
import { nullTokenize2 } from 'vs/editor/common/modes/nullMode';
|
||||
import { hexToCSS } from 'vs/base/common/color';
|
||||
|
||||
export class TMScopeRegistry {
|
||||
|
||||
@@ -153,7 +154,7 @@ export class MainProcessTextMateSyntax implements ITextMateService {
|
||||
let rules: string[] = [];
|
||||
for (let i = 1, len = colorMap.length; i < len; i++) {
|
||||
let color = colorMap[i];
|
||||
rules[i] = `.mtk${i} { color: ${color.substr(0, 7)}; }`;
|
||||
rules[i] = `.mtk${i} { color: ${hexToCSS(color)}; }`;
|
||||
}
|
||||
rules.push('.mtki { font-style: italic; }');
|
||||
rules.push('.mtkb { font-weight: bold; }');
|
||||
|
||||
@@ -53,6 +53,14 @@ class SingleLineTestModel implements ISimpleModel {
|
||||
getLineCount(): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
class TestView {
|
||||
@@ -180,4 +188,4 @@ const TESTS = [
|
||||
TESTS.forEach((t) => {
|
||||
document.body.appendChild(doCreateTest(TextAreaStrategy.NVDA, t.description, t.in, t.out));
|
||||
document.body.appendChild(doCreateTest(TextAreaStrategy.IENarrator, t.description, t.in, t.out));
|
||||
});
|
||||
});
|
||||
@@ -472,4 +472,12 @@ class SimpleModel implements ISimpleModel {
|
||||
public getLineCount(): number {
|
||||
return this._lines.length;
|
||||
}
|
||||
|
||||
public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace schema {
|
||||
|
||||
export function parseMenuId(value: string): MenuId {
|
||||
switch (value) {
|
||||
case 'commandPalette': return MenuId.CommandPalette;
|
||||
case 'editor/title': return MenuId.EditorTitle;
|
||||
case 'editor/context': return MenuId.EditorContext;
|
||||
case 'explorer/context': return MenuId.ExplorerContext;
|
||||
@@ -224,7 +225,7 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
|
||||
return;
|
||||
}
|
||||
|
||||
let {icon, category, title, command} = userFriendlyCommand;
|
||||
let { icon, category, title, command } = userFriendlyCommand;
|
||||
let iconClass: string;
|
||||
if (icon) {
|
||||
iconClass = ids.nextId();
|
||||
@@ -245,7 +246,7 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
|
||||
}
|
||||
|
||||
for (let extension of extensions) {
|
||||
const {value} = extension;
|
||||
const { value } = extension;
|
||||
if (Array.isArray<schema.IUserFriendlyCommand>(value)) {
|
||||
for (let command of value) {
|
||||
handleCommand(command, extension);
|
||||
@@ -259,7 +260,7 @@ ExtensionsRegistry.registerExtensionPoint<schema.IUserFriendlyCommand | schema.I
|
||||
|
||||
ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyMenuItem[] }>('menus', [], schema.menusContribtion).setHandler(extensions => {
|
||||
for (let extension of extensions) {
|
||||
const {value, collector} = extension;
|
||||
const { value, collector } = extension;
|
||||
|
||||
forEach(value, entry => {
|
||||
if (!schema.isValidMenuItems(entry.value, collector)) {
|
||||
|
||||
@@ -21,11 +21,6 @@ export interface ICommandAction {
|
||||
iconClass?: string;
|
||||
}
|
||||
|
||||
export interface IMenu extends IDisposable {
|
||||
onDidChange: Event<IMenu>;
|
||||
getActions(arg?: any): [string, MenuItemAction[]][];
|
||||
}
|
||||
|
||||
export interface IMenuItem {
|
||||
command: ICommandAction;
|
||||
alt?: ICommandAction;
|
||||
@@ -49,6 +44,7 @@ export class MenuId {
|
||||
static readonly SCMTitle = new MenuId('11');
|
||||
static readonly SCMResourceGroupContext = new MenuId('12');
|
||||
static readonly SCMResourceContext = new MenuId('13');
|
||||
static readonly CommandPalette = new MenuId('14');
|
||||
|
||||
constructor(private _id: string) {
|
||||
|
||||
@@ -59,6 +55,11 @@ export class MenuId {
|
||||
}
|
||||
}
|
||||
|
||||
export interface IMenu extends IDisposable {
|
||||
onDidChange: Event<IMenu>;
|
||||
getActions(arg?: any): [string, MenuItemAction[]][];
|
||||
}
|
||||
|
||||
export const IMenuService = createDecorator<IMenuService>('menuService');
|
||||
|
||||
export interface IMenuService {
|
||||
@@ -66,8 +67,6 @@ export interface IMenuService {
|
||||
_serviceBrand: any;
|
||||
|
||||
createMenu(id: MenuId, scopedKeybindingService: IContextKeyService): IMenu;
|
||||
|
||||
getCommandActions(): ICommandAction[];
|
||||
}
|
||||
|
||||
export interface IMenuRegistry {
|
||||
@@ -94,7 +93,7 @@ export const MenuRegistry: IMenuRegistry = new class {
|
||||
return this.commands[id];
|
||||
}
|
||||
|
||||
appendMenuItem({id}: MenuId, item: IMenuItem): IDisposable {
|
||||
appendMenuItem({ id }: MenuId, item: IMenuItem): IDisposable {
|
||||
let array = this.menuItems[id];
|
||||
if (!array) {
|
||||
this.menuItems[id] = array = [item];
|
||||
@@ -111,8 +110,30 @@ export const MenuRegistry: IMenuRegistry = new class {
|
||||
};
|
||||
}
|
||||
|
||||
getMenuItems({id}: MenuId): IMenuItem[] {
|
||||
return this.menuItems[id] || [];
|
||||
getMenuItems({ id }: MenuId): IMenuItem[] {
|
||||
const result = this.menuItems[id] || [];
|
||||
|
||||
if (id === MenuId.CommandPalette.id) {
|
||||
// CommandPalette is special because it shows
|
||||
// all commands by default
|
||||
this._appendImplicitItems(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _appendImplicitItems(result: IMenuItem[]) {
|
||||
const set = new Set<string>();
|
||||
for (const { command, alt } of result) {
|
||||
set.add(command.id);
|
||||
if (alt) {
|
||||
set.add(alt.id);
|
||||
}
|
||||
}
|
||||
for (let id in this.commands) {
|
||||
if (!set.has(id)) {
|
||||
result.push({ command: this.commands[id] });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -202,4 +223,4 @@ export class SyncActionDescriptor {
|
||||
public get keybindingWeight(): number {
|
||||
return this._keybindingWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export class Menu implements IMenu {
|
||||
private _onDidChange = new Emitter<IMenu>();
|
||||
|
||||
constructor(
|
||||
id: MenuId,
|
||||
private id: MenuId,
|
||||
startupSignal: TPromise<boolean>,
|
||||
@ICommandService private _commandService: ICommandService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuId, MenuRegistry, ICommandAction, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { Menu } from 'vs/platform/actions/common/menu';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -26,8 +25,4 @@ export class MenuService implements IMenuService {
|
||||
createMenu(id: MenuId, contextKeyService: IContextKeyService): IMenu {
|
||||
return new Menu(id, this._extensionService.onReady(), this._commandService, contextKeyService);
|
||||
}
|
||||
|
||||
getCommandActions(): ICommandAction[] {
|
||||
return values(MenuRegistry.commands);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,4 +186,20 @@ suite('MenuService', function () {
|
||||
assert.equal(two.id, 'b');
|
||||
assert.equal(three.id, 'a');
|
||||
});
|
||||
|
||||
test('special MenuId palette', function () {
|
||||
|
||||
disposables.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: { id: 'a', title: 'Explicit' }
|
||||
}));
|
||||
|
||||
MenuRegistry.addCommand({ id: 'b', title: 'Implicit' });
|
||||
|
||||
const [first, second] = MenuRegistry.getMenuItems(MenuId.CommandPalette);
|
||||
assert.equal(first.command.id, 'a');
|
||||
assert.equal(first.command.title, 'Explicit');
|
||||
|
||||
assert.equal(second.command.id, 'b');
|
||||
assert.equal(second.command.title, 'Implicit');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -122,13 +122,13 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
this.updateOverridePropertyPatternKey();
|
||||
}
|
||||
|
||||
public registerDefaultConfigurations(defaultConnfigurations: IDefaultConfigurationExtension[]): void {
|
||||
public registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void {
|
||||
const configurationNode: IConfigurationNode = {
|
||||
id: 'defaultOverrides',
|
||||
title: nls.localize('defaultConfigurations.title', "Default Configuration Overrides"),
|
||||
properties: {}
|
||||
};
|
||||
for (const defaultConfiguration of defaultConnfigurations) {
|
||||
for (const defaultConfiguration of defaultConfigurations) {
|
||||
for (const key in defaultConfiguration.defaults) {
|
||||
const defaultValue = defaultConfiguration.defaults[key];
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key) && typeof defaultValue === 'object') {
|
||||
@@ -141,7 +141,9 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.registerConfiguration(configurationNode, false);
|
||||
if (Object.keys(configurationNode.properties).length) {
|
||||
this.registerConfiguration(configurationNode, false);
|
||||
}
|
||||
}
|
||||
|
||||
private validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, overridable: boolean = false) {
|
||||
@@ -360,10 +362,8 @@ configurationExtPoint.setHandler(extensions => {
|
||||
|
||||
validateProperties(configuration, collector);
|
||||
|
||||
if (configuration.properties) {
|
||||
configuration.id = extensions[i].description.id;
|
||||
configurations.push(configuration);
|
||||
}
|
||||
configuration.id = extensions[i].description.id;
|
||||
configurations.push(configuration);
|
||||
}
|
||||
|
||||
configurationRegistry.registerConfigurations(configurations, false);
|
||||
|
||||
@@ -29,25 +29,25 @@ function getUniqueUserId(): string {
|
||||
return crypto.createHash('sha256').update(username).digest('hex').substr(0, 6);
|
||||
}
|
||||
|
||||
function getIPCHandlePrefix(nixBaseDir: string = os.tmpdir()): string {
|
||||
let name = pkg.name;
|
||||
|
||||
// Support to run VS Code multiple times as different user
|
||||
// by making the socket unique over the logged in user
|
||||
let userId = getUniqueUserId();
|
||||
if (userId) {
|
||||
name += `-${userId}`;
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
return `\\\\.\\pipe\\${name}`;
|
||||
} else {
|
||||
return path.join(nixBaseDir, name);
|
||||
}
|
||||
function getNixIPCHandle(userDataPath: string, type: string): string {
|
||||
return path.join(userDataPath, `${pkg.version}-${type}.sock`);
|
||||
}
|
||||
|
||||
function getIPCHandleSuffix(): string {
|
||||
return process.platform === 'win32' ? '-sock' : '.sock';
|
||||
function getWin32IPCHandle(type: string): string {
|
||||
// Support to run VS Code multiple times as different user
|
||||
// by making the socket unique over the logged in user
|
||||
const userId = getUniqueUserId();
|
||||
const name = product.applicationName + (userId ? `-${userId}` : '');
|
||||
|
||||
return `\\\\.\\pipe\\${name}-${pkg.version}-${type}-sock`;
|
||||
}
|
||||
|
||||
function getIPCHandle(userDataPath: string, type: string): string {
|
||||
if (process.platform === 'win32') {
|
||||
return getWin32IPCHandle(type);
|
||||
} else {
|
||||
return getNixIPCHandle(userDataPath, type);
|
||||
}
|
||||
}
|
||||
|
||||
export class EnvironmentService implements IEnvironmentService {
|
||||
@@ -113,10 +113,10 @@ export class EnvironmentService implements IEnvironmentService {
|
||||
get logExtensionHostCommunication(): boolean { return this._args.logExtensionHostCommunication; }
|
||||
|
||||
@memoize
|
||||
get mainIPCHandle(): string { return `${getIPCHandlePrefix(this.userDataPath)}-${pkg.version}${getIPCHandleSuffix()}`; }
|
||||
get mainIPCHandle(): string { return getIPCHandle(this.userDataPath, 'main'); }
|
||||
|
||||
@memoize
|
||||
get sharedIPCHandle(): string { return `${getIPCHandlePrefix(this.userDataPath)}-${pkg.version}-shared${getIPCHandleSuffix()}`; }
|
||||
get sharedIPCHandle(): string { return getIPCHandle(this.userDataPath, 'shared'); }
|
||||
|
||||
@memoize
|
||||
get nodeCachedDataDir(): string { return path.join(this.userDataPath, 'CachedData'); }
|
||||
|
||||
@@ -15,11 +15,17 @@ export interface ITelemetryInfo {
|
||||
instanceId: string;
|
||||
}
|
||||
|
||||
export interface ITelemetryData {
|
||||
from?: string;
|
||||
target?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ITelemetryExperiments {
|
||||
showNewUserWatermark: boolean;
|
||||
openUntitledFile: boolean;
|
||||
openGettingStarted?: boolean;
|
||||
enableWelcomePage: boolean;
|
||||
repositionPlaygroundLink: boolean;
|
||||
}
|
||||
|
||||
export interface ITelemetryService {
|
||||
@@ -30,7 +36,7 @@ export interface ITelemetryService {
|
||||
* Sends a telemetry event that has been privacy approved.
|
||||
* Do not call this unless you have been given approval.
|
||||
*/
|
||||
publicLog(eventName: string, data?: any): TPromise<void>;
|
||||
publicLog(eventName: string, data?: ITelemetryData): TPromise<void>;
|
||||
|
||||
getTelemetryInfo(): TPromise<ITelemetryInfo>;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryAppender, defaultExperiments } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -100,7 +100,7 @@ export class TelemetryService implements ITelemetryService {
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
publicLog(eventName: string, data?: any): TPromise<any> {
|
||||
publicLog(eventName: string, data?: ITelemetryData): TPromise<any> {
|
||||
// don't send events when the user is optout
|
||||
if (!this._userOptIn) {
|
||||
return TPromise.as(undefined);
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/com
|
||||
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { StorageService } from 'vs/platform/storage/common/storageService';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
@@ -22,13 +22,14 @@ import * as objects from 'vs/base/common/objects';
|
||||
export const defaultExperiments: ITelemetryExperiments = {
|
||||
showNewUserWatermark: false,
|
||||
openUntitledFile: true,
|
||||
enableWelcomePage: true
|
||||
enableWelcomePage: true,
|
||||
repositionPlaygroundLink: false,
|
||||
};
|
||||
|
||||
export const NullTelemetryService = {
|
||||
_serviceBrand: undefined,
|
||||
_experiments: defaultExperiments,
|
||||
publicLog(eventName: string, data?: any) {
|
||||
publicLog(eventName: string, data?: ITelemetryData) {
|
||||
return TPromise.as<void>(null);
|
||||
},
|
||||
isOptedIn: true,
|
||||
@@ -44,9 +45,6 @@ export const NullTelemetryService = {
|
||||
}
|
||||
};
|
||||
|
||||
const beginGettingStartedExp = Date.UTC(2017, 0, 9);
|
||||
const endGettingStartedExp = Date.UTC(2017, 0, 16);
|
||||
|
||||
export function loadExperiments(accessor: ServicesAccessor): ITelemetryExperiments {
|
||||
const contextService = accessor.get(IWorkspaceContextService);
|
||||
const storageService = accessor.get(IStorageService);
|
||||
@@ -58,8 +56,8 @@ export function loadExperiments(accessor: ServicesAccessor): ITelemetryExperimen
|
||||
let {
|
||||
showNewUserWatermark,
|
||||
openUntitledFile,
|
||||
openGettingStarted,
|
||||
enableWelcomePage
|
||||
enableWelcomePage,
|
||||
repositionPlaygroundLink,
|
||||
} = splitExperimentsRandomness();
|
||||
|
||||
const newUserDuration = 24 * 60 * 60 * 1000;
|
||||
@@ -70,17 +68,11 @@ export function loadExperiments(accessor: ServicesAccessor): ITelemetryExperimen
|
||||
openUntitledFile = defaultExperiments.openUntitledFile;
|
||||
}
|
||||
|
||||
const isNewSession = !storageService.get('telemetry.lastSessionDate');
|
||||
const now = Date.now();
|
||||
if (!(isNewSession && now >= beginGettingStartedExp && now < endGettingStartedExp)) {
|
||||
openGettingStarted = undefined;
|
||||
}
|
||||
|
||||
return applyOverrides({
|
||||
showNewUserWatermark,
|
||||
openUntitledFile,
|
||||
openGettingStarted,
|
||||
enableWelcomePage
|
||||
enableWelcomePage,
|
||||
repositionPlaygroundLink,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,13 +95,13 @@ function splitExperimentsRandomness(): ITelemetryExperiments {
|
||||
const random1 = getExperimentsRandomness();
|
||||
const [random2, showNewUserWatermark] = splitRandom(random1);
|
||||
const [random3, openUntitledFile] = splitRandom(random2);
|
||||
const [random4, openGettingStarted] = splitRandom(random3);
|
||||
const [random4, repositionPlaygroundLink] = splitRandom(random3);
|
||||
const [, enableWelcomePage] = splitRandom(random4);
|
||||
return {
|
||||
showNewUserWatermark,
|
||||
openUntitledFile,
|
||||
openGettingStarted,
|
||||
enableWelcomePage
|
||||
enableWelcomePage,
|
||||
repositionPlaygroundLink,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
@@ -134,6 +134,7 @@ declare module 'vscode' {
|
||||
readonly resources: SCMResourceGroup[];
|
||||
readonly onDidChange: Event<SCMResourceGroup[]>;
|
||||
readonly count?: number | undefined;
|
||||
readonly state?: string;
|
||||
|
||||
getOriginalResource?(uri: Uri, token: CancellationToken): ProviderResult<Uri>;
|
||||
open?(resource: SCMResource, token: CancellationToken): ProviderResult<void>;
|
||||
|
||||
@@ -183,6 +183,7 @@ export abstract class MainThreadMessageServiceShape {
|
||||
export abstract class MainThreadOutputServiceShape {
|
||||
$append(channelId: string, label: string, value: string): TPromise<void> { throw ni(); }
|
||||
$clear(channelId: string, label: string): TPromise<void> { throw ni(); }
|
||||
$dispose(channelId: string, label: string): TPromise<void> { throw ni(); }
|
||||
$reveal(channelId: string, label: string, preserveFocus: boolean): TPromise<void> { throw ni(); }
|
||||
$close(channelId: string): TPromise<void> { throw ni(); }
|
||||
}
|
||||
@@ -258,7 +259,7 @@ export type SCMRawResourceGroup = [string /*id*/, string /*label*/, SCMRawResour
|
||||
export abstract class MainThreadSCMShape {
|
||||
$register(id: string, features: SCMProviderFeatures): void { throw ni(); }
|
||||
$unregister(id: string): void { throw ni(); }
|
||||
$onChange(id: string, resources: SCMRawResourceGroup[], count: number | undefined): void { throw ni(); }
|
||||
$onChange(id: string, resources: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { throw ni(); }
|
||||
$setInputBoxValue(value: string): void { throw ni(); }
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export class ExtHostOutputChannel implements vscode.OutputChannel {
|
||||
|
||||
dispose(): void {
|
||||
if (!this._disposed) {
|
||||
this._proxy.$clear(this._id, this._name).then(() => {
|
||||
this._proxy.$dispose(this._id, this._name).then(() => {
|
||||
this._disposed = true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ export class ExtHostSCM {
|
||||
return [g.id, g.label, rawResources] as SCMRawResourceGroup;
|
||||
});
|
||||
|
||||
this._proxy.$onChange(providerId, rawResourceGroups, provider.count);
|
||||
this._proxy.$onChange(providerId, rawResourceGroups, provider.count, provider.state);
|
||||
});
|
||||
|
||||
return new Disposable(() => {
|
||||
|
||||
@@ -58,4 +58,9 @@ export class MainThreadOutputService extends MainThreadOutputServiceShape {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $dispose(channelId: string, label: string): TPromise<void> {
|
||||
this._getChannel(channelId, label).dispose();
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
private _count: number | undefined = undefined;
|
||||
get count(): number | undefined { return this._count; }
|
||||
|
||||
private _state: string | undefined = undefined;
|
||||
get state(): string | undefined { return this._state; }
|
||||
|
||||
constructor(
|
||||
private _id: string,
|
||||
private proxy: ExtHostSCMShape,
|
||||
@@ -71,7 +74,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
// }
|
||||
}
|
||||
|
||||
$onChange(rawResourceGroups: SCMRawResourceGroup[], count: number | undefined): void {
|
||||
$onChange(rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void {
|
||||
this._resources = rawResourceGroups.map(rawGroup => {
|
||||
const [id, label, rawResources] = rawGroup;
|
||||
|
||||
@@ -96,7 +99,9 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
|
||||
return { id, label, resources };
|
||||
});
|
||||
|
||||
this._count = count;
|
||||
this._state = state;
|
||||
|
||||
this._onDidChange.fire(this.resources);
|
||||
}
|
||||
@@ -140,14 +145,14 @@ export class MainThreadSCM extends MainThreadSCMShape {
|
||||
delete this.providers[id];
|
||||
}
|
||||
|
||||
$onChange(id: string, rawResourceGroups: SCMRawResourceGroup[], count: number | undefined): void {
|
||||
$onChange(id: string, rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void {
|
||||
const provider = this.providers[id];
|
||||
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider.$onChange(rawResourceGroups, count);
|
||||
provider.$onChange(rawResourceGroups, count, state);
|
||||
}
|
||||
|
||||
$setInputBoxValue(value: string): void {
|
||||
|
||||
@@ -168,14 +168,15 @@ export function triggerAndDisposeAction(instantitationService: IInstantiationSer
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const from = args && args.from || 'keybinding';
|
||||
if (telemetryService) {
|
||||
telemetryService.publicLog('workbenchActionExecuted', { id: actionInstance.id, from: args && args.from || 'keybinding' });
|
||||
telemetryService.publicLog('workbenchActionExecuted', { id: actionInstance.id, from });
|
||||
}
|
||||
|
||||
// run action when workbench is created
|
||||
return partService.joinCreation().then(() => {
|
||||
try {
|
||||
return TPromise.as(actionInstance.run()).then(() => {
|
||||
return TPromise.as(actionInstance.run(undefined, { from })).then(() => {
|
||||
actionInstance.dispose();
|
||||
}, (err) => {
|
||||
actionInstance.dispose();
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
.monaco-shell.vs-dark {
|
||||
background-color: #1E1E1E;
|
||||
}
|
||||
.monaco-shell.vs {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.monaco-shell.hc-black {
|
||||
background-color: #000000;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
@@ -16,13 +22,13 @@
|
||||
<script>
|
||||
(function() {
|
||||
try {
|
||||
var theme = window.localStorage.getItem('storage://global/workbench.theme');
|
||||
if (theme) {
|
||||
var baseTheme = theme.split(' ')[0];
|
||||
if (baseTheme !== 'vs-dark') {
|
||||
window.document.body.className = 'monaco-shell ' + baseTheme;
|
||||
window.location.search.substring(1).split('&').forEach(p => {
|
||||
var kv = p.split('=');
|
||||
if (kv[0] === 'config' && kv[1]) {
|
||||
let config = JSON.parse(decodeURIComponent(kv[1]));
|
||||
window.document.body.className = 'monaco-shell ' + config.baseTheme;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@@ -144,16 +144,6 @@ function main() {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
}
|
||||
|
||||
// Handle high contrast mode
|
||||
if (configuration.highContrast) {
|
||||
var themeStorageKey = 'storage://global/workbench.theme';
|
||||
var hcTheme = 'hc-black vscode-theme-defaults-themes-hc_black-json';
|
||||
if (window.localStorage.getItem(themeStorageKey) !== hcTheme) {
|
||||
window.localStorage.setItem(themeStorageKey, hcTheme);
|
||||
window.document.body.className = 'monaco-shell ' + hcTheme;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the loader and start loading the workbench
|
||||
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user