Merge from vscode 0fde6619172c9f04c41f2e816479e432cc974b8b (#5199)
@@ -43,7 +43,7 @@
|
||||
"request": "^2.85.0",
|
||||
"tslint": "^5.9.1",
|
||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||
"typescript": "3.4.1",
|
||||
"typescript": "3.4.5",
|
||||
"vsce": "1.48.0",
|
||||
"xml2js": "^0.4.17"
|
||||
},
|
||||
|
||||
@@ -3201,10 +3201,10 @@ typed-rest-client@^0.9.0:
|
||||
tunnel "0.0.4"
|
||||
underscore "1.8.3"
|
||||
|
||||
typescript@3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6"
|
||||
integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==
|
||||
typescript@3.4.5:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
|
||||
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
|
||||
|
||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||
version "1.0.5"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"vscode": "^1.20.0"
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"extensionKind": "ui",
|
||||
"categories": [
|
||||
"Programming Languages"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"description": "Dependencies shared by all extensions",
|
||||
"dependencies": {
|
||||
"typescript": "3.4.4"
|
||||
"typescript": "3.4.5"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node ./postinstall"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
typescript@3.4.4:
|
||||
version "3.4.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.4.tgz#aac4a08abecab8091a75f10842ffa0631818f785"
|
||||
integrity sha512-xt5RsIRCEaf6+j9AyOBgvVuAec0i92rgCaS3S+UVf5Z/vF2Hvtsw08wtUTJqp4djwznoAgjSxeCcU4r+CcDBJA==
|
||||
typescript@3.4.5:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
|
||||
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-microsoft-contrib": "^6.0.0",
|
||||
"typemoq": "^0.3.2",
|
||||
"typescript": "3.4.1",
|
||||
"typescript": "3.4.5",
|
||||
"typescript-formatter": "7.1.0",
|
||||
"typescript-tslint-plugin": "^0.0.7",
|
||||
"uglify-es": "^3.0.18",
|
||||
|
||||
@@ -6,29 +6,49 @@ COMMIT="@@COMMIT@@"
|
||||
APP_NAME="@@APPNAME@@"
|
||||
QUALITY="@@QUALITY@@"
|
||||
NAME="@@NAME@@"
|
||||
|
||||
VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||
ELECTRON="$VSCODE_PATH/$NAME.exe"
|
||||
if grep -qi Microsoft /proc/version; then
|
||||
# in a wsl shell
|
||||
WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd")
|
||||
if ! [ -z "$WIN_CODE_CMD" ]; then
|
||||
fallback() {
|
||||
# If running under older WSL, don't pass cli.js to Electron as
|
||||
# environment vars cannot be transferred from WSL to Windows
|
||||
# See: https://github.com/Microsoft/BashOnWindows/issues/1363
|
||||
# https://github.com/Microsoft/BashOnWindows/issues/1494
|
||||
"$ELECTRON" "$@"
|
||||
exit $?
|
||||
}
|
||||
WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-Microsoft/\1/')
|
||||
# wslpath is not available prior to WSL build 17046
|
||||
# See: https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-17046
|
||||
if [ -x /bin/wslpath ]; then
|
||||
WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd")
|
||||
# make sure the cwd is in the windows fs, otherwise there will be a warning from cmd
|
||||
pushd "$(dirname "$0")" > /dev/null
|
||||
WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||
WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID)
|
||||
popd > /dev/null
|
||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC, get linux path for
|
||||
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
|
||||
"$WSL_CODE" $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@"
|
||||
exit $?
|
||||
elif [ $WSL_BUILD -ge 17063 ] 2> /dev/null; then
|
||||
# Since WSL build 17063, we just need to set WSLENV so that
|
||||
# ELECTRON_RUN_AS_NODE is visible to the win32 process
|
||||
# See: https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-17063
|
||||
export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV
|
||||
CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||
else # $WSL_BUILD ∈ [17046, 17063) OR $WSL_BUILD is indeterminate
|
||||
fallback "$@"
|
||||
fi
|
||||
else
|
||||
fallback "$@"
|
||||
fi
|
||||
fi
|
||||
|
||||
VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||
|
||||
if [ -x "$(command -v cygpath)" ]; then
|
||||
elif [ -x "$(command -v cygpath)" ]; then
|
||||
CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||
else
|
||||
CLI="$VSCODE_PATH/resources/app/out/cli.js"
|
||||
fi
|
||||
ELECTRON="$VSCODE_PATH/$NAME.exe"
|
||||
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
|
||||
exit $?
|
||||
|
||||
@@ -40,7 +40,6 @@ export class Dialog extends Disposable {
|
||||
private buttonGroup: ButtonGroup | undefined;
|
||||
private styles: IDialogStyles | undefined;
|
||||
private focusToReturn: HTMLElement | undefined;
|
||||
private iconRotatingInternal: any | undefined;
|
||||
|
||||
constructor(private container: HTMLElement, private message: string, private buttons: string[], private options: IDialogOptions) {
|
||||
super();
|
||||
@@ -163,15 +162,6 @@ export class Dialog extends Disposable {
|
||||
break;
|
||||
case 'pending':
|
||||
addClass(this.iconElement, 'icon-pending');
|
||||
let deg = 0;
|
||||
this.iconRotatingInternal = setInterval(() => {
|
||||
if (this.iconElement) {
|
||||
this.iconElement.style.transform = `rotate(${deg}deg)`;
|
||||
deg += 45; // 360 / 8
|
||||
} else {
|
||||
this.iconRotatingInternal = undefined;
|
||||
}
|
||||
}, 125 /** 1000 / 8 */);
|
||||
break;
|
||||
case 'none':
|
||||
case 'info':
|
||||
@@ -233,10 +223,6 @@ export class Dialog extends Disposable {
|
||||
this.modal = undefined;
|
||||
}
|
||||
|
||||
if (this.iconRotatingInternal) {
|
||||
this.iconRotatingInternal = undefined;
|
||||
}
|
||||
|
||||
if (this.focusToReturn && isAncestor(this.focusToReturn, document.body)) {
|
||||
this.focusToReturn.focus();
|
||||
this.focusToReturn = undefined;
|
||||
|
||||
@@ -1,13 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s steps(8) infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:grey;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity: 1.0;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.9;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.8;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.7;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.6;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.5;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.4;' />
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 1.1 KiB |
@@ -1,13 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s steps(8) infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity: 1.0;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.9;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.8;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.7;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.6;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.5;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.4;' />
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 1.1 KiB |
@@ -1,13 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s steps(8) infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<circle cx='5' cy='1' r='1' style='opacity: 1.0;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.9;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.8;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.7;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.6;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.5;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.4;' />
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 612 B After Width: | Height: | Size: 1.1 KiB |
@@ -6,11 +6,11 @@
|
||||
"git": {
|
||||
"name": "marked",
|
||||
"repositoryUrl": "https://github.com/markedjs/marked",
|
||||
"commitHash": "78c977bc3a47f9e2fb146477d1ca3dad0cb134e6"
|
||||
"commitHash": "529a8d4e185a8aa561e4d8d2891f8556b5717cd4"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "0.5.0"
|
||||
"version": "0.6.2"
|
||||
}
|
||||
],
|
||||
"version": 1
|
||||
|
||||
@@ -23,7 +23,7 @@ var block = {
|
||||
heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
|
||||
nptable: noop,
|
||||
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
|
||||
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
|
||||
list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
|
||||
html: '^ {0,3}(?:' // optional indentation
|
||||
+ '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
|
||||
+ '|comment[^\\n]*(\\n+|$)' // (2)
|
||||
@@ -31,8 +31,8 @@ var block = {
|
||||
+ '|<![A-Z][\\s\\S]*?>\\n*' // (4)
|
||||
+ '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
|
||||
+ '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
|
||||
+ '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
|
||||
+ '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
|
||||
+ '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
|
||||
+ '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
|
||||
+ ')',
|
||||
def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
|
||||
table: noop,
|
||||
@@ -48,8 +48,8 @@ block.def = edit(block.def)
|
||||
.replace('title', block._title)
|
||||
.getRegex();
|
||||
|
||||
block.bullet = /(?:[*+-]|\d+\.)/;
|
||||
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
|
||||
block.bullet = /(?:[*+-]|\d{1,9}\.)/;
|
||||
block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
|
||||
block.item = edit(block.item, 'gm')
|
||||
.replace(/bull/g, block.bullet)
|
||||
.getRegex();
|
||||
@@ -95,7 +95,7 @@ block.normal = merge({}, block);
|
||||
*/
|
||||
|
||||
block.gfm = merge({}, block.normal, {
|
||||
fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,
|
||||
fences: /^ {0,3}(`{3,}|~{3,})([^`\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
|
||||
paragraph: /^/,
|
||||
heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
|
||||
});
|
||||
@@ -235,7 +235,7 @@ Lexer.prototype.token = function(src, top) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'code',
|
||||
lang: cap[2],
|
||||
lang: cap[2] ? cap[2].trim() : cap[2],
|
||||
text: cap[3] || ''
|
||||
});
|
||||
continue;
|
||||
@@ -253,7 +253,7 @@ Lexer.prototype.token = function(src, top) {
|
||||
}
|
||||
|
||||
// table no leading pipe (gfm)
|
||||
if (top && (cap = this.rules.nptable.exec(src))) {
|
||||
if (cap = this.rules.nptable.exec(src)) {
|
||||
item = {
|
||||
type: 'table',
|
||||
header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
|
||||
@@ -346,7 +346,7 @@ Lexer.prototype.token = function(src, top) {
|
||||
// Remove the list item's bullet
|
||||
// so it is seen as the next token.
|
||||
space = item.length;
|
||||
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
|
||||
item = item.replace(/^ *([*+-]|\d+\.) */, '');
|
||||
|
||||
// Outdent whatever the
|
||||
// list item contains. Hacky.
|
||||
@@ -359,9 +359,10 @@ Lexer.prototype.token = function(src, top) {
|
||||
|
||||
// Determine whether the next list item belongs here.
|
||||
// Backpedal if it does not belong in this list.
|
||||
if (this.options.smartLists && i !== l - 1) {
|
||||
if (i !== l - 1) {
|
||||
b = block.bullet.exec(cap[i + 1])[0];
|
||||
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
|
||||
if (bull.length > 1 ? b.length === 1
|
||||
: (b.length > 1 || (this.options.smartLists && b !== bull))) {
|
||||
src = cap.slice(i + 1).join('\n') + src;
|
||||
i = l - 1;
|
||||
}
|
||||
@@ -450,12 +451,12 @@ Lexer.prototype.token = function(src, top) {
|
||||
}
|
||||
|
||||
// table (gfm)
|
||||
if (top && (cap = this.rules.table.exec(src))) {
|
||||
if (cap = this.rules.table.exec(src)) {
|
||||
item = {
|
||||
type: 'table',
|
||||
header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
|
||||
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
||||
cells: cap[3] ? cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') : []
|
||||
cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
|
||||
};
|
||||
|
||||
if (item.header.length === item.align.length) {
|
||||
@@ -544,14 +545,19 @@ var inline = {
|
||||
link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,
|
||||
reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
|
||||
nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
|
||||
strong: /^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
|
||||
em: /^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
|
||||
code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,
|
||||
strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
|
||||
em: /^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
|
||||
code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
|
||||
br: /^( {2,}|\\)\n(?!\s*$)/,
|
||||
del: noop,
|
||||
text: /^[\s\S]+?(?=[\\<!\[`*]|\b_| {2,}\n|$)/
|
||||
text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
|
||||
};
|
||||
|
||||
// list of punctuation marks from common mark spec
|
||||
// without ` and ] to workaround Rule 17 (inline code blocks/links)
|
||||
inline._punctuation = '!"#$%&\'()*+,\\-./:;<=>?@\\[^_{|}~';
|
||||
inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();
|
||||
|
||||
inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
|
||||
|
||||
inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
|
||||
@@ -568,8 +574,8 @@ inline.tag = edit(inline.tag)
|
||||
.replace('attribute', inline._attribute)
|
||||
.getRegex();
|
||||
|
||||
inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
|
||||
inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/;
|
||||
inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|`(?!`)|[^\[\]\\`])*?/;
|
||||
inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*)/;
|
||||
inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
|
||||
|
||||
inline.link = edit(inline.link)
|
||||
@@ -609,24 +615,23 @@ inline.pedantic = merge({}, inline.normal, {
|
||||
|
||||
inline.gfm = merge({}, inline.normal, {
|
||||
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
|
||||
url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/)
|
||||
.replace('email', inline._email)
|
||||
.getRegex(),
|
||||
_extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
|
||||
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
|
||||
_backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
|
||||
del: /^~+(?=\S)([\s\S]*?\S)~+/,
|
||||
text: edit(inline.text)
|
||||
.replace(']|', '~]|')
|
||||
.replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|')
|
||||
.getRegex()
|
||||
text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
|
||||
});
|
||||
|
||||
inline.gfm.url = edit(inline.gfm.url, 'i')
|
||||
.replace('email', inline.gfm._extended_email)
|
||||
.getRegex();
|
||||
/**
|
||||
* GFM + Line Breaks Inline Grammar
|
||||
*/
|
||||
|
||||
inline.breaks = merge({}, inline.gfm, {
|
||||
br: edit(inline.br).replace('{2,}', '*').getRegex(),
|
||||
text: edit(inline.gfm.text).replace('{2,}', '*').getRegex()
|
||||
text: edit(inline.gfm.text).replace(/\{2,\}/g, '*').getRegex()
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -687,43 +692,7 @@ InlineLexer.prototype.output = function(src) {
|
||||
// escape
|
||||
if (cap = this.rules.escape.exec(src)) {
|
||||
src = src.substring(cap[0].length);
|
||||
out += cap[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
// autolink
|
||||
if (cap = this.rules.autolink.exec(src)) {
|
||||
src = src.substring(cap[0].length);
|
||||
if (cap[2] === '@') {
|
||||
text = escape(this.mangle(cap[1]));
|
||||
href = 'mailto:' + text;
|
||||
} else {
|
||||
text = escape(cap[1]);
|
||||
href = text;
|
||||
}
|
||||
out += this.renderer.link(href, null, text);
|
||||
continue;
|
||||
}
|
||||
|
||||
// url (gfm)
|
||||
if (!this.inLink && (cap = this.rules.url.exec(src))) {
|
||||
do {
|
||||
prevCapZero = cap[0];
|
||||
cap[0] = this.rules._backpedal.exec(cap[0])[0];
|
||||
} while (prevCapZero !== cap[0]);
|
||||
src = src.substring(cap[0].length);
|
||||
if (cap[2] === '@') {
|
||||
text = escape(cap[0]);
|
||||
href = 'mailto:' + text;
|
||||
} else {
|
||||
text = escape(cap[0]);
|
||||
if (cap[1] === 'www.') {
|
||||
href = 'http://' + text;
|
||||
} else {
|
||||
href = text;
|
||||
}
|
||||
}
|
||||
out += this.renderer.link(href, null, text);
|
||||
out += escape(cap[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -734,17 +703,30 @@ InlineLexer.prototype.output = function(src) {
|
||||
} else if (this.inLink && /^<\/a>/i.test(cap[0])) {
|
||||
this.inLink = false;
|
||||
}
|
||||
if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
||||
this.inRawBlock = true;
|
||||
} else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
||||
this.inRawBlock = false;
|
||||
}
|
||||
|
||||
src = src.substring(cap[0].length);
|
||||
out += this.options.sanitize
|
||||
? this.options.sanitizer
|
||||
? this.options.sanitizer(cap[0])
|
||||
: escape(cap[0])
|
||||
: cap[0]
|
||||
: cap[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
// link
|
||||
if (cap = this.rules.link.exec(src)) {
|
||||
var lastParenIndex = findClosingBracket(cap[2], '()');
|
||||
if (lastParenIndex > -1) {
|
||||
var linkLen = cap[0].length - (cap[2].length - lastParenIndex) - (cap[3] || '').length;
|
||||
cap[2] = cap[2].substring(0, lastParenIndex);
|
||||
cap[0] = cap[0].substring(0, linkLen).trim();
|
||||
cap[3] = '';
|
||||
}
|
||||
src = src.substring(cap[0].length);
|
||||
this.inLink = true;
|
||||
href = cap[2];
|
||||
@@ -821,10 +803,51 @@ InlineLexer.prototype.output = function(src) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// autolink
|
||||
if (cap = this.rules.autolink.exec(src)) {
|
||||
src = src.substring(cap[0].length);
|
||||
if (cap[2] === '@') {
|
||||
text = escape(this.mangle(cap[1]));
|
||||
href = 'mailto:' + text;
|
||||
} else {
|
||||
text = escape(cap[1]);
|
||||
href = text;
|
||||
}
|
||||
out += this.renderer.link(href, null, text);
|
||||
continue;
|
||||
}
|
||||
|
||||
// url (gfm)
|
||||
if (!this.inLink && (cap = this.rules.url.exec(src))) {
|
||||
if (cap[2] === '@') {
|
||||
text = escape(cap[0]);
|
||||
href = 'mailto:' + text;
|
||||
} else {
|
||||
// do extended autolink path validation
|
||||
do {
|
||||
prevCapZero = cap[0];
|
||||
cap[0] = this.rules._backpedal.exec(cap[0])[0];
|
||||
} while (prevCapZero !== cap[0]);
|
||||
text = escape(cap[0]);
|
||||
if (cap[1] === 'www.') {
|
||||
href = 'http://' + text;
|
||||
} else {
|
||||
href = text;
|
||||
}
|
||||
}
|
||||
src = src.substring(cap[0].length);
|
||||
out += this.renderer.link(href, null, text);
|
||||
continue;
|
||||
}
|
||||
|
||||
// text
|
||||
if (cap = this.rules.text.exec(src)) {
|
||||
src = src.substring(cap[0].length);
|
||||
out += this.renderer.text(escape(this.smartypants(cap[0])));
|
||||
if (this.inRawBlock) {
|
||||
out += this.renderer.text(cap[0]);
|
||||
} else {
|
||||
out += this.renderer.text(escape(this.smartypants(cap[0])));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -838,7 +861,7 @@ InlineLexer.prototype.output = function(src) {
|
||||
|
||||
InlineLexer.escapes = function(text) {
|
||||
return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compile Link
|
||||
@@ -906,7 +929,8 @@ function Renderer(options) {
|
||||
this.options = options || marked.defaults;
|
||||
}
|
||||
|
||||
Renderer.prototype.code = function(code, lang, escaped) {
|
||||
Renderer.prototype.code = function(code, infostring, escaped) {
|
||||
var lang = (infostring || '').match(/\S*/)[0];
|
||||
if (this.options.highlight) {
|
||||
var out = this.options.highlight(code, lang);
|
||||
if (out != null && out !== code) {
|
||||
@@ -937,13 +961,13 @@ Renderer.prototype.html = function(html) {
|
||||
return html;
|
||||
};
|
||||
|
||||
Renderer.prototype.heading = function(text, level, raw) {
|
||||
Renderer.prototype.heading = function(text, level, raw, slugger) {
|
||||
if (this.options.headerIds) {
|
||||
return '<h'
|
||||
+ level
|
||||
+ ' id="'
|
||||
+ this.options.headerPrefix
|
||||
+ raw.toLowerCase().replace(/[^\w]+/g, '-')
|
||||
+ slugger.slug(raw)
|
||||
+ '">'
|
||||
+ text
|
||||
+ '</h'
|
||||
@@ -974,7 +998,7 @@ Renderer.prototype.checkbox = function(checked) {
|
||||
+ 'disabled="" type="checkbox"'
|
||||
+ (this.options.xhtml ? ' /' : '')
|
||||
+ '> ';
|
||||
}
|
||||
};
|
||||
|
||||
Renderer.prototype.paragraph = function(text) {
|
||||
return '<p>' + text + '</p>\n';
|
||||
@@ -1025,24 +1049,8 @@ Renderer.prototype.del = function(text) {
|
||||
};
|
||||
|
||||
Renderer.prototype.link = function(href, title, text) {
|
||||
if (this.options.sanitize) {
|
||||
try {
|
||||
var prot = decodeURIComponent(unescape(href))
|
||||
.replace(/[^\w:]/g, '')
|
||||
.toLowerCase();
|
||||
} catch (e) {
|
||||
return text;
|
||||
}
|
||||
if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
if (this.options.baseUrl && !originIndependentUrl.test(href)) {
|
||||
href = resolveUrl(this.options.baseUrl, href);
|
||||
}
|
||||
try {
|
||||
href = encodeURI(href).replace(/%25/g, '%');
|
||||
} catch (e) {
|
||||
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
||||
if (href === null) {
|
||||
return text;
|
||||
}
|
||||
var out = '<a href="' + escape(href) + '"';
|
||||
@@ -1054,9 +1062,11 @@ Renderer.prototype.link = function(href, title, text) {
|
||||
};
|
||||
|
||||
Renderer.prototype.image = function(href, title, text) {
|
||||
if (this.options.baseUrl && !originIndependentUrl.test(href)) {
|
||||
href = resolveUrl(this.options.baseUrl, href);
|
||||
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
||||
if (href === null) {
|
||||
return text;
|
||||
}
|
||||
|
||||
var out = '<img src="' + href + '" alt="' + text + '"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
@@ -1084,16 +1094,16 @@ TextRenderer.prototype.codespan =
|
||||
TextRenderer.prototype.del =
|
||||
TextRenderer.prototype.text = function (text) {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
TextRenderer.prototype.link =
|
||||
TextRenderer.prototype.image = function(href, title, text) {
|
||||
return '' + text;
|
||||
}
|
||||
};
|
||||
|
||||
TextRenderer.prototype.br = function() {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parsing & Compiling
|
||||
@@ -1106,6 +1116,7 @@ function Parser(options) {
|
||||
this.options.renderer = this.options.renderer || new Renderer();
|
||||
this.renderer = this.options.renderer;
|
||||
this.renderer.options = this.options;
|
||||
this.slugger = new Slugger();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1184,7 +1195,8 @@ Parser.prototype.tok = function() {
|
||||
return this.renderer.heading(
|
||||
this.inline.output(this.token.text),
|
||||
this.token.depth,
|
||||
unescape(this.inlineText.output(this.token.text)));
|
||||
unescape(this.inlineText.output(this.token.text)),
|
||||
this.slugger);
|
||||
}
|
||||
case 'code': {
|
||||
return this.renderer.code(this.token.text,
|
||||
@@ -1247,9 +1259,11 @@ Parser.prototype.tok = function() {
|
||||
case 'list_item_start': {
|
||||
body = '';
|
||||
var loose = this.token.loose;
|
||||
var checked = this.token.checked;
|
||||
var task = this.token.task;
|
||||
|
||||
if (this.token.task) {
|
||||
body += this.renderer.checkbox(this.token.checked);
|
||||
body += this.renderer.checkbox(checked);
|
||||
}
|
||||
|
||||
while (this.next().type !== 'list_item_end') {
|
||||
@@ -1257,8 +1271,7 @@ Parser.prototype.tok = function() {
|
||||
? this.parseText()
|
||||
: this.tok();
|
||||
}
|
||||
|
||||
return this.renderer.listitem(body);
|
||||
return this.renderer.listitem(body, task, checked);
|
||||
}
|
||||
case 'html': {
|
||||
// TODO parse inline content if parameter markdown=1
|
||||
@@ -1270,22 +1283,79 @@ Parser.prototype.tok = function() {
|
||||
case 'text': {
|
||||
return this.renderer.paragraph(this.parseText());
|
||||
}
|
||||
default: {
|
||||
var errMsg = 'Token with "' + this.token.type + '" type was not found.';
|
||||
if (this.options.silent) {
|
||||
console.log(errMsg);
|
||||
} else {
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Slugger generates header id
|
||||
*/
|
||||
|
||||
function Slugger () {
|
||||
this.seen = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to unique id
|
||||
*/
|
||||
|
||||
Slugger.prototype.slug = function (value) {
|
||||
var slug = value
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '')
|
||||
.replace(/\s/g, '-');
|
||||
|
||||
if (this.seen.hasOwnProperty(slug)) {
|
||||
var originalSlug = slug;
|
||||
do {
|
||||
this.seen[originalSlug]++;
|
||||
slug = originalSlug + '-' + this.seen[originalSlug];
|
||||
} while (this.seen.hasOwnProperty(slug));
|
||||
}
|
||||
this.seen[slug] = 0;
|
||||
|
||||
return slug;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function escape(html, encode) {
|
||||
return html
|
||||
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
if (encode) {
|
||||
if (escape.escapeTest.test(html)) {
|
||||
return html.replace(escape.escapeReplace, function (ch) { return escape.replacements[ch]; });
|
||||
}
|
||||
} else {
|
||||
if (escape.escapeTestNoEncode.test(html)) {
|
||||
return html.replace(escape.escapeReplaceNoEncode, function (ch) { return escape.replacements[ch]; });
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
escape.escapeTest = /[&<>"']/;
|
||||
escape.escapeReplace = /[&<>"']/g;
|
||||
escape.replacements = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
|
||||
escape.escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
|
||||
escape.escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
|
||||
|
||||
function unescape(html) {
|
||||
// explicitly match decimal, hex, and named HTML entities
|
||||
return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
|
||||
@@ -1316,6 +1386,30 @@ function edit(regex, opt) {
|
||||
};
|
||||
}
|
||||
|
||||
function cleanUrl(sanitize, base, href) {
|
||||
if (sanitize) {
|
||||
try {
|
||||
var prot = decodeURIComponent(unescape(href))
|
||||
.replace(/[^\w:]/g, '')
|
||||
.toLowerCase();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (base && !originIndependentUrl.test(href)) {
|
||||
href = resolveUrl(base, href);
|
||||
}
|
||||
try {
|
||||
href = encodeURI(href).replace(/%25/g, '%');
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
return href;
|
||||
}
|
||||
|
||||
function resolveUrl(base, href) {
|
||||
if (!baseUrls[' ' + base]) {
|
||||
// we can ignore everything in base after the last slash of its path component,
|
||||
@@ -1418,6 +1512,26 @@ function rtrim(str, c, invert) {
|
||||
return str.substr(0, str.length - suffLen);
|
||||
}
|
||||
|
||||
function findClosingBracket(str, b) {
|
||||
if (str.indexOf(b[1]) === -1) {
|
||||
return -1;
|
||||
}
|
||||
var level = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (str[i] === '\\') {
|
||||
i++;
|
||||
} else if (str[i] === b[0]) {
|
||||
level++;
|
||||
} else if (str[i] === b[1]) {
|
||||
level--;
|
||||
if (level < 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marked
|
||||
*/
|
||||
@@ -1446,7 +1560,7 @@ function marked(src, opt, callback) {
|
||||
i = 0;
|
||||
|
||||
try {
|
||||
tokens = Lexer.lex(src, opt)
|
||||
tokens = Lexer.lex(src, opt);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
@@ -1545,7 +1659,7 @@ marked.getDefaults = function () {
|
||||
tables: true,
|
||||
xhtml: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
marked.defaults = marked.getDefaults();
|
||||
|
||||
@@ -1565,6 +1679,8 @@ marked.lexer = Lexer.lex;
|
||||
marked.InlineLexer = InlineLexer;
|
||||
marked.inlineLexer = InlineLexer.output;
|
||||
|
||||
marked.Slugger = Slugger;
|
||||
|
||||
marked.parse = marked;
|
||||
|
||||
// BEGIN MONACOCHANGE
|
||||
@@ -1582,7 +1698,7 @@ __marked_exports = marked;
|
||||
// ESM-comment-begin
|
||||
define(function() { return __marked_exports; });
|
||||
// ESM-comment-end
|
||||
|
||||
|
||||
// ESM-uncomment-begin
|
||||
// export var marked = __marked_exports;
|
||||
// export var Parser = __marked_exports.Parser;
|
||||
|
||||
@@ -146,7 +146,7 @@ export function normalizePath(resource: URI): URI {
|
||||
export function originalFSPath(uri: URI): string {
|
||||
let value: string;
|
||||
const uriPath = uri.path;
|
||||
if (uri.authority && uriPath.length > 1 && uri.scheme === 'file') {
|
||||
if (uri.authority && uriPath.length > 1 && uri.scheme === Schemas.file) {
|
||||
// unc path: file://shares/c$/far/boo
|
||||
value = `//${uri.authority}${uriPath}`;
|
||||
} else if (
|
||||
|
||||
@@ -151,7 +151,7 @@ export const enum ProtocolConstants {
|
||||
/**
|
||||
* If there is no reconnection within this time-frame, consider the connection permanently closed...
|
||||
*/
|
||||
ReconnectionGraceTime = 60 * 60 * 1000, // 1hr
|
||||
ReconnectionGraceTime = 3 * 60 * 60 * 1000, // 3hrs
|
||||
}
|
||||
|
||||
class ProtocolMessage {
|
||||
@@ -687,6 +687,10 @@ export class PersistentProtocol {
|
||||
this._recvKeepAliveCheck();
|
||||
}
|
||||
|
||||
public acceptDisconnect(): void {
|
||||
this._onClose.fire();
|
||||
}
|
||||
|
||||
private _receiveMessage(msg: ProtocolMessage): void {
|
||||
if (msg.ack > this._outgoingAckId) {
|
||||
this._outgoingAckId = msg.ack;
|
||||
|
||||
@@ -557,8 +557,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
const configuration = configurationIn ? configurationIn : objects.mixin({}, this.currentConfig);
|
||||
|
||||
// Delete some properties we do not want during reload
|
||||
delete configuration.filesToOpen;
|
||||
delete configuration.filesToCreate;
|
||||
delete configuration.filesToOpenOrCreate;
|
||||
delete configuration.filesToDiff;
|
||||
delete configuration.filesToWait;
|
||||
|
||||
|
||||
@@ -91,8 +91,7 @@ interface IPathParseOptions {
|
||||
}
|
||||
|
||||
interface IFileInputs {
|
||||
filesToOpen: IPath[];
|
||||
filesToCreate: IPath[];
|
||||
filesToOpenOrCreate: IPath[];
|
||||
filesToDiff: IPath[];
|
||||
filesToWait?: IPathsToWaitFor;
|
||||
remoteAuthority?: string;
|
||||
@@ -112,9 +111,6 @@ interface IPathToOpen extends IPath {
|
||||
// the remote authority for the Code instance to open. Undefined if not remote.
|
||||
remoteAuthority?: string;
|
||||
|
||||
// indicator to create the file path in the Code instance
|
||||
createFilePath?: boolean;
|
||||
|
||||
// optional label for the recent history
|
||||
label?: string;
|
||||
}
|
||||
@@ -397,13 +393,9 @@ export class WindowsManager implements IWindowsMainService {
|
||||
workspacesToOpen.push(path);
|
||||
} else if (path.fileUri) {
|
||||
if (!fileInputs) {
|
||||
fileInputs = { filesToCreate: [], filesToOpen: [], filesToDiff: [], remoteAuthority: path.remoteAuthority };
|
||||
}
|
||||
if (!path.createFilePath) {
|
||||
fileInputs.filesToOpen.push(path);
|
||||
} else {
|
||||
fileInputs.filesToCreate.push(path);
|
||||
fileInputs = { filesToOpenOrCreate: [], filesToDiff: [], remoteAuthority: path.remoteAuthority };
|
||||
}
|
||||
fileInputs.filesToOpenOrCreate.push(path);
|
||||
} else if (path.backupPath) {
|
||||
emptyToRestore.push({ backupFolder: basename(path.backupPath), remoteAuthority: path.remoteAuthority });
|
||||
} else {
|
||||
@@ -413,15 +405,14 @@ export class WindowsManager implements IWindowsMainService {
|
||||
|
||||
// When run with --diff, take the files to open as files to diff
|
||||
// if there are exactly two files provided.
|
||||
if (fileInputs && openConfig.diffMode && fileInputs.filesToOpen.length === 2) {
|
||||
fileInputs.filesToDiff = fileInputs.filesToOpen;
|
||||
fileInputs.filesToOpen = [];
|
||||
fileInputs.filesToCreate = []; // diff ignores other files that do not exist
|
||||
if (fileInputs && openConfig.diffMode && fileInputs.filesToOpenOrCreate.length === 2) {
|
||||
fileInputs.filesToDiff = fileInputs.filesToOpenOrCreate;
|
||||
fileInputs.filesToOpenOrCreate = [];
|
||||
}
|
||||
|
||||
// When run with --wait, make sure we keep the paths to wait for
|
||||
if (fileInputs && openConfig.waitMarkerFileURI) {
|
||||
fileInputs.filesToWait = { paths: [...fileInputs.filesToDiff, ...fileInputs.filesToOpen, ...fileInputs.filesToCreate], waitMarkerFileUri: openConfig.waitMarkerFileURI };
|
||||
fileInputs.filesToWait = { paths: [...fileInputs.filesToDiff, ...fileInputs.filesToOpenOrCreate], waitMarkerFileUri: openConfig.waitMarkerFileURI };
|
||||
}
|
||||
|
||||
//
|
||||
@@ -551,7 +542,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
if (potentialWindowsCount === 0 && fileInputs) {
|
||||
|
||||
// Find suitable window or folder path to open files in
|
||||
const fileToCheck = fileInputs.filesToOpen[0] || fileInputs.filesToCreate[0] || fileInputs.filesToDiff[0];
|
||||
const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0];
|
||||
// only look at the windows with correct authority
|
||||
const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority);
|
||||
|
||||
@@ -746,10 +737,9 @@ export class WindowsManager implements IWindowsMainService {
|
||||
private doOpenFilesInExistingWindow(configuration: IOpenConfiguration, window: ICodeWindow, fileInputs?: IFileInputs): ICodeWindow {
|
||||
window.focus(); // make sure window has focus
|
||||
|
||||
const params: { filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[], filesToWait?: IPathsToWaitFor, termProgram?: string } = {};
|
||||
const params: { filesToOpenOrCreate?: IPath[], filesToDiff?: IPath[], filesToWait?: IPathsToWaitFor, termProgram?: string } = {};
|
||||
if (fileInputs) {
|
||||
params.filesToOpen = fileInputs.filesToOpen;
|
||||
params.filesToCreate = fileInputs.filesToCreate;
|
||||
params.filesToOpenOrCreate = fileInputs.filesToOpenOrCreate;
|
||||
params.filesToDiff = fileInputs.filesToDiff;
|
||||
params.filesToWait = fileInputs.filesToWait;
|
||||
}
|
||||
@@ -958,7 +948,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
if (pathToOpen && pathToOpen.folderUri) {
|
||||
windowsToOpen.push(pathToOpen);
|
||||
}
|
||||
} else if (restoreWindows !== 'folders' && openedWindow.backupPath) { // Windows that were Empty
|
||||
} else if (restoreWindows !== 'folders' && openedWindow.backupPath && !openedWindow.remoteAuthority) { // Local windows that were empty. Empty windows with backups will always be restored in open()
|
||||
windowsToOpen.push({ backupPath: openedWindow.backupPath, remoteAuthority: openedWindow.remoteAuthority });
|
||||
}
|
||||
}
|
||||
@@ -1065,47 +1055,57 @@ export class WindowsManager implements IWindowsMainService {
|
||||
anyPath = parsedPath.path;
|
||||
}
|
||||
|
||||
// open remote if either specified in the cli even if it is a local file. TODO: Future idea: resolve in remote host context.
|
||||
// open remote if either specified in the cli even if it is a local file. TODO@aeschli: Future idea: resolve in remote host context.
|
||||
const remoteAuthority = options.remoteAuthority;
|
||||
|
||||
const candidate = normalize(anyPath);
|
||||
try {
|
||||
const candidateStat = fs.statSync(candidate);
|
||||
if (candidateStat) {
|
||||
if (candidateStat.isFile()) {
|
||||
if (candidateStat.isFile()) {
|
||||
|
||||
// Workspace (unless disabled via flag)
|
||||
if (!forceOpenWorkspaceAsFile) {
|
||||
const workspace = this.workspacesMainService.resolveLocalWorkspaceSync(URI.file(candidate));
|
||||
if (workspace) {
|
||||
return { workspace: { id: workspace.id, configPath: workspace.configPath }, remoteAuthority: workspace.remoteAuthority };
|
||||
}
|
||||
// Workspace (unless disabled via flag)
|
||||
if (!forceOpenWorkspaceAsFile) {
|
||||
const workspace = this.workspacesMainService.resolveLocalWorkspaceSync(URI.file(candidate));
|
||||
if (workspace) {
|
||||
return {
|
||||
workspace: { id: workspace.id, configPath: workspace.configPath },
|
||||
remoteAuthority: workspace.remoteAuthority,
|
||||
exists: true
|
||||
};
|
||||
}
|
||||
|
||||
// File
|
||||
return {
|
||||
fileUri: URI.file(candidate),
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
remoteAuthority
|
||||
};
|
||||
}
|
||||
|
||||
// Folder (we check for isDirectory() because e.g. paths like /dev/null
|
||||
// are neither file nor folder but some external tools might pass them
|
||||
// over to us)
|
||||
else if (candidateStat.isDirectory()) {
|
||||
return {
|
||||
folderUri: URI.file(candidate),
|
||||
remoteAuthority
|
||||
};
|
||||
}
|
||||
// File
|
||||
return {
|
||||
fileUri: URI.file(candidate),
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
remoteAuthority,
|
||||
exists: true
|
||||
};
|
||||
}
|
||||
|
||||
// Folder (we check for isDirectory() because e.g. paths like /dev/null
|
||||
// are neither file nor folder but some external tools might pass them
|
||||
// over to us)
|
||||
else if (candidateStat.isDirectory()) {
|
||||
return {
|
||||
folderUri: URI.file(candidate),
|
||||
remoteAuthority,
|
||||
exists: true
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
const fileUri = URI.file(candidate);
|
||||
this.historyMainService.removeFromRecentlyOpened([fileUri]); // since file does not seem to exist anymore, remove from recent
|
||||
|
||||
// assume this is a file that does not yet exist
|
||||
if (options && options.ignoreFileNotFound) {
|
||||
return { fileUri, createFilePath: true, remoteAuthority }; // assume this is a file that does not yet exist
|
||||
return {
|
||||
fileUri,
|
||||
remoteAuthority,
|
||||
exists: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1279,8 +1279,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
|
||||
const fileInputs = options.fileInputs;
|
||||
if (fileInputs) {
|
||||
configuration.filesToOpen = fileInputs.filesToOpen;
|
||||
configuration.filesToCreate = fileInputs.filesToCreate;
|
||||
configuration.filesToOpenOrCreate = fileInputs.filesToOpenOrCreate;
|
||||
configuration.filesToDiff = fileInputs.filesToDiff;
|
||||
configuration.filesToWait = fileInputs.filesToWait;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,15 @@ export interface IBaseResourceInput {
|
||||
* looking at the scheme of the resource(s).
|
||||
*/
|
||||
readonly forceFile?: boolean;
|
||||
|
||||
/**
|
||||
* Hint to indicate that this input should be treated as a
|
||||
* untitled file.
|
||||
*
|
||||
* Without this hint, the editor service will make a guess by
|
||||
* looking at the scheme of the resource(s).
|
||||
*/
|
||||
readonly forceUntitled?: boolean;
|
||||
}
|
||||
|
||||
export interface IResourceInput extends IBaseResourceInput {
|
||||
|
||||
@@ -288,7 +288,12 @@ export function markAsFileSystemProviderError(error: Error, code: FileSystemProv
|
||||
return error;
|
||||
}
|
||||
|
||||
export function toFileSystemProviderErrorCode(error: Error): FileSystemProviderErrorCode {
|
||||
export function toFileSystemProviderErrorCode(error: Error | undefined | null): FileSystemProviderErrorCode {
|
||||
|
||||
// Guard against abuse
|
||||
if (!error) {
|
||||
return FileSystemProviderErrorCode.Unknown;
|
||||
}
|
||||
|
||||
// FileSystemProviderError comes with the code
|
||||
if (error instanceof FileSystemProviderError) {
|
||||
@@ -758,12 +763,12 @@ export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096;
|
||||
*/
|
||||
export const ETAG_DISABLED = '';
|
||||
|
||||
export function etag(mtime: number, size: number): string;
|
||||
export function etag(mtime: number | undefined, size: number | undefined): string | undefined;
|
||||
export function etag(mtime: number | undefined, size: number | undefined): string | undefined {
|
||||
if (typeof size !== 'number' || typeof mtime !== 'number') {
|
||||
export function etag(stat: { mtime: number, size: number }): string;
|
||||
export function etag(stat: { mtime: number | undefined, size: number | undefined }): string | undefined;
|
||||
export function etag(stat: { mtime: number | undefined, size: number | undefined }): string | undefined {
|
||||
if (typeof stat.size !== 'number' || typeof stat.mtime !== 'number') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return mtime.toString(29) + size.toString(31);
|
||||
return stat.mtime.toString(29) + stat.size.toString(31);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ configurationRegistry.registerConfiguration({
|
||||
'update.showReleaseNotes': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
scope: ConfigurationScope.APPLICATION,
|
||||
description: localize('showReleaseNotes', "Show Release Notes after an update. The Release Notes are fetched from a Microsoft online service."),
|
||||
tags: ['usesOnlineServices']
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ export const enum ReadyState {
|
||||
|
||||
export interface IPath extends IPathData {
|
||||
|
||||
// the file path to open within a Code instance
|
||||
// the file path to open within the instance
|
||||
fileUri?: URI;
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ export interface IPathsToWaitForData {
|
||||
|
||||
export interface IPathData {
|
||||
|
||||
// the file path to open within a Code instance
|
||||
// the file path to open within the instance
|
||||
fileUri?: UriComponents;
|
||||
|
||||
// the line number in the file path to open
|
||||
@@ -382,11 +382,15 @@ export interface IPathData {
|
||||
|
||||
// the column number in the file path to open
|
||||
columnNumber?: number;
|
||||
|
||||
// a hint that the file exists. if true, the
|
||||
// file exists, if false it does not. with
|
||||
// undefined the state is unknown.
|
||||
exists?: boolean;
|
||||
}
|
||||
|
||||
export interface IOpenFileRequest {
|
||||
filesToOpen?: IPathData[];
|
||||
filesToCreate?: IPathData[];
|
||||
filesToOpenOrCreate?: IPathData[];
|
||||
filesToDiff?: IPathData[];
|
||||
filesToWait?: IPathsToWaitForData;
|
||||
termProgram?: string;
|
||||
@@ -430,8 +434,7 @@ export interface IWindowConfiguration extends ParsedArgs {
|
||||
perfWindowLoadTime?: number;
|
||||
perfEntries: ExportData;
|
||||
|
||||
filesToOpen?: IPath[];
|
||||
filesToCreate?: IPath[];
|
||||
filesToOpenOrCreate?: IPath[];
|
||||
filesToDiff?: IPath[];
|
||||
filesToWait?: IPathsToWaitFor;
|
||||
termProgram?: string;
|
||||
|
||||
@@ -74,9 +74,11 @@ export class WindowsService implements IWindowsService {
|
||||
return this.channel.call('closeWorkspace', windowId);
|
||||
}
|
||||
|
||||
enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult> {
|
||||
enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
|
||||
return this.channel.call('enterWorkspace', [windowId, path]).then((result: IEnterWorkspaceResult) => {
|
||||
result.workspace = reviveWorkspaceIdentifier(result.workspace);
|
||||
if (result) {
|
||||
result.workspace = reviveWorkspaceIdentifier(result.workspace);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
|
||||
async getRecentlyOpened(windowId: number): Promise<IRecentlyOpened> {
|
||||
this.logService.trace('windowsService#getRecentlyOpened', windowId);
|
||||
|
||||
return this.withWindow(windowId, codeWindow => this.historyService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpen), () => this.historyService.getRecentlyOpened())!;
|
||||
return this.withWindow(windowId, codeWindow => this.historyService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpenOrCreate), () => this.historyService.getRecentlyOpened())!;
|
||||
}
|
||||
|
||||
async newWindowTab(): Promise<void> {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/works
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { extname } from 'vs/base/common/path';
|
||||
import { dirname, resolvePath, isEqualAuthority, isEqualOrParent, relativePath } from 'vs/base/common/resources';
|
||||
import { dirname, resolvePath, isEqualAuthority, isEqualOrParent, relativePath, extname as resourceExtname } from 'vs/base/common/resources';
|
||||
import * as jsonEdit from 'vs/base/common/jsonEdit';
|
||||
import * as json from 'vs/base/common/json';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -158,8 +158,10 @@ export function isSingleFolderWorkspaceInitializationPayload(obj: any): obj is I
|
||||
|
||||
const WORKSPACE_SUFFIX = '.' + WORKSPACE_EXTENSION;
|
||||
|
||||
export function hasWorkspaceFileExtension(path: string) {
|
||||
return extname(path) === WORKSPACE_SUFFIX;
|
||||
export function hasWorkspaceFileExtension(path: string | URI) {
|
||||
const ext = (typeof path === 'string') ? extname(path) : resourceExtname(path);
|
||||
|
||||
return ext === WORKSPACE_SUFFIX;
|
||||
}
|
||||
|
||||
const SLASH = '/';
|
||||
|
||||
@@ -61,7 +61,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
|
||||
}
|
||||
|
||||
private isWorkspacePath(uri: URI): boolean {
|
||||
return this.isInsideWorkspacesHome(uri) || hasWorkspaceFileExtension(uri.path);
|
||||
return this.isInsideWorkspacesHome(uri) || hasWorkspaceFileExtension(uri);
|
||||
}
|
||||
|
||||
private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null {
|
||||
|
||||
@@ -36,6 +36,7 @@ function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) =>
|
||||
|
||||
interface IOpenFolderAPICommandOptions {
|
||||
forceNewWindow?: boolean;
|
||||
forceReuseWindow?: boolean;
|
||||
noRecentEntry?: boolean;
|
||||
}
|
||||
|
||||
@@ -50,9 +51,9 @@ export class OpenFolderAPICommand {
|
||||
if (!uri) {
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg.forceNewWindow });
|
||||
}
|
||||
const options: IOpenSettings = { forceNewWindow: arg.forceNewWindow, noRecentEntry: arg.noRecentEntry };
|
||||
const options: IOpenSettings = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry };
|
||||
uri = URI.revive(uri);
|
||||
const uriToOpen: IURIToOpen = (hasWorkspaceFileExtension(uri.path) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri };
|
||||
const uriToOpen: IURIToOpen = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri };
|
||||
return executor.executeCommand('_files.windowOpen', [uriToOpen], options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export class ResourcesDropHandler {
|
||||
return Promise.all(fileOnDiskResources.map(fileOnDiskResource => {
|
||||
|
||||
// Check for Workspace
|
||||
if (hasWorkspaceFileExtension(fileOnDiskResource.fsPath)) {
|
||||
if (hasWorkspaceFileExtension(fileOnDiskResource)) {
|
||||
urisToOpen.push({ workspaceUri: fileOnDiskResource });
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -10,8 +10,7 @@ import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/brow
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { IUntitledResourceInput, IResourceDiffInput } from 'vs/workbench/common/editor';
|
||||
import { IUntitledResourceInput, pathsToEditors } from 'vs/workbench/common/editor';
|
||||
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
|
||||
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
|
||||
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
|
||||
@@ -24,7 +23,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
|
||||
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IWindowService, IPath, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
@@ -34,7 +33,7 @@ import { IDimension } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
enum Settings {
|
||||
MENUBAR_VISIBLE = 'window.menuBarVisibility',
|
||||
@@ -182,7 +181,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.registerLayoutListeners();
|
||||
|
||||
// State
|
||||
this.initLayoutState(accessor.get(ILifecycleService));
|
||||
this.initLayoutState(accessor.get(ILifecycleService), accessor.get(IFileService));
|
||||
}
|
||||
|
||||
private registerLayoutListeners(): void {
|
||||
@@ -319,7 +318,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
}
|
||||
|
||||
private initLayoutState(lifecycleService: ILifecycleService): void {
|
||||
private initLayoutState(lifecycleService: ILifecycleService, fileService: IFileService): void {
|
||||
|
||||
// Fullscreen
|
||||
this.state.fullscreen = isFullscreen();
|
||||
@@ -358,7 +357,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.state.editor.restoreCentered = this.storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false);
|
||||
|
||||
// Editors to open
|
||||
this.state.editor.editorsToOpen = this.resolveEditorsToOpen();
|
||||
this.state.editor.editorsToOpen = this.resolveEditorsToOpen(fileService);
|
||||
|
||||
// Panel visibility
|
||||
this.state.panel.hidden = this.storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true);
|
||||
@@ -389,7 +388,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE);
|
||||
}
|
||||
|
||||
private resolveEditorsToOpen(): Promise<IResourceEditor[]> | IResourceEditor[] {
|
||||
private resolveEditorsToOpen(fileService: IFileService): Promise<IResourceEditor[]> | IResourceEditor[] {
|
||||
const configuration = this.environmentService.configuration;
|
||||
const hasInitialFilesToOpen = this.hasInitialFilesToOpen();
|
||||
|
||||
@@ -400,21 +399,19 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
if (hasInitialFilesToOpen) {
|
||||
|
||||
// Files to diff is exclusive
|
||||
const filesToDiff = this.toInputs(configuration.filesToDiff, false);
|
||||
if (filesToDiff && filesToDiff.length === 2) {
|
||||
return [<IResourceDiffInput>{
|
||||
leftResource: filesToDiff[0].resource,
|
||||
rightResource: filesToDiff[1].resource,
|
||||
options: { pinned: true },
|
||||
forceFile: true
|
||||
}];
|
||||
}
|
||||
return pathsToEditors(configuration.filesToDiff, fileService).then(filesToDiff => {
|
||||
if (filesToDiff && filesToDiff.length === 2) {
|
||||
return [{
|
||||
leftResource: filesToDiff[0].resource,
|
||||
rightResource: filesToDiff[1].resource,
|
||||
options: { pinned: true },
|
||||
forceFile: true
|
||||
}];
|
||||
}
|
||||
|
||||
const filesToCreate = this.toInputs(configuration.filesToCreate, true);
|
||||
const filesToOpen = this.toInputs(configuration.filesToOpen, false);
|
||||
|
||||
// Otherwise: Open/Create files
|
||||
return [...filesToOpen, ...filesToCreate];
|
||||
// Otherwise: Open/Create files
|
||||
return pathsToEditors(configuration.filesToOpenOrCreate, fileService);
|
||||
});
|
||||
}
|
||||
|
||||
// Empty workbench
|
||||
@@ -439,38 +436,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
const configuration = this.environmentService.configuration;
|
||||
|
||||
return !!(
|
||||
(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
|
||||
(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
|
||||
(configuration.filesToDiff && configuration.filesToDiff.length > 0));
|
||||
}
|
||||
|
||||
private toInputs(paths: IPath[] | undefined, isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
|
||||
if (!paths || !paths.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return coalesce(paths.map(p => {
|
||||
const resource = p.fileUri;
|
||||
if (!resource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let input: IResourceInput | IUntitledResourceInput;
|
||||
if (isNew) {
|
||||
input = { filePath: resource.fsPath, options: { pinned: true } };
|
||||
} else {
|
||||
input = { resource, options: { pinned: true }, forceFile: true };
|
||||
}
|
||||
|
||||
if (!isNew && typeof p.lineNumber === 'number') {
|
||||
input.options!.selection = {
|
||||
startLineNumber: p.lineNumber,
|
||||
startColumn: p.columnNumber || 1
|
||||
};
|
||||
}
|
||||
|
||||
return input;
|
||||
}));
|
||||
(configuration.filesToOpenOrCreate && configuration.filesToOpenOrCreate.length > 0) ||
|
||||
(configuration.filesToDiff && configuration.filesToDiff.length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
private updatePanelPosition() {
|
||||
|
||||
@@ -953,8 +953,7 @@ export class SimpleWindowConfiguration implements IWindowConfiguration {
|
||||
perfWindowLoadTime?: number;
|
||||
perfEntries: ExportData;
|
||||
|
||||
filesToOpen?: IPath[];
|
||||
filesToCreate?: IPath[];
|
||||
filesToOpenOrCreate?: IPath[];
|
||||
filesToDiff?: IPath[];
|
||||
filesToWait?: IPathsToWaitFor;
|
||||
termProgram?: string;
|
||||
|
||||
@@ -76,7 +76,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IViewsService private readonly viewsService: IViewsService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService
|
||||
) {
|
||||
super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
|
||||
|
||||
@@ -150,7 +150,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
if (viewContainer && viewContainer.hideIfEmpty) {
|
||||
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
|
||||
if (viewDescriptors && viewDescriptors.activeViewDescriptors.length === 0) {
|
||||
this.removeComposite(viewletDescriptor.id, true); // Update the composite bar by hiding
|
||||
this.hideComposite(viewletDescriptor.id); // Update the composite bar by hiding
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,14 +309,14 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
disposable.dispose();
|
||||
}
|
||||
this.viewletDisposables.delete(viewletId);
|
||||
this.removeComposite(viewletId, true);
|
||||
this.hideComposite(viewletId);
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews(viewlet: ViewletDescriptor, viewDescriptors: IViewDescriptorCollection): void {
|
||||
if (viewDescriptors.activeViewDescriptors.length) {
|
||||
this.compositeBar.addComposite(viewlet);
|
||||
} else {
|
||||
this.removeComposite(viewlet.id, true);
|
||||
this.hideComposite(viewlet.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,18 +334,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
const viewlets = this.viewletService.getViewlets();
|
||||
for (const { id } of this.cachedViewlets) {
|
||||
if (viewlets.every(viewlet => viewlet.id !== id)) {
|
||||
this.removeComposite(id, false);
|
||||
this.hideComposite(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private removeComposite(compositeId: string, hide: boolean): void {
|
||||
if (hide) {
|
||||
this.compositeBar.hideComposite(compositeId);
|
||||
} else {
|
||||
this.compositeBar.removeComposite(compositeId);
|
||||
}
|
||||
|
||||
private hideComposite(compositeId: string): void {
|
||||
this.compositeBar.hideComposite(compositeId);
|
||||
const compositeActions = this.compositeActions[compositeId];
|
||||
if (compositeActions) {
|
||||
compositeActions.activityAction.dispose();
|
||||
@@ -441,7 +436,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
}
|
||||
}
|
||||
state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem && compositeItem.pinned, order: compositeItem ? compositeItem.order : undefined, visible: compositeItem && compositeItem.visible });
|
||||
state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible });
|
||||
} else {
|
||||
state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export interface IOpenCallbacks {
|
||||
openInternal: (input: EditorInput, options: EditorOptions) => Promise<void>;
|
||||
@@ -48,6 +49,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
telemetryService: ITelemetryService,
|
||||
themeService: IThemeService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IStorageService storageService: IStorageService
|
||||
) {
|
||||
super(id, telemetryService, themeService, storageService);
|
||||
@@ -92,9 +94,11 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
this.textFileService,
|
||||
this.binaryContainer,
|
||||
this.scrollbar,
|
||||
resource => this.handleOpenInternalCallback(input, options),
|
||||
resource => this.callbacks.openExternal(resource),
|
||||
meta => this.handleMetadataChanged(meta)
|
||||
{
|
||||
openInternalClb: _ => this.handleOpenInternalCallback(input, options),
|
||||
openExternalClb: this.environmentService.configuration.remoteAuthority ? undefined : resource => this.callbacks.openExternal(resource),
|
||||
metadataClb: meta => this.handleMetadataChanged(meta)
|
||||
}
|
||||
);
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -47,6 +47,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
|
||||
import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { onDidChangeZoomLevel } from 'vs/base/browser/browser';
|
||||
import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
class Item extends BreadcrumbsItem {
|
||||
|
||||
@@ -167,6 +168,7 @@ export class BreadcrumbsControl {
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IBreadcrumbsService breadcrumbsService: IBreadcrumbsService,
|
||||
) {
|
||||
this.domNode = document.createElement('div');
|
||||
@@ -238,16 +240,18 @@ export class BreadcrumbsControl {
|
||||
this._ckBreadcrumbsVisible.set(true);
|
||||
this._ckBreadcrumbsPossible.set(true);
|
||||
|
||||
let editor = this._getActiveCodeEditor();
|
||||
let model = new EditorBreadcrumbsModel(input.getResource()!, editor, this._workspaceService, this._configurationService);
|
||||
const uri = input.getResource()!;
|
||||
const editor = this._getActiveCodeEditor();
|
||||
const model = new EditorBreadcrumbsModel(uri, editor, this._workspaceService, this._configurationService);
|
||||
dom.toggleClass(this.domNode, 'relative-path', model.isRelative());
|
||||
dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\');
|
||||
|
||||
let updateBreadcrumbs = () => {
|
||||
let items = model.getElements().map(element => new Item(element, this._options, this._instantiationService));
|
||||
const updateBreadcrumbs = () => {
|
||||
const items = model.getElements().map(element => new Item(element, this._options, this._instantiationService));
|
||||
this._widget.setItems(items);
|
||||
this._widget.reveal(items[items.length - 1]);
|
||||
};
|
||||
let listener = model.onDidUpdate(updateBreadcrumbs);
|
||||
const listener = model.onDidUpdate(updateBreadcrumbs);
|
||||
updateBreadcrumbs();
|
||||
this._breadcrumbsDisposables = [model, listener];
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { AllEditorsPicker, ActiveEditorGroupPicker } from 'vs/workbench/browser/parts/editor/editorPicker';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/editor/editorWidgets';
|
||||
import { ZoomStatusbarItem } from 'vs/workbench/browser/parts/editor/resourceViewer';
|
||||
@@ -148,11 +147,10 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
return instantiationService.invokeFunction<UntitledEditorInput>(accessor => {
|
||||
const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput);
|
||||
const resource = !!deserialized.resourceJSON ? URI.revive(<UriComponents>deserialized.resourceJSON) : URI.parse(deserialized.resource);
|
||||
const filePath = resource.scheme === Schemas.untitled ? undefined : resource.scheme === Schemas.file ? resource.fsPath : resource.path;
|
||||
const language = deserialized.modeId;
|
||||
const encoding = deserialized.encoding;
|
||||
|
||||
return accessor.get(IEditorService).createInput({ resource, filePath, language, encoding }) as UntitledEditorInput;
|
||||
return accessor.get(IEditorService).createInput({ resource, language, encoding, forceUntitled: true }) as UntitledEditorInput;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { guessMimeTypes } from 'vs/base/common/mime';
|
||||
import { extname } from 'vs/base/common/path';
|
||||
import { extname } from 'vs/base/common/resources';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
@@ -526,8 +527,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
const descriptor = editor.getTelemetryDescriptor();
|
||||
|
||||
const resource = editor.getResource();
|
||||
if (resource && resource.fsPath) {
|
||||
descriptor['resource'] = { mimeType: guessMimeTypes(resource.fsPath).join(', '), scheme: resource.scheme, ext: extname(resource.fsPath), path: hash(resource.fsPath) };
|
||||
const path = resource ? resource.scheme === Schemas.file ? resource.fsPath : resource.path : undefined;
|
||||
if (resource && path) {
|
||||
descriptor['resource'] = { mimeType: guessMimeTypes(path).join(', '), scheme: resource.scheme, ext: extname(resource), path: hash(path) };
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"EditorTelemetryDescriptor" : {
|
||||
|
||||
@@ -139,7 +139,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit
|
||||
return false; // we need a model
|
||||
}
|
||||
|
||||
if (!hasWorkspaceFileExtension(model.uri.fsPath)) {
|
||||
if (!hasWorkspaceFileExtension(model.uri)) {
|
||||
return false; // we need a workspace file
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.backslash-path .monaco-breadcrumb-item::before {
|
||||
content: '\\';
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ export interface ResourceViewerContext extends IDisposable {
|
||||
layout?(dimension: DOM.Dimension): void;
|
||||
}
|
||||
|
||||
interface ResourceViewerDelegate {
|
||||
openInternalClb(uri: URI): void;
|
||||
openExternalClb?(uri: URI): void;
|
||||
metadataClb(meta: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to actually render the given resource into the provided container. Will adjust scrollbar (if provided) automatically based on loading
|
||||
* progress of the binary resource.
|
||||
@@ -75,9 +81,7 @@ export class ResourceViewer {
|
||||
textFileService: ITextFileService,
|
||||
container: HTMLElement,
|
||||
scrollbar: DomScrollableElement,
|
||||
openInternalClb: (uri: URI) => void,
|
||||
openExternalClb: (uri: URI) => void,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
): ResourceViewerContext {
|
||||
|
||||
// Ensure CSS class
|
||||
@@ -85,17 +89,17 @@ export class ResourceViewer {
|
||||
|
||||
// Images
|
||||
if (ResourceViewer.isImageResource(descriptor)) {
|
||||
return ImageView.create(container, descriptor, textFileService, scrollbar, openExternalClb, metadataClb);
|
||||
return ImageView.create(container, descriptor, textFileService, scrollbar, delegate);
|
||||
}
|
||||
|
||||
// Large Files
|
||||
if (descriptor.size > ResourceViewer.MAX_OPEN_INTERNAL_SIZE) {
|
||||
return FileTooLargeFileView.create(container, descriptor, scrollbar, metadataClb);
|
||||
return FileTooLargeFileView.create(container, descriptor, scrollbar, delegate);
|
||||
}
|
||||
|
||||
// Seemingly Binary Files
|
||||
else {
|
||||
return FileSeemsBinaryFileView.create(container, descriptor, scrollbar, openInternalClb, metadataClb);
|
||||
return FileSeemsBinaryFileView.create(container, descriptor, scrollbar, delegate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,14 +120,13 @@ class ImageView {
|
||||
descriptor: IResourceDescriptor,
|
||||
textFileService: ITextFileService,
|
||||
scrollbar: DomScrollableElement,
|
||||
openExternalClb: (uri: URI) => void,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
): ResourceViewerContext {
|
||||
if (ImageView.shouldShowImageInline(descriptor)) {
|
||||
return InlineImageView.create(container, descriptor, textFileService, scrollbar, metadataClb);
|
||||
return InlineImageView.create(container, descriptor, textFileService, scrollbar, delegate);
|
||||
}
|
||||
|
||||
return LargeImageView.create(container, descriptor, openExternalClb, metadataClb);
|
||||
return LargeImageView.create(container, descriptor, delegate);
|
||||
}
|
||||
|
||||
private static shouldShowImageInline(descriptor: IResourceDescriptor): boolean {
|
||||
@@ -150,11 +153,10 @@ class LargeImageView {
|
||||
static create(
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
openExternalClb: (uri: URI) => void,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
const size = BinarySize.formatSize(descriptor.size);
|
||||
metadataClb(size);
|
||||
delegate.metadataClb(size);
|
||||
|
||||
DOM.clearNode(container);
|
||||
|
||||
@@ -164,12 +166,13 @@ class LargeImageView {
|
||||
label.textContent = nls.localize('largeImageError', "The image is not displayed in the editor because it is too large ({0}).", size);
|
||||
container.appendChild(label);
|
||||
|
||||
if (descriptor.resource.scheme === Schemas.file) {
|
||||
const openExternal = delegate.openExternalClb;
|
||||
if (descriptor.resource.scheme === Schemas.file && openExternal) {
|
||||
const link = DOM.append(label, DOM.$('a.embedded-link'));
|
||||
link.setAttribute('role', 'button');
|
||||
link.textContent = nls.localize('resourceOpenExternalButton', "Open image using external program?");
|
||||
|
||||
disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternalClb(descriptor.resource)));
|
||||
disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternal(descriptor.resource)));
|
||||
}
|
||||
|
||||
return combinedDisposable(disposables);
|
||||
@@ -181,10 +184,10 @@ class FileTooLargeFileView {
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
scrollbar: DomScrollableElement,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
const size = BinarySize.formatSize(descriptor.size);
|
||||
metadataClb(size);
|
||||
delegate.metadataClb(size);
|
||||
|
||||
DOM.clearNode(container);
|
||||
|
||||
@@ -203,10 +206,9 @@ class FileSeemsBinaryFileView {
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
scrollbar: DomScrollableElement,
|
||||
openInternalClb: (uri: URI) => void,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
metadataClb(typeof descriptor.size === 'number' ? BinarySize.formatSize(descriptor.size) : '');
|
||||
delegate.metadataClb(typeof descriptor.size === 'number' ? BinarySize.formatSize(descriptor.size) : '');
|
||||
|
||||
DOM.clearNode(container);
|
||||
|
||||
@@ -221,7 +223,7 @@ class FileSeemsBinaryFileView {
|
||||
link.setAttribute('role', 'button');
|
||||
link.textContent = nls.localize('openAsText', "Do you want to open it anyway?");
|
||||
|
||||
disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openInternalClb(descriptor.resource)));
|
||||
disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => delegate.openInternalClb(descriptor.resource)));
|
||||
}
|
||||
|
||||
scrollbar.scanDomNode();
|
||||
@@ -359,7 +361,7 @@ class InlineImageView {
|
||||
descriptor: IResourceDescriptor,
|
||||
textFileService: ITextFileService,
|
||||
scrollbar: DomScrollableElement,
|
||||
metadataClb: (meta: string) => void
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
const disposables: IDisposable[] = [];
|
||||
|
||||
@@ -543,9 +545,9 @@ class InlineImageView {
|
||||
return;
|
||||
}
|
||||
if (typeof descriptor.size === 'number') {
|
||||
metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', image.naturalWidth, image.naturalHeight, BinarySize.formatSize(descriptor.size)));
|
||||
delegate.metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', image.naturalWidth, image.naturalHeight, BinarySize.formatSize(descriptor.size)));
|
||||
} else {
|
||||
metadataClb(nls.localize('imgMetaNoSize', '{0}x{1}', image.naturalWidth, image.naturalHeight));
|
||||
delegate.metadataClb(nls.localize('imgMetaNoSize', '{0}x{1}', image.naturalWidth, image.naturalHeight));
|
||||
}
|
||||
|
||||
scrollbar.scanDomNode();
|
||||
|
||||
@@ -255,7 +255,7 @@ class QuickInput implements IQuickInput {
|
||||
this.ui.leftActionBar.clear();
|
||||
const leftButtons = this.buttons.filter(button => button === backButton);
|
||||
this.ui.leftActionBar.push(leftButtons.map((button, index) => {
|
||||
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath!), true, () => {
|
||||
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
|
||||
this.onDidTriggerButtonEmitter.fire(button);
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
@@ -265,7 +265,7 @@ class QuickInput implements IQuickInput {
|
||||
this.ui.rightActionBar.clear();
|
||||
const rightButtons = this.buttons.filter(button => button !== backButton);
|
||||
this.ui.rightActionBar.push(rightButtons.map((button, index) => {
|
||||
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath!), true, () => {
|
||||
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
|
||||
this.onDidTriggerButtonEmitter.fire(button);
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
@@ -757,7 +757,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
this.showMessageDecoration(Severity.Error);
|
||||
} else {
|
||||
this.ui.message.textContent = null;
|
||||
this.showMessageDecoration(Severity.Info);
|
||||
this.showMessageDecoration(Severity.Ignore);
|
||||
}
|
||||
this.ui.customButton.label = this.customLabel;
|
||||
this.ui.customButton.element.title = this.customHover;
|
||||
@@ -888,7 +888,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
}
|
||||
if (!this.validationMessage && this.ui.message.textContent !== this.noValidationMessage) {
|
||||
this.ui.message.textContent = this.noValidationMessage;
|
||||
this.showMessageDecoration(Severity.Info);
|
||||
this.showMessageDecoration(Severity.Ignore);
|
||||
}
|
||||
if (this.validationMessage && this.ui.message.textContent !== this.validationMessage) {
|
||||
this.ui.message.textContent = this.validationMessage;
|
||||
@@ -1571,4 +1571,4 @@ export class BackAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IQuickInputService, QuickInputService, true);
|
||||
registerSingleton(IQuickInputService, QuickInputService, true);
|
||||
|
||||
@@ -11,7 +11,10 @@ import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||
const iconPathToClass = {};
|
||||
const iconClassGenerator = new IdGenerator('quick-input-button-icon-');
|
||||
|
||||
export function getIconClass(iconPath: { dark: URI; light?: URI; }) {
|
||||
export function getIconClass(iconPath: { dark: URI; light?: URI; } | undefined): string | undefined {
|
||||
if (!iconPath) {
|
||||
return undefined;
|
||||
}
|
||||
let iconClass: string;
|
||||
|
||||
const key = iconPath.dark.toString();
|
||||
|
||||
@@ -36,6 +36,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class TitlebarPart extends Part implements ITitleService {
|
||||
|
||||
@@ -179,7 +180,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
}
|
||||
|
||||
private updateRepresentedFilename(): void {
|
||||
const file = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: 'file' });
|
||||
const file = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.file });
|
||||
const path = file ? file.fsPath : '';
|
||||
|
||||
// Apply to window
|
||||
|
||||
@@ -9,7 +9,7 @@ import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -17,6 +17,9 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ICompositeControl } from 'vs/workbench/common/composite';
|
||||
import { ActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IPathData } from 'vs/platform/windows/common/windows';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null);
|
||||
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
|
||||
@@ -198,15 +201,11 @@ export interface IEditorInputFactory {
|
||||
export interface IUntitledResourceInput extends IBaseResourceInput {
|
||||
|
||||
/**
|
||||
* Optional resource. If the resource is not provided a new untitled file is created.
|
||||
* Optional resource. If the resource is not provided a new untitled file is created (e.g. Untitled-1).
|
||||
* Otherwise the untitled editor will have an associated path and use that when saving.
|
||||
*/
|
||||
resource?: URI;
|
||||
|
||||
/**
|
||||
* Optional file path. Using the file resource will associate the file to the untitled resource.
|
||||
*/
|
||||
filePath?: string;
|
||||
|
||||
/**
|
||||
* Optional language of the untitled resource.
|
||||
*/
|
||||
@@ -1089,3 +1088,37 @@ export const Extensions = {
|
||||
};
|
||||
|
||||
Registry.add(Extensions.EditorInputFactories, new EditorInputFactoryRegistry());
|
||||
|
||||
export async function pathsToEditors(paths: IPathData[] | undefined, fileService: IFileService): Promise<(IResourceInput | IUntitledResourceInput)[]> {
|
||||
if (!paths || !paths.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const editors = await Promise.all(paths.map(async path => {
|
||||
const resource = URI.revive(path.fileUri);
|
||||
if (!resource || !fileService.canHandleResource(resource)) {
|
||||
return undefined; // {{SQL CARBON EDIT}} @anthonydresser revert after strictnullchecks
|
||||
}
|
||||
|
||||
const exists = (typeof path.exists === 'boolean') ? path.exists : await fileService.exists(resource);
|
||||
|
||||
const options: ITextEditorOptions = { pinned: true };
|
||||
if (exists && typeof path.lineNumber === 'number') {
|
||||
options.selection = {
|
||||
startLineNumber: path.lineNumber,
|
||||
startColumn: path.columnNumber || 1
|
||||
};
|
||||
}
|
||||
|
||||
let input: IResourceInput | IUntitledResourceInput;
|
||||
if (!exists) {
|
||||
input = { resource, options, forceUntitled: true };
|
||||
} else {
|
||||
input = { resource, options, forceFile: true };
|
||||
}
|
||||
|
||||
return input;
|
||||
}));
|
||||
|
||||
return coalesce(editors);
|
||||
}
|
||||
|
||||
@@ -310,15 +310,15 @@ export const STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND = registerColor('statusB
|
||||
}, nls.localize('statusBarProminentItemHoverBackground', "Status bar prominent items background color when hovering. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window."));
|
||||
|
||||
export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.hostBackground', {
|
||||
dark: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
||||
light: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
||||
hc: STATUS_BAR_PROMINENT_ITEM_BACKGROUND
|
||||
dark: '#C40057',
|
||||
light: '#C40057',
|
||||
hc: '#C40057'
|
||||
}, nls.localize('statusBarItemHostBackground', "Background color for the host indicator on the status bar."));
|
||||
|
||||
export const STATUS_BAR_HOST_NAME_FOREGROUND = registerColor('statusBarItem.hostForeground', {
|
||||
dark: STATUS_BAR_PROMINENT_ITEM_FOREGROUND,
|
||||
light: STATUS_BAR_PROMINENT_ITEM_FOREGROUND,
|
||||
hc: STATUS_BAR_PROMINENT_ITEM_FOREGROUND
|
||||
dark: '#FFFFFF',
|
||||
light: '#FFFFFF',
|
||||
hc: '#FFFFFF'
|
||||
}, nls.localize('statusBarItemHostForeground', "Foreground color for the host indicator on the status bar."));
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import { IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IUntitledResourceInput } from 'vs/workbench/common/editor';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export class BackupRestorer implements IWorkbenchContribution {
|
||||
|
||||
@@ -21,7 +23,8 @@ export class BackupRestorer implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IBackupFileService private readonly backupFileService: IBackupFileService,
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this.restoreBackups();
|
||||
}
|
||||
@@ -79,9 +82,9 @@ export class BackupRestorer implements IWorkbenchContribution {
|
||||
if (resource.scheme === Schemas.untitled
|
||||
&& !BackupRestorer.UNTITLED_REGEX.test(resource.fsPath)
|
||||
&& !BackupRestorer.SQLQUERY_REGEX.test(resource.fsPath)) {
|
||||
return { filePath: resource.fsPath, options };
|
||||
return { resource: toLocalResource(resource, this.environmentService.configuration.remoteAuthority), options, forceUntitled: true };
|
||||
}
|
||||
|
||||
return { resource, options };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface IExtensionsWorkbenchService {
|
||||
_serviceBrand: any;
|
||||
onChange: Event<IExtension | undefined>;
|
||||
local: IExtension[];
|
||||
installed: IExtension[];
|
||||
outdated: IExtension[];
|
||||
queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]>;
|
||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
|
||||
@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
@@ -300,7 +300,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token)));
|
||||
this.extensionDependencies = new Cache(() => createCancelablePromise(token => this.extensionsWorkbenchService.loadDependencies(extension, token)));
|
||||
|
||||
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer);
|
||||
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer, true);
|
||||
const onError = Event.once(domEvent(this.icon, 'error'));
|
||||
onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
|
||||
this.icon.src = extension.iconUrl;
|
||||
@@ -393,6 +393,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.instantiationService.createInstance(EnableDropDownAction),
|
||||
this.instantiationService.createInstance(DisableDropDownAction, runningExtensions),
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
this.instantiationService.createInstance(LocalInstallAction),
|
||||
combinedInstallAction,
|
||||
systemDisabledWarningAction,
|
||||
this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction),
|
||||
|
||||
@@ -316,12 +316,14 @@ export class RemoteInstallAction extends ExtensionAction {
|
||||
private updateLabel(): void {
|
||||
if (this.installing) {
|
||||
this.label = RemoteInstallAction.INSTALLING_LABEL;
|
||||
this.tooltip = this.label;
|
||||
return;
|
||||
}
|
||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||
if (remoteAuthority) {
|
||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${host}`;
|
||||
this.tooltip = this.label;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -339,9 +341,9 @@ export class RemoteInstallAction extends ExtensionAction {
|
||||
// Installed User Extension
|
||||
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.configurationService))
|
||||
// Extension does not exist in remote
|
||||
&& !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
||||
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
||||
&& this.extensionsWorkbenchService.canInstall(this.extension)
|
||||
) {
|
||||
this.enabled = true;
|
||||
@@ -370,6 +372,85 @@ export class RemoteInstallAction extends ExtensionAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalInstallAction extends ExtensionAction {
|
||||
|
||||
private static INSTALL_LABEL = localize('install locally', "Install Locally");
|
||||
private static INSTALLING_LABEL = localize('installing', "Installing");
|
||||
|
||||
private static readonly Class = 'extension-action prominent install';
|
||||
private static readonly InstallingClass = 'extension-action install installing';
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
private installing: boolean = false;
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false);
|
||||
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
|
||||
this.updateLabel();
|
||||
this.update();
|
||||
}
|
||||
|
||||
private updateLabel(): void {
|
||||
if (this.installing) {
|
||||
this.label = LocalInstallAction.INSTALLING_LABEL;
|
||||
this.tooltip = this.label;
|
||||
return;
|
||||
}
|
||||
this.label = `${LocalInstallAction.INSTALL_LABEL}`;
|
||||
this.tooltip = this.label;
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = LocalInstallAction.Class;
|
||||
if (this.installing) {
|
||||
this.enabled = true;
|
||||
this.class = LocalInstallAction.InstallingClass;
|
||||
this.updateLabel();
|
||||
return;
|
||||
}
|
||||
if (this.environmentService.configuration.remoteAuthority
|
||||
// Installed User Extension
|
||||
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
|
||||
// Remote UI or Language pack Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.configurationService))
|
||||
// Extension does not exist in local
|
||||
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)
|
||||
&& this.extensionsWorkbenchService.canInstall(this.extension)
|
||||
) {
|
||||
this.enabled = true;
|
||||
this.updateLabel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (!this.installing) {
|
||||
this.installing = true;
|
||||
this.update();
|
||||
this.extensionsWorkbenchService.open(this.extension);
|
||||
alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
|
||||
if (this.extension.gallery) {
|
||||
await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery);
|
||||
this.installing = false;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class UninstallAction extends ExtensionAction {
|
||||
|
||||
private static readonly UninstallLabel = localize('uninstallAction', "Uninstall");
|
||||
@@ -1265,23 +1346,34 @@ export class ReloadAction extends ExtensionAction {
|
||||
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
return;
|
||||
}
|
||||
if (this.workbenchEnvironmentService.configuration.remoteAuthority
|
||||
if (this.workbenchEnvironmentService.configuration.remoteAuthority) {
|
||||
const uiExtension = isUIExtension(this.extension.local.manifest, this.configurationService);
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
) {
|
||||
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
|
||||
// Extension exist in remote and enabled
|
||||
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
|
||||
return;
|
||||
if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
|
||||
// Extension exist in remote and enabled
|
||||
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Remote UI Extension
|
||||
if (uiExtension && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)[0];
|
||||
// Extension exist in local and enabled
|
||||
if (localExtension && localExtension.local && this.extensionEnablementService.isEnabled(localExtension.local)) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2464,7 +2556,8 @@ export class StatusLabelAction extends Action implements IExtensionContainer {
|
||||
}
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly extensionService: IExtensionService
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
super('extensions.action.statusLabel', '', StatusLabelAction.DISABLED_CLASS, false);
|
||||
}
|
||||
@@ -2503,7 +2596,7 @@ export class StatusLabelAction extends Action implements IExtensionContainer {
|
||||
};
|
||||
const canRemoveExtension = () => {
|
||||
if (this.extension.local) {
|
||||
if (runningExtensions.every(e => !areSameExtensions({ id: e.identifier.value }, this.extension.identifier))) {
|
||||
if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value }, this.extension.identifier) && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) {
|
||||
return true;
|
||||
}
|
||||
return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension.local));
|
||||
@@ -2592,21 +2685,18 @@ export class DisabledLabelAction extends ExtensionAction {
|
||||
update(): void {
|
||||
this.class = `${DisabledLabelAction.Class} hide`;
|
||||
this.label = '';
|
||||
this.enabled = false;
|
||||
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
return;
|
||||
}
|
||||
if (this.warningAction.enabled) {
|
||||
this.enabled = true;
|
||||
if (this.warningAction.tooltip) {
|
||||
this.class = DisabledLabelAction.Class;
|
||||
this.label = this.warningAction.tooltip;
|
||||
return;
|
||||
}
|
||||
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
return;
|
||||
}
|
||||
if (this.extension && this.extension.local && this._runningExtensions) {
|
||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||
const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier));
|
||||
if (!isExtensionRunning && !isEnabled) {
|
||||
this.enabled = true;
|
||||
if (!isExtensionRunning && !isEnabled && this.extensionEnablementService.canChangeEnablement(this.extension.local)) {
|
||||
this.class = DisabledLabelAction.Class;
|
||||
this.label = localize('disabled by user', "This extension is disabled by the user.");
|
||||
return;
|
||||
@@ -2626,7 +2716,9 @@ export class DisabledLabelAction extends ExtensionAction {
|
||||
|
||||
export class SystemDisabledWarningAction extends ExtensionAction {
|
||||
|
||||
private static readonly Class = 'disable-warning';
|
||||
private static readonly CLASS = 'system-disable';
|
||||
private static readonly WARNING_CLASS = `${SystemDisabledWarningAction.CLASS} warning`;
|
||||
private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} info`;
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
@@ -2640,7 +2732,7 @@ export class SystemDisabledWarningAction extends ExtensionAction {
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
) {
|
||||
super('extensions.install', '', `${SystemDisabledWarningAction.Class} hide`, false);
|
||||
super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false);
|
||||
this.labelService.onDidChangeFormatters(() => this.update(), this, this.disposables);
|
||||
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
|
||||
this.updateRunningExtensions();
|
||||
@@ -2652,44 +2744,54 @@ export class SystemDisabledWarningAction extends ExtensionAction {
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
||||
this.class = `${SystemDisabledWarningAction.CLASS} hide`;
|
||||
this.tooltip = '';
|
||||
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
if (
|
||||
!this.extension ||
|
||||
!this.extension.local ||
|
||||
!this.extension.server ||
|
||||
!this._runningExtensions ||
|
||||
!this.workbenchEnvironmentService.configuration.remoteAuthority ||
|
||||
!this.extensionManagementServerService.remoteExtensionManagementServer ||
|
||||
this.extension.state !== ExtensionState.Installed
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
|
||||
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
|
||||
const localExtensionServer = localExtension ? localExtension.server : null;
|
||||
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
if (isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) {
|
||||
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
|
||||
this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer
|
||||
? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer))
|
||||
: localize('Install language pack also locally', "Install the language pack extension locally to enable it also there.");
|
||||
}
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
|
||||
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
|
||||
const localExtensionServer = localExtension ? localExtension.server : null;
|
||||
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
|
||||
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
|
||||
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
|
||||
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
return;
|
||||
}
|
||||
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
|
||||
this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`;
|
||||
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -67,7 +67,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
const element = append(root, $('.extension'));
|
||||
const iconContainer = append(element, $('.icon-container'));
|
||||
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
|
||||
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
|
||||
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer, false);
|
||||
const details = append(element, $('.details'));
|
||||
const headerContainer = append(details, $('.header-container'));
|
||||
const header = append(headerContainer, $('.header'));
|
||||
@@ -75,7 +75,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
const version = append(header, $('span.version'));
|
||||
const installCount = append(header, $('span.install-count'));
|
||||
const ratings = append(header, $('span.ratings'));
|
||||
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header);
|
||||
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header, false);
|
||||
const description = append(details, $('.description.ellipsis'));
|
||||
const footer = append(details, $('.footer'));
|
||||
const author = append(footer, $('.author.ellipsis'));
|
||||
@@ -98,6 +98,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
reloadAction,
|
||||
this.instantiationService.createInstance(InstallAction),
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
this.instantiationService.createInstance(LocalInstallAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
|
||||
systemDisabledWarningAction,
|
||||
this.instantiationService.createInstance(ManageExtensionAction)
|
||||
|
||||
@@ -55,6 +55,9 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
@@ -91,7 +94,9 @@ const viewIdNameMappings: { [id: string]: string } = {
|
||||
export class ExtensionsViewletViewsContribution implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this.registerViews();
|
||||
}
|
||||
@@ -180,22 +185,32 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
*/
|
||||
|
||||
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
|
||||
const getViewName = (viewTitle: string, server: IExtensionManagementServer): string => {
|
||||
const serverLabel = this.workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? this.labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
|
||||
if (viewTitle && this.workbenchEnvironmentService.configuration.remoteAuthority) {
|
||||
return `${serverLabel} - ${viewTitle}`;
|
||||
}
|
||||
return viewTitle ? viewTitle : serverLabel;
|
||||
};
|
||||
const getInstalledViewName = (): string => getViewName(localize('installed', "Installed"), server);
|
||||
const getOutdatedViewName = (): string => getViewName(localize('outdated', "Outdated"), server);
|
||||
const onDidChangeServerLabel: EventOf<void> = this.workbenchEnvironmentService.configuration.remoteAuthority ? EventOf.map(this.labelService.onDidChangeFormatters, () => undefined) : EventOf.None;
|
||||
return [{
|
||||
id: `extensions.${server.authority}.installed`,
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchInstalledExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.authority}.outdated`,
|
||||
name: localize('outdated', "Outdated"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
get name() { return getOutdatedViewName(); },
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getOutdatedViewName())] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchOutdatedExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.authority}.default`,
|
||||
name: localize('installed', "Installed"),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
get name() { return getInstalledViewName(); },
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map<void, string>(onDidChangeServerLabel, () => getInstalledViewName())] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
@@ -228,7 +243,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
ctorDescriptor: { ctor: RecommendedExtensionsView },
|
||||
when: ContextKeyExpr.has('recommendedExtensions'),
|
||||
weight: 50,
|
||||
canToggleVisibility: true,
|
||||
order: 2
|
||||
};
|
||||
}
|
||||
@@ -243,7 +257,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
ctorDescriptor: { ctor: WorkspaceRecommendedExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('recommendedExtensions'), ContextKeyExpr.has('nonEmptyWorkspace')),
|
||||
weight: 50,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
@@ -256,7 +269,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
ctorDescriptor: { ctor: EnabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchEnabledExtensions')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
@@ -269,7 +281,6 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
ctorDescriptor: { ctor: DisabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchDisabledExtensions')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
collapsed: true
|
||||
};
|
||||
@@ -282,8 +293,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: BuiltInExtensionsView },
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100,
|
||||
canToggleVisibility: true
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
|
||||
@@ -294,8 +304,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: BuiltInThemesExtensionsView },
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100,
|
||||
canToggleVisibility: true
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
|
||||
@@ -306,8 +315,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: BuiltInBasicsExtensionsView },
|
||||
when: ContextKeyExpr.has('searchBuiltInExtensions'),
|
||||
weight: 100,
|
||||
canToggleVisibility: true
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { append, $, toggleClass } from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/electron-browser/extensionsList';
|
||||
import { IExtension, IExtensionsWorkbenchService } from '../common/extensions';
|
||||
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
|
||||
import { Query } from '../common/extensionQuery';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -45,9 +45,7 @@ import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePa
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
|
||||
|
||||
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
|
||||
|
||||
@@ -97,7 +95,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
|
||||
@IExperimentService private readonly experimentService: IExperimentService,
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
|
||||
this.server = options.server;
|
||||
@@ -340,11 +338,20 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
const isE1Running = running1 && this.extensionManagementServerService.getExtensionManagementServer(running1.extensionLocation) === e1.server;
|
||||
const running2 = runningExtensionsById.get(ExtensionIdentifier.toKey(e2.identifier.id));
|
||||
const isE2Running = running2 && this.extensionManagementServerService.getExtensionManagementServer(running2.extensionLocation) === e2.server;
|
||||
if ((isE1Running && isE2Running) || (!isE1Running && !isE2Running)) {
|
||||
if ((isE1Running && isE2Running)) {
|
||||
return e1.displayName.localeCompare(e2.displayName);
|
||||
}
|
||||
const isE1LanguagePackExtension = e1.local && isLanguagePackExtension(e1.local.manifest);
|
||||
const isE2LanguagePackExtension = e2.local && isLanguagePackExtension(e2.local.manifest);
|
||||
if (!isE1Running && !isE2Running) {
|
||||
if (isE1LanguagePackExtension) {
|
||||
return -1;
|
||||
}
|
||||
if (isE2LanguagePackExtension) {
|
||||
return 1;
|
||||
}
|
||||
return e1.displayName.localeCompare(e2.displayName);
|
||||
}
|
||||
if ((isE1Running && isE2LanguagePackExtension) || (isE2Running && isE1LanguagePackExtension)) {
|
||||
return e1.displayName.localeCompare(e2.displayName);
|
||||
}
|
||||
@@ -865,18 +872,11 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
}
|
||||
|
||||
function getViewTitleForServer(viewTitle: string, server: IExtensionManagementServer, labelService: ILabelService, workbenchEnvironmentService: IWorkbenchEnvironmentService): string {
|
||||
const serverLabel = workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
|
||||
if (viewTitle && workbenchEnvironmentService.configuration.remoteAuthority) {
|
||||
return `${serverLabel} - ${viewTitle}`;
|
||||
}
|
||||
return viewTitle ? viewTitle : serverLabel;
|
||||
}
|
||||
|
||||
export class ServerExtensionsView extends ExtensionsListView {
|
||||
|
||||
constructor(
|
||||
server: IExtensionManagementServer,
|
||||
onDidChangeTitle: Event<string>,
|
||||
options: ExtensionsListViewOptions,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@@ -893,15 +893,11 @@ export class ServerExtensionsView extends ExtensionsListView {
|
||||
@IExperimentService experimentService: IExperimentService,
|
||||
@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
const viewTitle = options.title;
|
||||
options.title = getViewTitleForServer(viewTitle, server, labelService, workbenchEnvironmentService);
|
||||
options.server = server;
|
||||
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, modeService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService);
|
||||
this.disposables.push(labelService.onDidChangeFormatters(() => this.updateTitle(getViewTitleForServer(viewTitle, server, labelService, workbenchEnvironmentService))));
|
||||
this.disposables.push(onDidChangeTitle(title => this.updateTitle(title)));
|
||||
}
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
@@ -1044,6 +1040,12 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
|
||||
|
||||
private getRecommendationsToInstall(): Promise<IExtensionRecommendation[]> {
|
||||
return this.tipsService.getWorkspaceRecommendations()
|
||||
.then(recommendations => recommendations.filter(({ extensionId }) => !this.extensionsWorkbenchService.local.some(i => areSameExtensions({ id: extensionId }, i.identifier))));
|
||||
.then(recommendations => recommendations.filter(({ extensionId }) => {
|
||||
const extension = this.extensionsWorkbenchService.local.filter(i => areSameExtensions({ id: extensionId }, i.identifier))[0];
|
||||
if (!extension || !extension.local || extension.state !== ExtensionState.Installed) {
|
||||
return true;
|
||||
}
|
||||
return isUIExtension(extension.local.manifest, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/extensionsWidgets';
|
||||
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from '../common/extensions';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions';
|
||||
import { append, $, addClass } from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -148,34 +148,46 @@ export class TooltipWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
private readonly parent: HTMLElement,
|
||||
private readonly extensionLabelAction: DisabledLabelAction,
|
||||
private readonly disabledLabelAction: DisabledLabelAction,
|
||||
private readonly recommendationWidget: RecommendationWidget,
|
||||
private readonly reloadAction: ReloadAction
|
||||
private readonly reloadAction: ReloadAction,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super();
|
||||
this._register(Event.any<any>(
|
||||
this.extensionLabelAction.onDidChange,
|
||||
this.disabledLabelAction.onDidChange,
|
||||
this.reloadAction.onDidChange,
|
||||
this.recommendationWidget.onDidChangeTooltip
|
||||
this.recommendationWidget.onDidChangeTooltip,
|
||||
this.labelService.onDidChangeFormatters
|
||||
)(() => this.render()));
|
||||
}
|
||||
|
||||
render(): void {
|
||||
this.parent.title = '';
|
||||
this.parent.removeAttribute('aria-label');
|
||||
this.parent.title = this.getTooltip();
|
||||
if (this.extension) {
|
||||
const title = this.getTitle();
|
||||
this.parent.title = title;
|
||||
this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. {1} Press enter for extension details.", this.extension.displayName));
|
||||
}
|
||||
}
|
||||
|
||||
private getTitle(): string {
|
||||
private getTooltip(): string {
|
||||
if (!this.extension) {
|
||||
return '';
|
||||
}
|
||||
if (this.reloadAction.enabled) {
|
||||
return this.reloadAction.tooltip;
|
||||
}
|
||||
if (this.extensionLabelAction.enabled) {
|
||||
return this.extensionLabelAction.label;
|
||||
if (this.disabledLabelAction.label) {
|
||||
return this.disabledLabelAction.label;
|
||||
}
|
||||
if (this.extension.local && this.extension.state === ExtensionState.Installed) {
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority));
|
||||
}
|
||||
return localize('extension enabled locally', "Extension is enabled locally.");
|
||||
}
|
||||
return this.recommendationWidget.tooltip;
|
||||
}
|
||||
@@ -252,6 +264,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
private readonly tooltip: boolean,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
@@ -276,7 +289,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
return;
|
||||
}
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge);
|
||||
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
|
||||
append(this.element, this.remoteBadge.element);
|
||||
}
|
||||
}
|
||||
@@ -294,6 +307,7 @@ class RemoteBadge extends Disposable {
|
||||
readonly element: HTMLElement;
|
||||
|
||||
constructor(
|
||||
private readonly tooltip: boolean,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@@ -320,12 +334,14 @@ class RemoteBadge extends Disposable {
|
||||
this._register(this.themeService.onThemeChange(() => applyBadgeStyle()));
|
||||
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => applyBadgeStyle()));
|
||||
|
||||
const updateTitle = () => {
|
||||
if (this.element) {
|
||||
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
|
||||
}
|
||||
};
|
||||
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
|
||||
updateTitle();
|
||||
if (this.tooltip) {
|
||||
const updateTitle = () => {
|
||||
if (this.element) {
|
||||
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
|
||||
}
|
||||
};
|
||||
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
|
||||
updateTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
padding: 0 5px;
|
||||
outline-offset: 2px;
|
||||
line-height: initial;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .action-label.clear-extensions {
|
||||
@@ -35,7 +38,7 @@
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action.extension-editor-dropdown-action,
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action.reload,
|
||||
.monaco-action-bar .action-item.disabled .action-label.disable-status.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.disable-warning.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.system-disable.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-status-label.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.malicious-status.not-malicious {
|
||||
display: none;
|
||||
@@ -67,24 +70,33 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.disable-warning,
|
||||
.extensions-viewlet>.extensions .extension>.details>.footer>.monaco-action-bar .action-item .action-label.disable-warning {
|
||||
cursor: default;
|
||||
margin: 0.1em;
|
||||
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.system-disable,
|
||||
.extensions-viewlet>.extensions .extension>.details>.footer>.monaco-action-bar .action-item .action-label.system-disable {
|
||||
margin: 0.15em;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .action-label.disable-warning.icon {
|
||||
.monaco-action-bar .action-item .action-label.system-disable.icon {
|
||||
opacity: 1;
|
||||
height: 18px;
|
||||
width: 10px;
|
||||
background: url('status-warning.svg') center center no-repeat;
|
||||
margin-top: 0.15em
|
||||
}
|
||||
|
||||
.vs-dark .monaco-action-bar .action-item .action-label.disable-warning.icon {
|
||||
.monaco-action-bar .action-item .action-label.system-disable.warning.icon {
|
||||
background: url('status-warning.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.warning.icon {
|
||||
background: url('status-warning-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .action-label.system-disable.info.icon {
|
||||
background: url('status-info.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.info.icon {
|
||||
background: url('status-info-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.extension-status-label,
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.disable-status,
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status {
|
||||
|
||||
@@ -41,11 +41,13 @@
|
||||
line-height: 38px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .icon-container .extension-remote-badge .octicon {
|
||||
font-size: 32px;
|
||||
vertical-align: middle;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details {
|
||||
@@ -145,6 +147,9 @@
|
||||
padding: 1px 6px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .extension-action {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .subtext-container {
|
||||
display: block;
|
||||
|
||||
@@ -113,6 +113,10 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container .extension-remote-badge > .octicon {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header > .extension-remote-badge-container {
|
||||
margin-left: 6px;
|
||||
}
|
||||
@@ -123,11 +127,13 @@
|
||||
line-height: 14px;
|
||||
border-radius: 20px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .octicon {
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.extensions-viewlet.narrow > .extensions .extension > .icon-container,
|
||||
@@ -224,6 +230,14 @@
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar > .actions-container .extension-action {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.extensions-viewlet.narrow > .extensions .extension > .details > .footer > .monaco-action-bar > .actions-container .extension-action {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-label {
|
||||
margin-top: 0.3em;
|
||||
margin-left: 0.3em;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#1E1E1E"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#252526"/></svg>
|
||||
|
After Width: | Height: | Size: 356 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#F6F6F6"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 353 B |
@@ -379,12 +379,12 @@ export class RuntimeExtensionsEditor extends BaseEditor {
|
||||
|
||||
if (element.description.extensionLocation.scheme !== 'file') {
|
||||
const el = $('span');
|
||||
el.innerHTML = renderOcticons(`$(rss) ${element.description.extensionLocation.authority}`);
|
||||
el.innerHTML = renderOcticons(`$(remote) ${element.description.extensionLocation.authority}`);
|
||||
data.msgContainer.appendChild(el);
|
||||
|
||||
const hostLabel = this._labelService.getHostLabel(REMOTE_HOST_SCHEME, this._environmentService.configuration.remoteAuthority);
|
||||
if (hostLabel) {
|
||||
el.innerHTML = renderOcticons(`$(rss) ${hostLabel}`);
|
||||
el.innerHTML = renderOcticons(`$(remote) ${hostLabel}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import * as resources from 'vs/base/common/resources';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
|
||||
@@ -605,15 +605,19 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
get local(): IExtension[] {
|
||||
const result = [...this.localExtensions.local];
|
||||
if (!this.remoteExtensions) {
|
||||
return result;
|
||||
}
|
||||
result.push(...this.remoteExtensions.local);
|
||||
const result = [...this.installed];
|
||||
const byId = groupByExtension(result, r => r.identifier);
|
||||
return byId.reduce((result, extensions) => { result.push(this.getPrimaryExtension(extensions)); return result; }, []);
|
||||
}
|
||||
|
||||
get installed(): IExtension[] {
|
||||
const result = [...this.localExtensions.local];
|
||||
if (this.remoteExtensions) {
|
||||
result.push(...this.remoteExtensions.local);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
get outdated(): IExtension[] {
|
||||
const allLocal = [...this.localExtensions.local];
|
||||
if (this.remoteExtensions) {
|
||||
@@ -855,7 +859,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
return this.installWithProgress(async () => {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// {{SQL CARBON EDIT}} remove extensionservice install from gallery
|
||||
if (extensionPolicy === ExtensionsPolicy.allowMicrosoft) {
|
||||
if (extension.publisherDisplayName === 'Microsoft') {
|
||||
await this.downloadOrBrowse(extension).then(() => this.checkAndEnableDisabledDependencies(gallery.identifier));
|
||||
@@ -916,7 +920,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' with version '{1}' as it is not compatible with Azure Data Studio.", extension.gallery!.identifier.id, version)));
|
||||
}
|
||||
return this.installWithProgress(async () => {
|
||||
await this.extensionService.installFromGallery(gallery);
|
||||
const extensionService = extension.server && extension.local && !isLanguagePackExtension(extension.local.manifest) ? extension.server.extensionManagementService : this.extensionService;
|
||||
await extensionService.installFromGallery(gallery);
|
||||
if (extension.latestVersion !== version) {
|
||||
this.ignoreAutoUpdate(new ExtensionIdentifierWithVersion(gallery.identifier, version));
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
/**
|
||||
* An implementation of editor for binary files like images.
|
||||
@@ -29,7 +30,8 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ITextFileService textFileService: ITextFileService
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
) {
|
||||
super(
|
||||
BinaryFileEditor.ID,
|
||||
@@ -40,7 +42,8 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
||||
telemetryService,
|
||||
themeService,
|
||||
textFileService,
|
||||
storageService
|
||||
environmentService,
|
||||
storageService,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerService';
|
||||
import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
// Viewlet Action
|
||||
export class OpenExplorerViewletAction extends ShowViewletAction {
|
||||
@@ -59,7 +60,7 @@ class FileUriLabelContribution implements IWorkbenchContribution {
|
||||
|
||||
constructor(@ILabelService labelService: ILabelService) {
|
||||
labelService.registerFormatter({
|
||||
scheme: 'file',
|
||||
scheme: Schemas.file,
|
||||
formatting: {
|
||||
label: '${authority}${path}',
|
||||
separator: sep,
|
||||
@@ -307,6 +308,7 @@ configurationRegistry.registerConfiguration({
|
||||
},
|
||||
'files.hotExit': {
|
||||
'type': 'string',
|
||||
'scope': ConfigurationScope.APPLICATION,
|
||||
'enum': [HotExitConfiguration.OFF, HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE],
|
||||
'default': HotExitConfiguration.ON_EXIT,
|
||||
'markdownEnumDescriptions': [
|
||||
|
||||
@@ -136,14 +136,15 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
|
||||
const isReadonly = fileOperationError.fileOperationResult === FileOperationResult.FILE_READ_ONLY;
|
||||
const triedToMakeWriteable = isReadonly && fileOperationError.options && (fileOperationError.options as IWriteTextFileOptions).overwriteReadonly;
|
||||
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
|
||||
const canHandlePermissionOrReadonlyErrors = resource.scheme === Schemas.file; // https://github.com/Microsoft/vscode/issues/48659
|
||||
|
||||
// Save Elevated (cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
|
||||
if (resource.scheme === Schemas.file && (isPermissionDenied || triedToMakeWriteable)) {
|
||||
// Save Elevated
|
||||
if (canHandlePermissionOrReadonlyErrors && (isPermissionDenied || triedToMakeWriteable)) {
|
||||
actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable));
|
||||
}
|
||||
|
||||
// Overwrite (cannot overwrite readonly https://github.com/Microsoft/vscode/issues/48659)
|
||||
else if (resource.scheme === Schemas.file && isReadonly) {
|
||||
// Overwrite
|
||||
else if (canHandlePermissionOrReadonlyErrors && isReadonly) {
|
||||
actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model));
|
||||
}
|
||||
|
||||
@@ -158,13 +159,14 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
|
||||
// Discard
|
||||
actions.primary!.push(this.instantiationService.createInstance(ExecuteCommandAction, REVERT_FILE_COMMAND_ID, nls.localize('discard', "Discard")));
|
||||
|
||||
if (isReadonly) {
|
||||
// Message
|
||||
if (canHandlePermissionOrReadonlyErrors && isReadonly) {
|
||||
if (triedToMakeWriteable) {
|
||||
message = isWindows ? nls.localize('readonlySaveErrorAdmin', "Failed to save '{0}': File is read-only. Select 'Overwrite as Admin' to retry as administrator.", basename(resource)) : nls.localize('readonlySaveErrorSudo', "Failed to save '{0}': File is read-only. Select 'Overwrite as Sudo' to retry as superuser.", basename(resource));
|
||||
} else {
|
||||
message = nls.localize('readonlySaveError', "Failed to save '{0}': File is read-only. Select 'Overwrite' to attempt to make it writeable.", basename(resource));
|
||||
}
|
||||
} else if (isPermissionDenied) {
|
||||
} else if (canHandlePermissionOrReadonlyErrors && isPermissionDenied) {
|
||||
message = isWindows ? nls.localize('permissionDeniedSaveError', "Failed to save '{0}': Insufficient permissions. Select 'Retry as Admin' to retry as administrator.", basename(resource)) : nls.localize('permissionDeniedSaveErrorSudo', "Failed to save '{0}': Insufficient permissions. Select 'Retry as Sudo' to retry as superuser.", basename(resource));
|
||||
} else {
|
||||
message = nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(resource), toErrorMessage(error, false));
|
||||
@@ -246,7 +248,7 @@ class ResolveSaveConflictAction extends Action {
|
||||
|
||||
return this.editorService.openEditor(
|
||||
{
|
||||
leftResource: URI.from({ scheme: CONFLICT_RESOLUTION_SCHEME, path: resource.fsPath }),
|
||||
leftResource: resource.with({ scheme: CONFLICT_RESOLUTION_SCHEME }),
|
||||
rightResource: resource,
|
||||
label: editorLabel,
|
||||
options: { pinned: true }
|
||||
|
||||
@@ -50,7 +50,7 @@ registerEditorAction(class FormatDocumentMultipleAction extends EditorAction {
|
||||
return commandService.executeCommand('editor.action.formatDocument');
|
||||
} else {
|
||||
const langName = model.getLanguageIdentifier().language;
|
||||
const message = nls.localize('no.rovider', "There is no formatter for '{0}'-files installed.", langName);
|
||||
const message = nls.localize('no.provider', "There is no formatter for '{0}'-files installed.", langName);
|
||||
const choice = {
|
||||
label: nls.localize('install.formatter', "Install Formatter..."),
|
||||
run: () => showExtensionQuery(viewletService, `category:formatters ${langName}`)
|
||||
|
||||
@@ -159,6 +159,11 @@ export const tocData: ITOCEntry = {
|
||||
id: 'features/comments',
|
||||
label: localize('comments', "Comments"),
|
||||
settings: ['comments.*']
|
||||
},
|
||||
{
|
||||
id: 'features/remote',
|
||||
label: localize('remote', "Remote"),
|
||||
settings: ['remote.*']
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -418,14 +418,14 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
|
||||
.then(() => {
|
||||
const remoteAuthority = environmentService.configuration.remoteAuthority;
|
||||
const hostLabel = labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority) || remoteAuthority;
|
||||
const label = nls.localize('openRemoteSettings', "Open User Settings ({0})", hostLabel);
|
||||
const label = nls.localize('openRemoteSettings', "Open Remote Settings ({0})", hostLabel);
|
||||
CommandsRegistry.registerCommand(OpenRemoteSettingsAction.ID, serviceAccessor => {
|
||||
serviceAccessor.get(IInstantiationService).createInstance(OpenRemoteSettingsAction, OpenRemoteSettingsAction.ID, label).run();
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: OpenRemoteSettingsAction.ID,
|
||||
title: { value: label, original: `Preferences: Open User Settings (${hostLabel})` },
|
||||
title: { value: label, original: `Preferences: Open Remote Settings (${hostLabel})` },
|
||||
category: nls.localize('preferencesCategory', "Preferences")
|
||||
},
|
||||
when: RemoteAuthorityContext.notEqualsTo('')
|
||||
|
||||
@@ -205,7 +205,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
setInput(input: SettingsEditor2Input, options: SettingsEditorOptions, token: CancellationToken): Promise<void> {
|
||||
setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | null, token: CancellationToken): Promise<void> {
|
||||
this.inSettingsEditorContextKey.set(true);
|
||||
return super.setInput(input, options, token)
|
||||
.then(() => new Promise(process.nextTick)) // Force setInput to be async
|
||||
@@ -213,10 +213,10 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
return this.render(token);
|
||||
})
|
||||
.then(() => {
|
||||
options = options || SettingsEditorOptions.create({});
|
||||
|
||||
if (!this.viewState.settingsTarget) {
|
||||
if (!options) {
|
||||
options = SettingsEditorOptions.create({ target: ConfigurationTarget.USER_LOCAL });
|
||||
} else if (!options.target) {
|
||||
if (!options.target) {
|
||||
options.target = ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.searchInProgress = null;
|
||||
}
|
||||
|
||||
this.viewState.filterToCategory = undefined;
|
||||
this.tocTree.setFocus([]);
|
||||
this.tocTreeModel.currentSearchModel = this.searchResultModel;
|
||||
this.onSearchModeToggled();
|
||||
|
||||
@@ -1206,8 +1206,7 @@ export class SettingsEditor2 extends BaseEditor {
|
||||
this.tocTreeModel.update();
|
||||
}
|
||||
|
||||
this.tocTree.setSelection([]);
|
||||
this.viewState.filterToCategory = undefined;
|
||||
this.tocTree.setFocus([]);
|
||||
this.tocTree.expandAll();
|
||||
|
||||
this.renderTree(undefined, true);
|
||||
|
||||
@@ -26,12 +26,12 @@ const id = 'workbench.action.openSnippets';
|
||||
|
||||
namespace ISnippetPick {
|
||||
export function is(thing: object): thing is ISnippetPick {
|
||||
return thing && typeof (<ISnippetPick>thing).filepath === 'string';
|
||||
return thing && URI.isUri((<ISnippetPick>thing).filepath);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISnippetPick extends IQuickPickItem {
|
||||
filepath: string;
|
||||
filepath: URI;
|
||||
hint?: true;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
|
||||
|
||||
existing.push({
|
||||
label: basename(file.location.fsPath),
|
||||
filepath: file.location.fsPath,
|
||||
filepath: file.location,
|
||||
description: names.size === 0
|
||||
? nls.localize('global.scope', "(global)")
|
||||
: nls.localize('global.1', "({0})", values(names).join(', '))
|
||||
@@ -83,7 +83,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
|
||||
existing.push({
|
||||
label: basename(file.location.fsPath),
|
||||
description: `(${modeService.getLanguageName(mode)})`,
|
||||
filepath: file.location.fsPath
|
||||
filepath: file.location
|
||||
});
|
||||
seen.add(mode);
|
||||
}
|
||||
@@ -96,15 +96,15 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir
|
||||
future.push({
|
||||
label: mode,
|
||||
description: `(${label})`,
|
||||
filepath: join(dir, `${mode}.json`),
|
||||
filepath: URI.file(join(dir, `${mode}.json`)),
|
||||
hint: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
existing.sort((a, b) => {
|
||||
let a_ext = extname(a.filepath);
|
||||
let b_ext = extname(b.filepath);
|
||||
let a_ext = extname(a.filepath.path);
|
||||
let b_ext = extname(b.filepath.path);
|
||||
if (a_ext === b_ext) {
|
||||
return a.label.localeCompare(b.label);
|
||||
} else if (a_ext === '.code-snippets') {
|
||||
@@ -165,7 +165,7 @@ async function createSnippetFile(scope: string, defaultPath: URI, windowService:
|
||||
}
|
||||
|
||||
async function createLanguageSnippetFile(pick: ISnippetPick, fileService: IFileService, textFileService: ITextFileService) {
|
||||
if (await fileService.exists(URI.file(pick.filepath))) {
|
||||
if (await fileService.exists(pick.filepath)) {
|
||||
return;
|
||||
}
|
||||
const contents = [
|
||||
@@ -185,7 +185,7 @@ async function createLanguageSnippetFile(pick: ISnippetPick, fileService: IFileS
|
||||
'\t// }',
|
||||
'}'
|
||||
].join('\n');
|
||||
await textFileService.write(URI.file(pick.filepath), contents);
|
||||
await textFileService.write(pick.filepath, contents);
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
|
||||
@@ -240,7 +240,7 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise<any> => {
|
||||
if (pick.hint) {
|
||||
await createLanguageSnippetFile(pick, fileService, textFileService);
|
||||
}
|
||||
return opener.open(URI.file(pick.filepath));
|
||||
return opener.open(pick.filepath);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -246,8 +246,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"WorkspaceTags" : {
|
||||
"workbench.filesToOpen" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
@@ -352,9 +351,8 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
|
||||
tags['workspace.id'] = workspaceId;
|
||||
|
||||
const { filesToOpen, filesToCreate, filesToDiff } = configuration;
|
||||
tags['workbench.filesToOpen'] = filesToOpen && filesToOpen.length || 0;
|
||||
tags['workbench.filesToCreate'] = filesToCreate && filesToCreate.length || 0;
|
||||
const { filesToOpenOrCreate, filesToDiff } = configuration;
|
||||
tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
|
||||
tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0;
|
||||
|
||||
const isEmpty = state === WorkbenchState.EMPTY;
|
||||
@@ -586,11 +584,9 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
return folder && [folder];
|
||||
}
|
||||
|
||||
private findFolder({ filesToOpen, filesToCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
|
||||
if (filesToOpen && filesToOpen.length) {
|
||||
return this.parentURI(filesToOpen[0].fileUri);
|
||||
} else if (filesToCreate && filesToCreate.length) {
|
||||
return this.parentURI(filesToCreate[0].fileUri);
|
||||
private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
|
||||
if (filesToOpenOrCreate && filesToOpenOrCreate.length) {
|
||||
return this.parentURI(filesToOpenOrCreate[0].fileUri);
|
||||
} else if (filesToDiff && filesToDiff.length) {
|
||||
return this.parentURI(filesToDiff[0].fileUri);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
) {
|
||||
super();
|
||||
|
||||
const { filesToOpen, filesToCreate, filesToDiff } = environmentService.configuration;
|
||||
const { filesToOpenOrCreate, filesToDiff } = environmentService.configuration;
|
||||
const activeViewlet = viewletService.getActiveViewlet();
|
||||
|
||||
/* __GDPR__
|
||||
@@ -47,8 +47,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
"windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToOpenOrCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
@@ -64,8 +63,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
userAgent: navigator.userAgent,
|
||||
windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
|
||||
emptyWorkbench: contextService.getWorkbenchState() === WorkbenchState.EMPTY,
|
||||
'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0,
|
||||
'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0,
|
||||
'workbench.filesToOpenOrCreate': filesToOpenOrCreate && filesToOpenOrCreate.length || 0,
|
||||
'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0,
|
||||
customKeybindingsCount: keybindingsService.customKeybindingsCount(),
|
||||
theme: themeService.getColorTheme().id,
|
||||
|
||||
@@ -339,7 +339,7 @@ export class CreateNewTerminalAction extends Action {
|
||||
// Don't create the instance if the workspace picker was canceled
|
||||
return null;
|
||||
}
|
||||
return this.terminalService.createTerminal({ cwd: workspace.uri.fsPath }, true);
|
||||
return this.terminalService.createTerminal({ cwd: workspace.uri }, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
@@ -131,7 +131,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
});
|
||||
}
|
||||
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
|
||||
} else {
|
||||
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
||||
|
||||
@@ -34,24 +34,26 @@ export function registerFileProtocol(
|
||||
getRoots: () => ReadonlyArray<URI>
|
||||
) {
|
||||
contents.session.protocol.registerBufferProtocol(protocol, (request, callback: any) => {
|
||||
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
|
||||
const requestUri = URI.parse(request.url);
|
||||
const redirectedUri = URI.from({
|
||||
scheme: REMOTE_HOST_SCHEME,
|
||||
authority: extensionLocation.authority,
|
||||
path: '/vscode-resource',
|
||||
query: JSON.stringify({
|
||||
requestResourcePath: requestUri.path
|
||||
})
|
||||
});
|
||||
resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback);
|
||||
return;
|
||||
}
|
||||
|
||||
const requestPath = URI.parse(request.url).path;
|
||||
const normalizedPath = URI.file(requestPath);
|
||||
for (const root of getRoots()) {
|
||||
if (startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
|
||||
if (!startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
|
||||
const requestUri = URI.parse(request.url);
|
||||
const redirectedUri = URI.from({
|
||||
scheme: REMOTE_HOST_SCHEME,
|
||||
authority: extensionLocation.authority,
|
||||
path: '/vscode-resource',
|
||||
query: JSON.stringify({
|
||||
requestResourcePath: requestUri.path
|
||||
})
|
||||
});
|
||||
resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback);
|
||||
return;
|
||||
} else {
|
||||
resolveContent(textFileService, normalizedPath, getMimeType(normalizedPath), callback);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -652,6 +652,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/electron-brow
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': nls.localize('autoDetectHighContrast', "If enabled, will automatically change to high contrast theme if Windows is using a high contrast theme, and to dark theme when switching away from a Windows high contrast theme."),
|
||||
'scope': ConfigurationScope.APPLICATION,
|
||||
'included': isWindows
|
||||
},
|
||||
'window.doubleClickIconToClose': {
|
||||
@@ -678,6 +679,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/electron-brow
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': nls.localize('window.nativeFullScreen', "Controls if native full-screen should be used on macOS. Disable this option to prevent macOS from creating a new space when going full-screen."),
|
||||
'scope': ConfigurationScope.APPLICATION,
|
||||
'included': isMacintosh
|
||||
},
|
||||
'window.clickThroughInactive': {
|
||||
|
||||
@@ -91,7 +91,7 @@ class CodeRendererMain extends Disposable {
|
||||
|
||||
const filesToWait = this.configuration.filesToWait;
|
||||
const filesToWaitPaths = filesToWait && filesToWait.paths;
|
||||
[filesToWaitPaths, this.configuration.filesToOpen, this.configuration.filesToCreate, this.configuration.filesToDiff].forEach(paths => {
|
||||
[filesToWaitPaths, this.configuration.filesToOpenOrCreate, this.configuration.filesToDiff].forEach(paths => {
|
||||
if (Array.isArray(paths)) {
|
||||
paths.forEach(path => {
|
||||
if (path.fileUri) {
|
||||
|
||||
@@ -11,10 +11,10 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { toResource, IUntitledResourceInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { toResource, IUntitledResourceInput, SideBySideEditor, pathsToEditors } from 'vs/workbench/common/editor';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWindowsService, IWindowService, IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IPathData, IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowsService, IWindowService, IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
|
||||
import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
@@ -468,20 +468,16 @@ export class ElectronWindow extends Disposable {
|
||||
this.workspaceEditingService.addFolders(foldersToAdd);
|
||||
}
|
||||
|
||||
private onOpenFiles(request: IOpenFileRequest): void {
|
||||
private async onOpenFiles(request: IOpenFileRequest): Promise<void> {
|
||||
const inputs: IResourceEditor[] = [];
|
||||
const diffMode = !!(request.filesToDiff && (request.filesToDiff.length === 2));
|
||||
|
||||
if (!diffMode && request.filesToOpen) {
|
||||
inputs.push(...this.toInputs(request.filesToOpen, false));
|
||||
}
|
||||
|
||||
if (!diffMode && request.filesToCreate) {
|
||||
inputs.push(...this.toInputs(request.filesToCreate, true));
|
||||
if (!diffMode && request.filesToOpenOrCreate) {
|
||||
inputs.push(...(await pathsToEditors(request.filesToOpenOrCreate, this.fileService)));
|
||||
}
|
||||
|
||||
if (diffMode && request.filesToDiff) {
|
||||
inputs.push(...this.toInputs(request.filesToDiff, false));
|
||||
inputs.push(...(await pathsToEditors(request.filesToDiff, this.fileService)));
|
||||
}
|
||||
|
||||
if (inputs.length) {
|
||||
@@ -521,27 +517,6 @@ export class ElectronWindow extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private toInputs(paths: IPathData[], isNew: boolean): IResourceEditor[] {
|
||||
return paths.map(p => {
|
||||
const resource = URI.revive(p.fileUri);
|
||||
let input: IResourceInput | IUntitledResourceInput;
|
||||
if (isNew) {
|
||||
input = { filePath: resource!.fsPath, options: { pinned: true } };
|
||||
} else {
|
||||
input = { resource, options: { pinned: true } };
|
||||
}
|
||||
|
||||
if (!isNew && typeof p.lineNumber === 'number' && typeof p.columnNumber === 'number') {
|
||||
input.options!.selection = {
|
||||
startLineNumber: p.lineNumber,
|
||||
startColumn: p.columnNumber
|
||||
};
|
||||
}
|
||||
|
||||
return input;
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.touchBarDisposables = dispose(this.touchBarDisposables);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ interface FileQuickPickItem extends IQuickPickItem {
|
||||
|
||||
enum UpdateResult {
|
||||
Updated,
|
||||
Updating,
|
||||
NotUpdated,
|
||||
InvalidPath
|
||||
}
|
||||
@@ -51,6 +52,7 @@ export class RemoteFileDialog {
|
||||
private allowFolderSelection: boolean;
|
||||
private remoteAuthority: string | undefined;
|
||||
private requiresTrailing: boolean;
|
||||
private trailing: string | undefined;
|
||||
private scheme: string = REMOTE_HOST_SCHEME;
|
||||
private contextKey: IContextKey<boolean>;
|
||||
private userEnteredPathSegment: string;
|
||||
@@ -149,7 +151,6 @@ export class RemoteFileDialog {
|
||||
this.allowFileSelection = !!this.options.canSelectFiles;
|
||||
this.hidden = false;
|
||||
let homedir: URI = this.options.defaultUri ? this.options.defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri;
|
||||
let trailing: string | undefined;
|
||||
let stat: IFileStat | undefined;
|
||||
let ext: string = resources.extname(homedir);
|
||||
if (this.options.defaultUri) {
|
||||
@@ -160,14 +161,14 @@ export class RemoteFileDialog {
|
||||
}
|
||||
if (!stat || !stat.isDirectory) {
|
||||
homedir = resources.dirname(this.options.defaultUri);
|
||||
trailing = resources.basename(this.options.defaultUri);
|
||||
this.trailing = resources.basename(this.options.defaultUri);
|
||||
}
|
||||
// append extension
|
||||
if (isSave && !ext && this.options.filters) {
|
||||
for (let i = 0; i < this.options.filters.length; i++) {
|
||||
if (this.options.filters[i].extensions[0] !== '*') {
|
||||
ext = '.' + this.options.filters[i].extensions[0];
|
||||
trailing = trailing ? trailing + ext : ext;
|
||||
this.trailing = this.trailing ? this.trailing + ext : ext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -176,6 +177,7 @@ export class RemoteFileDialog {
|
||||
|
||||
return new Promise<URI | undefined>(async (resolve) => {
|
||||
this.filePickBox = this.quickInputService.createQuickPick<FileQuickPickItem>();
|
||||
this.filePickBox.busy = true;
|
||||
this.filePickBox.matchOnLabel = false;
|
||||
this.filePickBox.autoFocusOnList = false;
|
||||
this.filePickBox.ignoreFocusOut = true;
|
||||
@@ -221,6 +223,7 @@ export class RemoteFileDialog {
|
||||
this.options.availableFileSystems.shift();
|
||||
}
|
||||
this.options.defaultUri = undefined;
|
||||
this.filePickBox.hide();
|
||||
if (this.requiresTrailing) {
|
||||
return this.fileDialogService.showSaveDialog(this.options).then(result => {
|
||||
doResolve(this, result);
|
||||
@@ -264,7 +267,7 @@ export class RemoteFileDialog {
|
||||
// onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything
|
||||
if (this.isChangeFromUser()) {
|
||||
// If the user has just entered more bad path, don't change anything
|
||||
if (value !== this.constructFullUserPath() && !this.isBadSubpath(value)) {
|
||||
if (!equalsIgnoreCase(value, this.constructFullUserPath()) && !this.isBadSubpath(value)) {
|
||||
this.filePickBox.validationMessage = undefined;
|
||||
const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value));
|
||||
let updated: UpdateResult = UpdateResult.NotUpdated;
|
||||
@@ -288,12 +291,13 @@ export class RemoteFileDialog {
|
||||
|
||||
this.filePickBox.show();
|
||||
this.contextKey.set(true);
|
||||
await this.updateItems(homedir, trailing);
|
||||
if (trailing) {
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - ext.length];
|
||||
await this.updateItems(homedir, this.trailing);
|
||||
if (this.trailing) {
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length - this.trailing.length, this.filePickBox.value.length - ext.length];
|
||||
} else {
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
|
||||
}
|
||||
this.filePickBox.busy = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -302,7 +306,7 @@ export class RemoteFileDialog {
|
||||
}
|
||||
|
||||
private isChangeFromUser(): boolean {
|
||||
if ((this.filePickBox.value === this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
|
||||
if (equalsIgnoreCase(this.filePickBox.value, this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))
|
||||
&& (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) {
|
||||
return false;
|
||||
}
|
||||
@@ -314,6 +318,7 @@ export class RemoteFileDialog {
|
||||
}
|
||||
|
||||
private async onDidAccept(): Promise<URI | undefined> {
|
||||
this.filePickBox.busy = true;
|
||||
let resolveValue: URI | undefined;
|
||||
let navigateValue: URI | undefined;
|
||||
const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value;
|
||||
@@ -351,21 +356,25 @@ export class RemoteFileDialog {
|
||||
if (resolveValue) {
|
||||
resolveValue = this.addPostfix(resolveValue);
|
||||
if (await this.validate(resolveValue)) {
|
||||
return Promise.resolve(resolveValue);
|
||||
this.filePickBox.busy = false;
|
||||
return resolveValue;
|
||||
}
|
||||
} else if (navigateValue) {
|
||||
// Try to navigate into the folder
|
||||
await this.updateItems(navigateValue);
|
||||
// Try to navigate into the folder.
|
||||
await this.updateItems(navigateValue, this.trailing);
|
||||
} else {
|
||||
// validation error. Path does not exist.
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
this.filePickBox.busy = false;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async tryUpdateItems(value: string, valueUri: URI): Promise<UpdateResult> {
|
||||
if (value[value.length - 1] === '~') {
|
||||
await this.updateItems(this.userHome);
|
||||
if (this.filePickBox.busy) {
|
||||
this.badPath = undefined;
|
||||
return UpdateResult.Updating;
|
||||
} else if (value[value.length - 1] === '~') {
|
||||
await this.updateItems(this.userHome);
|
||||
return UpdateResult.Updated;
|
||||
} else if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true))) {
|
||||
let stat: IFileStat | undefined;
|
||||
@@ -409,7 +418,7 @@ export class RemoteFileDialog {
|
||||
const inputBasename = resources.basename(this.remoteUriFrom(value));
|
||||
// Make sure that the folder whose children we are currently viewing matches the path in the input
|
||||
const userPath = this.constructFullUserPath();
|
||||
if (userPath === value.substring(0, userPath.length)) {
|
||||
if (equalsIgnoreCase(userPath, value.substring(0, userPath.length))) {
|
||||
let hasMatch = false;
|
||||
for (let i = 0; i < this.filePickBox.items.length; i++) {
|
||||
const item = <FileQuickPickItem>this.filePickBox.items[i];
|
||||
@@ -424,7 +433,7 @@ export class RemoteFileDialog {
|
||||
this.filePickBox.activeItems = [];
|
||||
}
|
||||
} else {
|
||||
if (inputBasename !== resources.basename(this.currentFolder)) {
|
||||
if (!equalsIgnoreCase(inputBasename, resources.basename(this.currentFolder))) {
|
||||
this.userEnteredPathSegment = inputBasename;
|
||||
} else {
|
||||
this.userEnteredPathSegment = '';
|
||||
@@ -442,24 +451,34 @@ export class RemoteFileDialog {
|
||||
}
|
||||
const itemBasename = quickPickItem.label;
|
||||
// Either force the autocomplete, or the old value should be one smaller than the new value and match the new value.
|
||||
if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
|
||||
if (itemBasename === '..') {
|
||||
// Don't match on the up directory item ever.
|
||||
this.userEnteredPathSegment = startingValue;
|
||||
this.autoCompletePathSegment = '';
|
||||
this.activeItem = quickPickItem;
|
||||
if (force) {
|
||||
// clear any selected text
|
||||
this.insertText(this.userEnteredPathSegment, '');
|
||||
}
|
||||
return false;
|
||||
} else if (!force && (itemBasename.length >= startingBasename.length) && equalsIgnoreCase(itemBasename.substr(0, startingBasename.length), startingBasename)) {
|
||||
this.userEnteredPathSegment = startingBasename;
|
||||
this.activeItem = quickPickItem;
|
||||
// Changing the active items will trigger the onDidActiveItemsChanged. Clear the autocomplete first, then set it after.
|
||||
this.autoCompletePathSegment = '';
|
||||
this.filePickBox.activeItems = [quickPickItem];
|
||||
this.autoCompletePathSegment = itemBasename.substr(startingBasename.length);
|
||||
this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename.substr(startingBasename.length));
|
||||
this.insertText(startingValue + this.autoCompletePathSegment, this.autoCompletePathSegment);
|
||||
this.filePickBox.valueSelection = [startingValue.length, this.filePickBox.value.length];
|
||||
return true;
|
||||
} else if (force && (quickPickItem.label !== (this.userEnteredPathSegment + this.autoCompletePathSegment))) {
|
||||
} else if (force && (!equalsIgnoreCase(quickPickItem.label, (this.userEnteredPathSegment + this.autoCompletePathSegment)))) {
|
||||
this.userEnteredPathSegment = '';
|
||||
this.autoCompletePathSegment = itemBasename;
|
||||
this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename);
|
||||
this.activeItem = quickPickItem;
|
||||
this.filePickBox.valueSelection = [this.pathFromUri(this.currentFolder, true).length, this.filePickBox.value.length];
|
||||
// use insert text to preserve undo buffer
|
||||
this.insertText(this.pathAppend(this.currentFolder, itemBasename), itemBasename);
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length - itemBasename.length, this.filePickBox.value.length];
|
||||
this.insertText(this.pathAppend(this.currentFolder, this.autoCompletePathSegment), this.autoCompletePathSegment);
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length - this.autoCompletePathSegment.length, this.filePickBox.value.length];
|
||||
return true;
|
||||
} else {
|
||||
this.userEnteredPathSegment = startingBasename;
|
||||
@@ -506,21 +525,24 @@ export class RemoteFileDialog {
|
||||
return ((path.length > 1) && this.endsWithSlash(path)) ? path.substr(0, path.length - 1) : path;
|
||||
}
|
||||
|
||||
private yesNoPrompt(message: string): Promise<boolean> {
|
||||
private yesNoPrompt(uri: URI, message: string): Promise<boolean> {
|
||||
interface YesNoItem extends IQuickPickItem {
|
||||
value: boolean;
|
||||
}
|
||||
const prompt = this.quickInputService.createQuickPick<YesNoItem>();
|
||||
const no = nls.localize('remoteFileDialog.no', 'No');
|
||||
prompt.items = [{ label: no, value: false }, { label: nls.localize('remoteFileDialog.yes', 'Yes'), value: true }];
|
||||
prompt.title = message;
|
||||
prompt.placeholder = no;
|
||||
prompt.ignoreFocusOut = true;
|
||||
prompt.ok = true;
|
||||
prompt.customButton = true;
|
||||
prompt.customLabel = nls.localize('remoteFileDialog.cancel', 'Cancel');
|
||||
prompt.value = this.pathFromUri(uri);
|
||||
|
||||
let isResolving = false;
|
||||
return new Promise<boolean>(resolve => {
|
||||
prompt.onDidAccept(() => {
|
||||
isResolving = true;
|
||||
prompt.hide();
|
||||
resolve(prompt.selectedItems ? prompt.selectedItems[0].value : false);
|
||||
resolve(true);
|
||||
});
|
||||
prompt.onDidHide(() => {
|
||||
if (!isResolving) {
|
||||
@@ -531,6 +553,12 @@ export class RemoteFileDialog {
|
||||
this.filePickBox.items = this.filePickBox.items;
|
||||
prompt.dispose();
|
||||
});
|
||||
prompt.onDidChangeValue(() => {
|
||||
prompt.hide();
|
||||
});
|
||||
prompt.onDidCustom(() => {
|
||||
prompt.hide();
|
||||
});
|
||||
prompt.show();
|
||||
});
|
||||
}
|
||||
@@ -554,7 +582,7 @@ export class RemoteFileDialog {
|
||||
// Replacing a file.
|
||||
// Show a yes/no prompt
|
||||
const message = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri));
|
||||
return this.yesNoPrompt(message);
|
||||
return this.yesNoPrompt(uri, message);
|
||||
} else if (!this.isValidBaseName(resources.basename(uri))) {
|
||||
// Filename not allowed
|
||||
this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.');
|
||||
@@ -587,15 +615,24 @@ export class RemoteFileDialog {
|
||||
this.userEnteredPathSegment = trailing ? trailing : '';
|
||||
this.autoCompletePathSegment = '';
|
||||
const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true);
|
||||
this.currentFolder = this.remoteUriFrom(this.pathFromUri(newFolder, true));
|
||||
const oldFolder = this.currentFolder;
|
||||
const newFolderPath = this.pathFromUri(newFolder, true);
|
||||
this.currentFolder = this.remoteUriFrom(newFolderPath);
|
||||
return this.createItems(this.currentFolder).then(items => {
|
||||
this.filePickBox.items = items;
|
||||
if (this.allowFolderSelection) {
|
||||
this.filePickBox.activeItems = [];
|
||||
}
|
||||
if (!equalsIgnoreCase(this.filePickBox.value, newValue)) {
|
||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
||||
this.insertText(newValue, newValue);
|
||||
// the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory.
|
||||
if (!equalsIgnoreCase(this.filePickBox.value.substring(0, newValue.length), newValue)) {
|
||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
||||
this.insertText(newValue, newValue);
|
||||
} else if (equalsIgnoreCase(this.pathFromUri(resources.dirname(oldFolder), true), newFolderPath)) {
|
||||
// This is the case where the user went up one dir. We need to make sure that we remove the final dir.
|
||||
this.filePickBox.valueSelection = [newFolderPath.length, this.filePickBox.value.length];
|
||||
this.insertText(newValue, '');
|
||||
}
|
||||
}
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length];
|
||||
this.filePickBox.busy = false;
|
||||
|
||||
@@ -530,16 +530,11 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
||||
|
||||
// Untitled file support
|
||||
const untitledInput = <IUntitledResourceInput>input;
|
||||
if (!untitledInput.resource || typeof untitledInput.filePath === 'string' || (untitledInput.resource instanceof URI && untitledInput.resource.scheme === Schemas.untitled)) {
|
||||
if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
|
||||
let modeId: string = untitledInput.language ? untitledInput.language : getFileMode(this.instantiationService, untitledInput.resource);
|
||||
return convertEditorInput(this.untitledEditorService.createOrGet(
|
||||
untitledInput.filePath ? URI.file(untitledInput.filePath) : untitledInput.resource,
|
||||
modeId,
|
||||
untitledInput.contents,
|
||||
untitledInput.encoding
|
||||
), undefined, this.instantiationService);
|
||||
return convertEditorInput(this.untitledEditorService.createOrGet(untitledInput.resource, modeId, untitledInput.contents, untitledInput.encoding), undefined, this.instantiationService);
|
||||
}
|
||||
|
||||
// Resource Editor Support
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorInput, EditorOptions, IFileEditorInput, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { workbenchInstantiationService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { workbenchInstantiationService, TestStorageService, NullFileSystemProvider } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
@@ -27,6 +27,8 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { toResource } from 'vs/base/test/common/utils';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
// {{SQL CARBON EDIT}} - Disable editor tests
|
||||
/*
|
||||
@@ -66,8 +68,17 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput {
|
||||
this.gotDisposed = true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
suite('Editor service', () => {/*
|
||||
|
||||
class FileServiceProvider extends Disposable {
|
||||
constructor(scheme: string, @IFileService fileService: IFileService) {
|
||||
super();
|
||||
|
||||
this._register(fileService.registerProvider(scheme, new NullFileSystemProvider()));
|
||||
}
|
||||
}
|
||||
|
||||
*/suite('Editor service', () => {/*
|
||||
|
||||
function registerTestEditorInput(): void {
|
||||
Registry.as<IEditorRegistry>(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), new SyncDescriptor(TestEditorInput));
|
||||
}
|
||||
@@ -250,9 +261,23 @@ suite('Editor service', () => {/*
|
||||
assert(input instanceof UntitledEditorInput);
|
||||
|
||||
// Untyped Input (untitled with file path)
|
||||
input = service.createInput({ filePath: '/some/path.txt', options: { selection: { startLineNumber: 1, startColumn: 1 } } });
|
||||
input = service.createInput({ resource: URI.file('/some/path.txt'), forceUntitled: true, options: { selection: { startLineNumber: 1, startColumn: 1 } } });
|
||||
assert(input instanceof UntitledEditorInput);
|
||||
assert.ok((input as UntitledEditorInput).hasAssociatedFilePath);
|
||||
|
||||
// Untyped Input (untitled with untitled resource)
|
||||
input = service.createInput({ resource: URI.parse('untitled://Untitled-1'), forceUntitled: true, options: { selection: { startLineNumber: 1, startColumn: 1 } } });
|
||||
assert(input instanceof UntitledEditorInput);
|
||||
assert.ok(!(input as UntitledEditorInput).hasAssociatedFilePath);
|
||||
|
||||
// Untyped Input (untitled with custom resource)
|
||||
const provider = instantiationService.createInstance(FileServiceProvider, 'untitled-custom');
|
||||
|
||||
input = service.createInput({ resource: URI.parse('untitled-custom://some/path'), forceUntitled: true, options: { selection: { startLineNumber: 1, startColumn: 1 } } });
|
||||
assert(input instanceof UntitledEditorInput);
|
||||
assert.ok((input as UntitledEditorInput).hasAssociatedFilePath);
|
||||
|
||||
provider.dispose();
|
||||
});
|
||||
|
||||
test('delegate', function (done) {
|
||||
|
||||
@@ -481,7 +481,7 @@ function readWindowsCaCertificates() {
|
||||
}
|
||||
|
||||
async function readMacCaCertificates() {
|
||||
const stdout = (await promisify(cp.execFile)('/usr/bin/security', ['find-certificate', '-a', '-p'], { encoding: 'utf8' })).stdout;
|
||||
const stdout = (await promisify(cp.execFile)('/usr/bin/security', ['find-certificate', '-a', '-p'], { encoding: 'utf8', maxBuffer: 1024 * 1024 })).stdout;
|
||||
const seen = {};
|
||||
const certs = stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g)
|
||||
.filter(pem => !!pem.length && !seen[pem] && (seen[pem] = true));
|
||||
|
||||
@@ -157,7 +157,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
}
|
||||
|
||||
// Bubble up any other error as is
|
||||
throw error;
|
||||
throw this.ensureError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
etag: etag(stat.mtime, stat.size)
|
||||
etag: etag({ mtime: stat.mtime, size: stat.size })
|
||||
};
|
||||
|
||||
// check to recurse for directories
|
||||
@@ -306,7 +306,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
await this.doWriteUnbuffered(provider, resource, bufferOrReadable);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new FileOperationError(localize('err.write', "Unable to write file ({0})", error.toString()), toFileOperationResult(error), options);
|
||||
throw new FileOperationError(localize('err.write', "Unable to write file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options);
|
||||
}
|
||||
|
||||
return this.resolve(resource, { resolveMetadata: true });
|
||||
@@ -337,7 +337,10 @@ export class FileService extends Disposable implements IFileService {
|
||||
// check for size is a weaker check because it can return a false negative if the file has changed
|
||||
// but to the same length. This is a compromise we take to avoid having to produce checksums of
|
||||
// the file content for comparison which would be much slower to compute.
|
||||
if (options && typeof options.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.mtime < stat.mtime && options.etag !== etag(stat.size, options.mtime)) {
|
||||
if (
|
||||
options && typeof options.mtime === 'number' && typeof options.etag === 'string' &&
|
||||
options.etag !== ETAG_DISABLED && options.mtime < stat.mtime && options.etag !== etag({ mtime: options.mtime /* not using stat.mtime for a reason, see above */, size: stat.size })
|
||||
) {
|
||||
throw new FileOperationError(localize('fileModifiedError', "File Modified Since"), FileOperationResult.FILE_MODIFIED_SINCE, options);
|
||||
}
|
||||
|
||||
@@ -398,7 +401,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
value: fileStream
|
||||
};
|
||||
} catch (error) {
|
||||
throw new FileOperationError(localize('err.read', "Unable to read file ({0})", error.toString()), toFileOperationResult(error), options);
|
||||
throw new FileOperationError(localize('err.read', "Unable to read file ({0})", this.ensureError(error).toString()), toFileOperationResult(error), options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +465,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
stream.write(buffer.slice(0, lastChunkLength));
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
throw this.ensureError(error);
|
||||
} finally {
|
||||
await provider.close(handle);
|
||||
}
|
||||
@@ -492,8 +495,8 @@ export class FileService extends Disposable implements IFileService {
|
||||
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);
|
||||
}
|
||||
|
||||
// Return early if file not modified since
|
||||
if (options && options.etag === stat.etag) {
|
||||
// Return early if file not modified since (unless disabled)
|
||||
if (options && options.etag !== ETAG_DISABLED && options.etag === stat.etag) {
|
||||
throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options);
|
||||
}
|
||||
|
||||
@@ -863,7 +866,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
posInFile += chunk.byteLength;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
throw this.ensureError(error);
|
||||
} finally {
|
||||
await provider.close(handle);
|
||||
}
|
||||
@@ -929,7 +932,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
}
|
||||
} while (bytesRead > 0);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
throw this.ensureError(error);
|
||||
} finally {
|
||||
await Promise.all([
|
||||
typeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(),
|
||||
@@ -960,7 +963,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
const buffer = await sourceProvider.readFile(source);
|
||||
await this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
throw this.ensureError(error);
|
||||
} finally {
|
||||
await targetProvider.close(targetHandle);
|
||||
}
|
||||
@@ -991,6 +994,14 @@ export class FileService extends Disposable implements IFileService {
|
||||
return true;
|
||||
}
|
||||
|
||||
private ensureError(error?: Error): Error {
|
||||
if (!error) {
|
||||
return new Error(localize('unknownError', "Unknown Error")); // https://github.com/Microsoft/vscode/issues/72798
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
private throwIfTooLarge(totalBytesRead: number, options?: IReadFileOptions): boolean {
|
||||
|
||||
// Return early if file is too large to load
|
||||
|
||||
@@ -355,7 +355,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('resolve - folder symbolic link', async () => {
|
||||
if (isWindows) {
|
||||
return; // not happy
|
||||
return; // not reliable on windows
|
||||
}
|
||||
|
||||
const link = URI.file(join(testDir, 'deep-link'));
|
||||
@@ -369,7 +369,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('resolve - file symbolic link', async () => {
|
||||
if (isWindows) {
|
||||
return; // not happy
|
||||
return; // not reliable on windows
|
||||
}
|
||||
|
||||
const link = URI.file(join(testDir, 'lorem.txt-linked'));
|
||||
@@ -382,7 +382,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('resolve - invalid symbolic link does not break', async () => {
|
||||
if (isWindows) {
|
||||
return; // not happy
|
||||
return; // not reliable on windows
|
||||
}
|
||||
|
||||
const link = URI.file(join(testDir, 'foo'));
|
||||
@@ -824,12 +824,24 @@ suite('Disk File Service', () => {
|
||||
return testReadFile(URI.file(join(testDir, 'small.txt')));
|
||||
});
|
||||
|
||||
test('readFile - small file - buffered / readonly', () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose | FileSystemProviderCapabilities.Readonly);
|
||||
|
||||
return testReadFile(URI.file(join(testDir, 'small.txt')));
|
||||
});
|
||||
|
||||
test('readFile - small file - unbuffered', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite);
|
||||
|
||||
return testReadFile(URI.file(join(testDir, 'small.txt')));
|
||||
});
|
||||
|
||||
test('readFile - small file - unbuffered / readonly', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.Readonly);
|
||||
|
||||
return testReadFile(URI.file(join(testDir, 'small.txt')));
|
||||
});
|
||||
|
||||
test('readFile - large file - buffered', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose);
|
||||
|
||||
@@ -1200,6 +1212,26 @@ suite('Disk File Service', () => {
|
||||
assert.equal(readFileSync(resource.fsPath), newContent);
|
||||
});
|
||||
|
||||
test('writeFile - buffered - readonly throws', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileOpenReadWriteClose | FileSystemProviderCapabilities.Readonly);
|
||||
|
||||
const resource = URI.file(join(testDir, 'small.txt'));
|
||||
|
||||
const content = readFileSync(resource.fsPath);
|
||||
assert.equal(content, 'Small File');
|
||||
|
||||
const newContent = 'Updates to the small file';
|
||||
|
||||
let error: Error;
|
||||
try {
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContent));
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error!);
|
||||
});
|
||||
|
||||
test('writeFile - unbuffered', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite);
|
||||
|
||||
@@ -1228,6 +1260,26 @@ suite('Disk File Service', () => {
|
||||
assert.equal(readFileSync(resource.fsPath), newContent);
|
||||
});
|
||||
|
||||
test('writeFile - unbuffered - readonly throws', async () => {
|
||||
setCapabilities(fileProvider, FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.Readonly);
|
||||
|
||||
const resource = URI.file(join(testDir, 'small.txt'));
|
||||
|
||||
const content = readFileSync(resource.fsPath);
|
||||
assert.equal(content, 'Small File');
|
||||
|
||||
const newContent = 'Updates to the small file';
|
||||
|
||||
let error: Error;
|
||||
try {
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContent));
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error!);
|
||||
});
|
||||
|
||||
test('writeFile (large file) - multiple parallel writes queue up', async () => {
|
||||
const resource = URI.file(join(testDir, 'lorem.txt'));
|
||||
|
||||
@@ -1336,20 +1388,25 @@ suite('Disk File Service', () => {
|
||||
assert.equal(readFileSync(resource.fsPath), newContent);
|
||||
});
|
||||
|
||||
test('writeFile (error when writing to file that has been updated meanwhile)', async () => {
|
||||
test('writeFile - error when writing to file that has been updated meanwhile', async () => {
|
||||
const resource = URI.file(join(testDir, 'small.txt'));
|
||||
|
||||
const stat = await service.resolve(resource);
|
||||
|
||||
const content = readFileSync(resource.fsPath);
|
||||
const content = readFileSync(resource.fsPath).toString();
|
||||
assert.equal(content, 'Small File');
|
||||
|
||||
const newContent = 'Updates to the small file';
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContent), { etag: stat.etag, mtime: stat.mtime });
|
||||
|
||||
const newContentLeadingToError = newContent + newContent;
|
||||
|
||||
const fakeMtime = 1000;
|
||||
const fakeSize = 1000;
|
||||
|
||||
let error: FileOperationError | undefined = undefined;
|
||||
try {
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContent), { etag: etag(0, 0), mtime: 0 });
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContentLeadingToError), { etag: etag({ mtime: fakeMtime, size: fakeSize }), mtime: fakeMtime });
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
@@ -1359,6 +1416,32 @@ suite('Disk File Service', () => {
|
||||
assert.equal(error!.fileOperationResult, FileOperationResult.FILE_MODIFIED_SINCE);
|
||||
});
|
||||
|
||||
test('writeFile - no error when writing to file where size is the same', async () => {
|
||||
const resource = URI.file(join(testDir, 'small.txt'));
|
||||
|
||||
const stat = await service.resolve(resource);
|
||||
|
||||
const content = readFileSync(resource.fsPath).toString();
|
||||
assert.equal(content, 'Small File');
|
||||
|
||||
const newContent = content; // same content
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContent), { etag: stat.etag, mtime: stat.mtime });
|
||||
|
||||
const newContentLeadingToNoError = newContent; // writing the same content should be OK
|
||||
|
||||
const fakeMtime = 1000;
|
||||
const actualSize = newContent.length;
|
||||
|
||||
let error: FileOperationError | undefined = undefined;
|
||||
try {
|
||||
await service.writeFile(resource, VSBuffer.fromString(newContentLeadingToNoError), { etag: etag({ mtime: fakeMtime, size: actualSize }), mtime: fakeMtime });
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(!error);
|
||||
});
|
||||
|
||||
test('watch - file', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
@@ -1370,7 +1453,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('watch - file symbolic link', async done => {
|
||||
if (isWindows) {
|
||||
return done(); // not happy
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const toWatch = URI.file(join(testDir, 'lorem.txt-linked'));
|
||||
@@ -1383,7 +1466,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('watch - file - multiple writes', done => {
|
||||
if (isWindows) {
|
||||
return done(); // not happy
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
@@ -1446,6 +1529,10 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - change file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch3'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
@@ -1458,6 +1545,10 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - add file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch4'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
@@ -1469,6 +1560,10 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - delete file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch5'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
@@ -1481,6 +1576,10 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - add folder', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch6'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
@@ -1492,8 +1591,8 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - delete folder', done => {
|
||||
if (isWindows) {
|
||||
return done(); // not happy
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch7'));
|
||||
@@ -1508,8 +1607,8 @@ suite('Disk File Service', () => {
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - symbolic link - change file', async done => {
|
||||
if (isWindows) {
|
||||
return done(); // not happy
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'deep-link'));
|
||||
@@ -1525,7 +1624,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('watch - folder (non recursive) - rename file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // not happy
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch8'));
|
||||
@@ -1543,7 +1642,7 @@ suite('Disk File Service', () => {
|
||||
|
||||
test('watch - folder (non recursive) - rename file (different case)', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // not happy
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
const watchDir = URI.file(join(testDir, 'watch8'));
|
||||
|
||||
@@ -137,7 +137,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
}
|
||||
|
||||
if (this.defaultSettingsRawResource.toString() === uri.toString()) {
|
||||
const defaultRawSettingsEditorModel = this.instantiationService.createInstance(DefaultRawSettingsEditorModel, this.getDefaultSettings(ConfigurationTarget.USER));
|
||||
const defaultRawSettingsEditorModel = this.instantiationService.createInstance(DefaultRawSettingsEditorModel, this.getDefaultSettings(ConfigurationTarget.USER_LOCAL));
|
||||
const languageSelection = this.modeService.create('jsonc');
|
||||
const model = this._register(this.modelService.createModel(defaultRawSettingsEditorModel.content, languageSelection, uri));
|
||||
return Promise.resolve(model);
|
||||
@@ -159,7 +159,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
}
|
||||
|
||||
if (this.userSettingsResource.toString() === uri.toString()) {
|
||||
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri);
|
||||
return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_LOCAL, uri);
|
||||
}
|
||||
|
||||
const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
|
||||
@@ -209,8 +209,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
jsonEditor;
|
||||
|
||||
return jsonEditor ?
|
||||
this.openOrSwitchSettings(ConfigurationTarget.USER, this.userSettingsResource, options, group) :
|
||||
this.openOrSwitchSettings2(ConfigurationTarget.USER, undefined, options, group);
|
||||
this.openOrSwitchSettings(ConfigurationTarget.USER_LOCAL, this.userSettingsResource, options, group) :
|
||||
this.openOrSwitchSettings2(ConfigurationTarget.USER_LOCAL, undefined, options, group);
|
||||
}
|
||||
|
||||
async openRemoteSettings(): Promise<IEditor | null> {
|
||||
@@ -377,7 +377,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
}
|
||||
|
||||
public createSettings2EditorModel(): Settings2EditorModel {
|
||||
return this.instantiationService.createInstance(Settings2EditorModel, this.getDefaultSettings(ConfigurationTarget.USER));
|
||||
return this.instantiationService.createInstance(Settings2EditorModel, this.getDefaultSettings(ConfigurationTarget.USER_LOCAL));
|
||||
}
|
||||
|
||||
private doOpenSettings2(target: ConfigurationTarget, folderUri: URI | undefined, options?: IEditorOptions, group?: IEditorGroup): Promise<IEditor | null> {
|
||||
@@ -419,7 +419,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
|
||||
private getConfigurationTargetFromSettingsResource(resource: URI): ConfigurationTarget {
|
||||
if (this.userSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.USER;
|
||||
return ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
|
||||
const workspaceSettingsResource = this.workspaceSettingsResource;
|
||||
@@ -432,11 +432,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return ConfigurationTarget.WORKSPACE_FOLDER;
|
||||
}
|
||||
|
||||
return ConfigurationTarget.USER;
|
||||
return ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
|
||||
private getConfigurationTargetFromDefaultSettingsResource(uri: URI) {
|
||||
return this.isDefaultWorkspaceSettingsResource(uri) ? ConfigurationTarget.WORKSPACE : this.isDefaultFolderSettingsResource(uri) ? ConfigurationTarget.WORKSPACE_FOLDER : ConfigurationTarget.USER;
|
||||
return this.isDefaultWorkspaceSettingsResource(uri) ?
|
||||
ConfigurationTarget.WORKSPACE :
|
||||
this.isDefaultFolderSettingsResource(uri) ?
|
||||
ConfigurationTarget.WORKSPACE_FOLDER :
|
||||
ConfigurationTarget.USER_LOCAL;
|
||||
}
|
||||
|
||||
private isDefaultSettingsResource(uri: URI): boolean {
|
||||
|
||||
@@ -309,7 +309,7 @@ export class ProgressService2 implements IProgressService2 {
|
||||
disposables.push(attachDialogStyler(dialog, this._themeService));
|
||||
|
||||
dialog.show().then(() => {
|
||||
if (options.cancellable && typeof onDidCancel === 'function') {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { isEqual, isEqualOrParent, extname, basename } from 'vs/base/common/resources';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
/**
|
||||
* The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk.
|
||||
@@ -300,7 +301,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
// Decide on etag
|
||||
let etag: string | undefined;
|
||||
if (forceReadFromDisk) {
|
||||
etag = undefined; // reset ETag if we enforce to read from disk
|
||||
etag = ETAG_DISABLED; // disable ETag if we enforce to read from disk
|
||||
} else if (this.lastResolvedDiskStat) {
|
||||
etag = this.lastResolvedDiskStat.etag; // otherwise respect etag to support caching
|
||||
}
|
||||
@@ -826,10 +827,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
private getTelemetryData(reason: number | undefined): object {
|
||||
const ext = extname(this.resource);
|
||||
const fileName = basename(this.resource);
|
||||
const path = this.resource.scheme === Schemas.file ? this.resource.fsPath : this.resource.path;
|
||||
const telemetryData = {
|
||||
mimeType: guessMimeTypes(this.resource.fsPath).join(', '),
|
||||
mimeType: guessMimeTypes(path).join(', '),
|
||||
ext,
|
||||
path: hash(this.resource.fsPath),
|
||||
path: hash(path),
|
||||
reason
|
||||
};
|
||||
|
||||
|
||||
@@ -871,13 +871,20 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
|
||||
return false;
|
||||
}
|
||||
|
||||
// take over encoding and model value from source model
|
||||
// take over encoding, mode and model value from source model
|
||||
targetModel.updatePreferredEncoding(sourceModel.getEncoding());
|
||||
if (targetModel.textEditorModel) {
|
||||
const snapshot = sourceModel.createSnapshot();
|
||||
if (snapshot) {
|
||||
this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(snapshot));
|
||||
}
|
||||
|
||||
if (sourceModel.textEditorModel) {
|
||||
const language = sourceModel.textEditorModel.getLanguageIdentifier();
|
||||
if (language.id > 1) {
|
||||
targetModel.textEditorModel.setMode(language); // only use if more specific than plain/text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save model
|
||||
|
||||
@@ -30,6 +30,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema';
|
||||
import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
// implementation
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -480,7 +481,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
|
||||
this.doSetFileIconTheme(newIconTheme);
|
||||
|
||||
// remember theme data for a quick restore
|
||||
if (newIconTheme.isLoaded) {
|
||||
if (newIconTheme.isLoaded && newIconTheme.location && !getRemoteAuthority(newIconTheme.location)) {
|
||||
this.storageService.store(PERSISTED_ICON_THEME_STORAGE_KEY, newIconTheme.toStorageData(), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1017,8 +1017,12 @@ export class TestFileService implements IFileService {
|
||||
|
||||
onDidChangeFileSystemProviderRegistrations = Event.None;
|
||||
|
||||
registerProvider(_scheme: string, _provider: IFileSystemProvider) {
|
||||
return { dispose() { } };
|
||||
private providers = new Map<string, IFileSystemProvider>();
|
||||
|
||||
registerProvider(scheme: string, provider: IFileSystemProvider) {
|
||||
this.providers.set(scheme, provider);
|
||||
|
||||
return toDisposable(() => this.providers.delete(scheme));
|
||||
}
|
||||
|
||||
activateProvider(_scheme: string): Promise<void> {
|
||||
@@ -1026,7 +1030,7 @@ export class TestFileService implements IFileService {
|
||||
}
|
||||
|
||||
canHandleResource(resource: URI): boolean {
|
||||
return resource.scheme === 'file';
|
||||
return resource.scheme === 'file' || this.providers.has(resource.scheme);
|
||||
}
|
||||
|
||||
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean { return false; }
|
||||
|
||||
@@ -9257,10 +9257,10 @@ typescript-tslint-plugin@^0.0.7:
|
||||
minimatch "^3.0.4"
|
||||
vscode-languageserver "^5.1.0"
|
||||
|
||||
typescript@3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6"
|
||||
integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==
|
||||
typescript@3.4.5:
|
||||
version "3.4.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99"
|
||||
integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==
|
||||
|
||||
typescript@^2.6.2:
|
||||
version "2.6.2"
|
||||
|
||||