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