From b66ce71972e56a3abcb73d15e8fe846e7291f4df Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Sun, 15 Sep 2019 22:17:17 -0700 Subject: [PATCH 01/82] Add Codicon --- .../codicon/codicon-animations.css | 14 + .../ui/codiconLabel/codicon/codicon.css | 354 ++++++++++++++++++ .../ui/codiconLabel/codicon/codicon.ttf | Bin 0 -> 52456 bytes .../ui/codiconLabel/codiconLabel.mock.ts | 24 ++ .../browser/ui/codiconLabel/codiconLabel.ts | 33 ++ .../ui/highlightedlabel/highlightedLabel.ts | 8 +- 6 files changed, 429 insertions(+), 4 deletions(-) create mode 100644 src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css create mode 100644 src/vs/base/browser/ui/codiconLabel/codicon/codicon.css create mode 100644 src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf create mode 100644 src/vs/base/browser/ui/codiconLabel/codiconLabel.mock.ts create mode 100644 src/vs/base/browser/ui/codiconLabel/codiconLabel.ts diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css new file mode 100644 index 00000000000..86c223674ec --- /dev/null +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon-animations.css @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +@keyframes codicon-spin { + 100% { + transform:rotate(360deg); + } +} + +.codicon-animation-spin { + animation: octicon-spin 1.5s linear infinite; +} diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css new file mode 100644 index 00000000000..04309db0ca4 --- /dev/null +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -0,0 +1,354 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +@font-face { + font-family: "codicon"; + src: url("./codicon.ttf?e042d2dda15ef7b36b910e3edf539f26") format("truetype"), +url("./codicon.svg?e042d2dda15ef7b36b910e3edf539f26#codicon") format("svg"); +} + +.codicon { + font: normal normal normal 16px/1 codicon; + display: inline-block; + text-decoration: none; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + + +.codicon-add:before { content: "\ea60" } +.codicon-plus:before { content: "\ea60" } +.codicon-gist-new:before { content: "\ea60" } +.codicon-repo-create:before { content: "\ea60" } +.codicon-lightbulb:before { content: "\ea61" } +.codicon-light-bulb:before { content: "\ea61" } +.codicon-repo:before { content: "\ea62" } +.codicon-repo-delete:before { content: "\ea62" } +.codicon-gist-fork:before { content: "\ea63" } +.codicon-repo-forked:before { content: "\ea63" } +.codicon-git-pull-request:before { content: "\ea64" } +.codicon-git-pull-request-abandoned:before { content: "\ea64" } +.codicon-record-keys:before { content: "\ea65" } +.codicon-keyboard:before { content: "\ea65" } +.codicon-tag:before { content: "\ea66" } +.codicon-tag-add:before { content: "\ea66" } +.codicon-tag-remove:before { content: "\ea66" } +.codicon-person:before { content: "\ea67" } +.codicon-person-add:before { content: "\ea67" } +.codicon-person-follow:before { content: "\ea67" } +.codicon-person-outline:before { content: "\ea67" } +.codicon-person-filled:before { content: "\ea67" } +.codicon-git-branch:before { content: "\ea68" } +.codicon-git-branch-create:before { content: "\ea68" } +.codicon-git-branch-delete:before { content: "\ea68" } +.codicon-source-control:before { content: "\ea68" } +.codicon-mirror:before { content: "\ea69" } +.codicon-mirror-public:before { content: "\ea69" } +.codicon-star:before { content: "\ea6a" } +.codicon-star-add:before { content: "\ea6a" } +.codicon-star-delete:before { content: "\ea6a" } +.codicon-comment:before { content: "\ea6b" } +.codicon-comment-add:before { content: "\ea6b" } +.codicon-alert:before { content: "\ea6c" } +.codicon-warning:before { content: "\ea6c" } +.codicon-search:before { content: "\ea6d" } +.codicon-search-save:before { content: "\ea6d" } +.codicon-log-out:before { content: "\ea6e" } +.codicon-sign-out:before { content: "\ea6e" } +.codicon-log-in:before { content: "\ea6f" } +.codicon-sign-in:before { content: "\ea6f" } +.codicon-eye:before { content: "\ea70" } +.codicon-eye-unwatch:before { content: "\ea70" } +.codicon-eye-watch:before { content: "\ea70" } +.codicon-circle-filled:before { content: "\ea71" } +.codicon-primitive-dot:before { content: "\ea71" } +.codicon-stop:before { content: "\ea72" } +.codicon-primitive-square:before { content: "\ea72" } +.codicon-edit:before { content: "\ea73" } +.codicon-pencil:before { content: "\ea73" } +.codicon-info:before { content: "\ea74" } +.codicon-issue-opened:before { content: "\ea74" } +.codicon-gist-private:before { content: "\ea75" } +.codicon-git-fork-private:before { content: "\ea75" } +.codicon-lock:before { content: "\ea75" } +.codicon-mirror-private:before { content: "\ea75" } +.codicon-close:before { content: "\ea76" } +.codicon-remove-close:before { content: "\ea76" } +.codicon-x:before { content: "\ea76" } +.codicon-repo-sync:before { content: "\ea77" } +.codicon-sync:before { content: "\ea77" } +.codicon-clone:before { content: "\ea78" } +.codicon-desktop-download:before { content: "\ea78" } +.codicon-beaker:before { content: "\ea79" } +.codicon-microscope:before { content: "\ea79" } +.codicon-vm:before { content: "\ea7a" } +.codicon-device-desktop:before { content: "\ea7a" } +.codicon-file:before { content: "\ea7b" } +.codicon-file-text:before { content: "\ea7b" } +.codicon-more:before { content: "\ea7c" } +.codicon-kebab-horizontal:before { content: "\ea7c" } +.codicon-mail-reply:before { content: "\ea7d" } +.codicon-reply:before { content: "\ea7d" } +.codicon-organization:before { content: "\ea7e" } +.codicon-organization-filled:before { content: "\ea7e" } +.codicon-organization-outline:before { content: "\ea7e" } +.codicon-new-file:before { content: "\ea7f" } +.codicon-file-add:before { content: "\ea7f" } +.codicon-new-folder:before { content: "\ea80" } +.codicon-file-directory-create:before { content: "\ea80" } +.codicon-Vector:before { content: "\f101" } +.codicon-activate-breakpoints:before { content: "\f102" } +.codicon-archive:before { content: "\f103" } +.codicon-array:before { content: "\f104" } +.codicon-arrow-both:before { content: "\f105" } +.codicon-arrow-down:before { content: "\f106" } +.codicon-arrow-left:before { content: "\f107" } +.codicon-arrow-right:before { content: "\f108" } +.codicon-arrow-small-down:before { content: "\f109" } +.codicon-arrow-small-left:before { content: "\f10a" } +.codicon-arrow-small-right:before { content: "\f10b" } +.codicon-arrow-small-up:before { content: "\f10c" } +.codicon-arrow-up:before { content: "\f10d" } +.codicon-bell:before { content: "\f10e" } +.codicon-bold:before { content: "\f10f" } +.codicon-book:before { content: "\f110" } +.codicon-bookmark:before { content: "\f111" } +.codicon-boolean:before { content: "\f112" } +.codicon-breakpoint-conditional-unverified:before { content: "\f113" } +.codicon-breakpoint-conditional:before { content: "\f114" } +.codicon-breakpoint-data-unverified:before { content: "\f115" } +.codicon-breakpoint-data:before { content: "\f116" } +.codicon-breakpoint-log-unverified:before { content: "\f117" } +.codicon-breakpoint-log:before { content: "\f118" } +.codicon-briefcase:before { content: "\f119" } +.codicon-broadcast:before { content: "\f11a" } +.codicon-browser:before { content: "\f11b" } +.codicon-bug:before { content: "\f11c" } +.codicon-calendar:before { content: "\f11d" } +.codicon-case-sensitive:before { content: "\f11e" } +.codicon-check:before { content: "\f11f" } +.codicon-checklist:before { content: "\f120" } +.codicon-chevron-down:before { content: "\f121" } +.codicon-chevron-left:before { content: "\f122" } +.codicon-chevron-right:before { content: "\f123" } +.codicon-chevron-up:before { content: "\f124" } +.codicon-circle-outline:before { content: "\f125" } +.codicon-circle-slash:before { content: "\f126" } +.codicon-circuit-board:before { content: "\f127" } +.codicon-class:before { content: "\f128" } +.codicon-clear-all:before { content: "\f129" } +.codicon-clippy:before { content: "\f12a" } +.codicon-close-all:before { content: "\f12b" } +.codicon-cloud-download:before { content: "\f12c" } +.codicon-cloud-upload:before { content: "\f12d" } +.codicon-code:before { content: "\f12e" } +.codicon-collapse-all:before { content: "\f12f" } +.codicon-color-mode:before { content: "\f130" } +.codicon-color:before { content: "\f131" } +.codicon-comment-discussion:before { content: "\f132" } +.codicon-compare-changes:before { content: "\f133" } +.codicon-console:before { content: "\f134" } +.codicon-constant:before { content: "\f135" } +.codicon-continue:before { content: "\f136" } +.codicon-credit-card:before { content: "\f137" } +.codicon-current-and-breakpoint:before { content: "\f138" } +.codicon-current:before { content: "\f139" } +.codicon-dash:before { content: "\f13a" } +.codicon-dashboard:before { content: "\f13b" } +.codicon-database:before { content: "\f13c" } +.codicon-debug:before { content: "\f13d" } +.codicon-device-camera-video:before { content: "\f13e" } +.codicon-device-camera:before { content: "\f13f" } +.codicon-device-mobile:before { content: "\f140" } +.codicon-diff-added:before { content: "\f141" } +.codicon-diff-ignored:before { content: "\f142" } +.codicon-diff-modified:before { content: "\f143" } +.codicon-diff-removed:before { content: "\f144" } +.codicon-diff-renamed:before { content: "\f145" } +.codicon-diff:before { content: "\f146" } +.codicon-discard:before { content: "\f147" } +.codicon-disconnect-:before { content: "\f148" } +.codicon-editor-layout:before { content: "\f149" } +.codicon-ellipsis:before { content: "\f14a" } +.codicon-empty-window:before { content: "\f14b" } +.codicon-enumerator-member:before { content: "\f14c" } +.codicon-enumerator:before { content: "\f14d" } +.codicon-error:before { content: "\f14e" } +.codicon-event:before { content: "\f14f" } +.codicon-exclude:before { content: "\f150" } +.codicon-extensions:before { content: "\f151" } +.codicon-eye-closed:before { content: "\f152" } +.codicon-field:before { content: "\f153" } +.codicon-file-binary:before { content: "\f154" } +.codicon-file-code:before { content: "\f155" } +.codicon-file-media:before { content: "\f156" } +.codicon-file-pdf:before { content: "\f157" } +.codicon-file-submodule:before { content: "\f158" } +.codicon-file-symlink-directory:before { content: "\f159" } +.codicon-file-symlink-file:before { content: "\f15a" } +.codicon-file-zip:before { content: "\f15b" } +.codicon-files:before { content: "\f15c" } +.codicon-filter:before { content: "\f15d" } +.codicon-flame:before { content: "\f15e" } +.codicon-fold-down:before { content: "\f15f" } +.codicon-fold-up:before { content: "\f160" } +.codicon-fold:before { content: "\f161" } +.codicon-folder-active:before { content: "\f162" } +.codicon-folder-opened:before { content: "\f163" } +.codicon-folder:before { content: "\f164" } +.codicon-gift:before { content: "\f165" } +.codicon-gist-secret:before { content: "\f166" } +.codicon-gist:before { content: "\f167" } +.codicon-git-commit:before { content: "\f168" } +.codicon-git-compare:before { content: "\f169" } +.codicon-git-merge:before { content: "\f16a" } +.codicon-github-action:before { content: "\f16b" } +.codicon-github-alt:before { content: "\f16c" } +.codicon-github:before { content: "\f16d" } +.codicon-globe:before { content: "\f16e" } +.codicon-go-to-file:before { content: "\f16f" } +.codicon-grabber:before { content: "\f170" } +.codicon-graph:before { content: "\f171" } +.codicon-gripper:before { content: "\f172" } +.codicon-heart:before { content: "\f173" } +.codicon-history:before { content: "\f174" } +.codicon-home:before { content: "\f175" } +.codicon-horizontal-rule:before { content: "\f176" } +.codicon-hubot:before { content: "\f177" } +.codicon-inbox:before { content: "\f178" } +.codicon-interface:before { content: "\f179" } +.codicon-issue-closed:before { content: "\f17a" } +.codicon-issue-reopened:before { content: "\f17b" } +.codicon-issues:before { content: "\f17c" } +.codicon-italic:before { content: "\f17d" } +.codicon-jersey:before { content: "\f17e" } +.codicon-json:before { content: "\f17f" } +.codicon-kebab-vertical:before { content: "\f180" } +.codicon-key:before { content: "\f181" } +.codicon-keyword:before { content: "\f182" } +.codicon-law:before { content: "\f183" } +.codicon-lightbulb-autofix:before { content: "\f184" } +.codicon-link-external:before { content: "\f185" } +.codicon-link:before { content: "\f186" } +.codicon-list-ordered:before { content: "\f187" } +.codicon-list-unordered:before { content: "\f188" } +.codicon-live-share:before { content: "\f189" } +.codicon-loading:before { content: "\f18a" } +.codicon-location:before { content: "\f18b" } +.codicon-mail-read:before { content: "\f18c" } +.codicon-mail:before { content: "\f18d" } +.codicon-markdown:before { content: "\f18e" } +.codicon-megaphone:before { content: "\f18f" } +.codicon-mention:before { content: "\f190" } +.codicon-method:before { content: "\f191" } +.codicon-milestone:before { content: "\f192" } +.codicon-misc:before { content: "\f193" } +.codicon-mortar-board:before { content: "\f194" } +.codicon-move:before { content: "\f195" } +.codicon-multiple-windows:before { content: "\f196" } +.codicon-mute:before { content: "\f197" } +.codicon-namespace:before { content: "\f198" } +.codicon-no-newline:before { content: "\f199" } +.codicon-note:before { content: "\f19a" } +.codicon-numeric:before { content: "\f19b" } +.codicon-octoface:before { content: "\f19c" } +.codicon-open-preview:before { content: "\f19d" } +.codicon-operator:before { content: "\f19e" } +.codicon-package:before { content: "\f19f" } +.codicon-paintcan:before { content: "\f1a0" } +.codicon-parameter:before { content: "\f1a1" } +.codicon-pause:before { content: "\f1a2" } +.codicon-pin:before { content: "\f1a3" } +.codicon-play:before { content: "\f1a4" } +.codicon-plug:before { content: "\f1a5" } +.codicon-preserve-case:before { content: "\f1a6" } +.codicon-preview:before { content: "\f1a7" } +.codicon-project:before { content: "\f1a8" } +.codicon-property:before { content: "\f1a9" } +.codicon-pulse:before { content: "\f1aa" } +.codicon-question:before { content: "\f1ab" } +.codicon-quote:before { content: "\f1ac" } +.codicon-radio-tower:before { content: "\f1ad" } +.codicon-reactions:before { content: "\f1ae" } +.codicon-references:before { content: "\f1af" } +.codicon-refresh:before { content: "\f1b0" } +.codicon-regex:before { content: "\f1b1" } +.codicon-remote:before { content: "\f1b2" } +.codicon-remove:before { content: "\f1b3" } +.codicon-replace-all:before { content: "\f1b4" } +.codicon-replace:before { content: "\f1b5" } +.codicon-repo-clone:before { content: "\f1b6" } +.codicon-repo-force-push:before { content: "\f1b7" } +.codicon-repo-pull:before { content: "\f1b8" } +.codicon-repo-push:before { content: "\f1b9" } +.codicon-report:before { content: "\f1ba" } +.codicon-request-changes:before { content: "\f1bb" } +.codicon-restart:before { content: "\f1bc" } +.codicon-rocket:before { content: "\f1bd" } +.codicon-root-folder-opened:before { content: "\f1be" } +.codicon-root-folder:before { content: "\f1bf" } +.codicon-rss:before { content: "\f1c0" } +.codicon-ruby:before { content: "\f1c1" } +.codicon-ruler:before { content: "\f1c2" } +.codicon-save-all:before { content: "\f1c3" } +.codicon-save-as:before { content: "\f1c4" } +.codicon-save:before { content: "\f1c5" } +.codicon-screen-full:before { content: "\f1c6" } +.codicon-screen-normal:before { content: "\f1c7" } +.codicon-search-stop:before { content: "\f1c8" } +.codicon-selection:before { content: "\f1c9" } +.codicon-server:before { content: "\f1ca" } +.codicon-settings:before { content: "\f1cb" } +.codicon-shield:before { content: "\f1cc" } +.codicon-smiley:before { content: "\f1cd" } +.codicon-snippet:before { content: "\f1ce" } +.codicon-sort-precedence:before { content: "\f1cf" } +.codicon-split-horizontal:before { content: "\f1d0" } +.codicon-split-vertical:before { content: "\f1d1" } +.codicon-squirrel:before { content: "\f1d2" } +.codicon-star-empty:before { content: "\f1d3" } +.codicon-star-full:before { content: "\f1d4" } +.codicon-star-half:before { content: "\f1d5" } +.codicon-start:before { content: "\f1d6" } +.codicon-step-into:before { content: "\f1d7" } +.codicon-step-out:before { content: "\f1d8" } +.codicon-step-over:before { content: "\f1d9" } +.codicon-string:before { content: "\f1da" } +.codicon-structure:before { content: "\f1db" } +.codicon-tasklist:before { content: "\f1dc" } +.codicon-telescope:before { content: "\f1dd" } +.codicon-text-size:before { content: "\f1de" } +.codicon-three-bars:before { content: "\f1df" } +.codicon-thumbsdown:before { content: "\f1e0" } +.codicon-thumbsup:before { content: "\f1e1" } +.codicon-tools:before { content: "\f1e2" } +.codicon-trash:before { content: "\f1e3" } +.codicon-triangle-down:before { content: "\f1e4" } +.codicon-triangle-left:before { content: "\f1e5" } +.codicon-triangle-right:before { content: "\f1e6" } +.codicon-triangle-up:before { content: "\f1e7" } +.codicon-twitter:before { content: "\f1e8" } +.codicon-unfold:before { content: "\f1e9" } +.codicon-unlock:before { content: "\f1ea" } +.codicon-unmute:before { content: "\f1eb" } +.codicon-unverified:before { content: "\f1ec" } +.codicon-variable:before { content: "\f1ed" } +.codicon-verified:before { content: "\f1ee" } +.codicon-versions:before { content: "\f1ef" } +.codicon-vm-active:before { content: "\f1f0" } +.codicon-vm-outline:before { content: "\f1f1" } +.codicon-vm-running:before { content: "\f1f2" } +.codicon-watch:before { content: "\f1f3" } +.codicon-whitespace:before { content: "\f1f4" } +.codicon-whole-word:before { content: "\f1f5" } +.codicon-window:before { content: "\f1f6" } +.codicon-word-wrap:before { content: "\f1f7" } +.codicon-zoom-in:before { content: "\f1f8" } +.codicon-zoom-out:before { content: "\f1f9" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..688b9ffd0bd65ca22309fb809f1e91d3685faf52 GIT binary patch literal 52456 zcmeFad3;@Exi9{{Ywa<6o`)oR$j;t7$sUsIG2`B8lFsv7I;8VJ3zQDf76?UwLTd$N zC@KMQ01*`s1&$_i9Pm(7(1XfR>MZxDJ;GsW1&z((exJ2=O3`!g@AEmI``7Q@G*8y_ zu6KT)=lcxrD&veX6T5+ltYh}_m4lHF#IIqDcj4}e#mn1s11A=3!1YO7uiAR~<|{ql zZT$&jx;c#5zrXXcBRf9vh0pC|EU$;%a_{UxZh3pey(%|e_{fSPw* ze(>>69t(#XxkGdK2`56-mmv26NrBGnVpW~WEuGoC}_ULD3ypOT3 z-iqgSSMEJ<@S}$xY-jAB?`F)hl%eio;T@DM{_Y+8h`*;h7ys~patC+&R(&_P(bo58 zW)go#DSq;)=l4w?@#>)Xd$EXX0~6>je((<7evvtpE4o{Ue~i7OTr1CU-N7nM7@oCY z1+!kZ`QQ~S$TSx{zxbSAcInQ|$X|VvBON{ExWk!l`mXpIzk_LUWf!Q&PO3-#OV-Iz z1A%Ep-2E?pmh70hjSZaLB>h$CkF{vavq*MPZ-@_~f6(&(NB^%6{_mXw|EJc#|EYZb z|1%fCZHR9Xe@cVE+r+z7{v+ImyTpmoID&)XzDC%BYlF&d&t7`=2I;TwfUln2bas!# z=}h?{-WX)VI2YON?0f9H>;U^Z`wROb`#t*@D{}|?1^XZDHMW)|*_YX3_I`FRYiDn> zA!g%twvBz9y}%x053^6BbOANeg3s!arxCRYJDH2QnTL6qkNH^uW!AF> z*2qFE%pxqxnpliAvp7qz7S_tzSPCu4uq=3gC(E%sE3hIfu`brldRQ;(WBrf`RW`t8 zutC&*CY!}(vpH-oo5$v}1#BT(#Fnt7Y#Ce5R~eMm+lw?;vVCknJIJnLSF=OxFgwDoVb`+j*eJW69c4GL z_puw~rk%>~Z!4`vQBCeThBAo@URme_~%@+B8opX^O0u|Kjuu|Ko7*k9Qs`x`sYrkKp$;f!-GaFJ`c zmg~5l8@Q3zaT7Ol3%7C`cXAhZa}W1&AE5_MGWGxVA2W4;rBCe!pc$+%m1v!w-K-MU z7CVdeNQ70!&Tdr+>y4e=rV>^jJG)&atU-2mhe}wD>@4sf5!NL;yGtdkP|T|yy4l$)Rl+)FXMx#>u;SU-{VHMYv$Iq` z5V!z4dr&3t19tW*mB1O;*{f9ok6>pHsRVAp&K_0?e1n}mq7t*=2pmiVUc$~^s}i^h zJA0i<;4kd#s7l~8?CkX_f#{3C)iU=lq8K`tAV?u5 zQ92Oh5tAq#2$G3Olnw+L#iX)IkXB5hcR-L^Orm!{kYG%rcR-M3Orm!{Yyd}k2L$=X zBzgw~Nyj952SgHEqIW=$eoPur338B0^bQCTkxBFp2(pn$Ln=W^GKt;?L0&S6-UmT) zGKt;?L54Dk-UmUNGKt;?L9Q~1-UmU#GKt;?LDn*f-UmVIGKt;?LH;s{-UmSvGl|{@ zK_)Y4u}YB6OrpF%kkd?}yg-oHOrpF%kljq8yg-oROrpF%kmpRIyg-oJOrpF%knv2S zyg-olOrpF%Y!i-@7YGP|No!RC7GM(P3j!)&66Fg5K422%3j$JL66Fg5W?&NK3j%sz z(k7LFBbY?_f`BNPMEQb%Eto|4f`BrZv`r=84JJ_;ARrGWQ5hg$5GGL>Af;VY1_-!> zNmK?12!%;h1_)S%NmK?1sD(*X1_=0tNmK?1NQOyN1_+pjNmK?1=!Qv@F9y0Rl#15|sgBH{eKRfPkBrL}h@0pqNBu zfPkf#L}h@0s+dG&fPk-VsO2A=EqB1~0WK4R$O2B4J zqVhmMX-uN>K)`EEqVhmMZcL)`K)`TJqVhmMb4;T0K)`iOqVhmMcub=5K)`xTqVhmM zeN3YAK)`=YqVhmMf=r_FK){4dx?LrpLncw#AmBtMQQ06MMkZ0&AYex(QQ08&AdXZv z2zZi7R5l36l1WrH2pE$|_o@W6$t0==Na-u82M7q1NmLIIuqczL9w4AnCQ&^=z^6>2 zdVqjbnMCyf0kbmcV=4i?GU-8;fMc2Tag~5*nMCyi0oyW(>IVYKWfIj71iZ^6svii* zmq`z+1PsiiPpbqp%p|HS2)LL@R96rXGLxvTAhLZ)R96sCGn1&UAhOU%R96s?G?N}v ziG2-6sy7Jenn_e|5O6k=sNNtTZYEK^LBQTj`l3oe;Y^}7fPlxDL~Q^8nKOyn00Ks5 z614#Yw9X`I0|>aCNnch82%bsQ9uTlRlc+r)pn4`zdqBYVOrrLHfb^L}?EwMvGl|** z0{Umt*HnTYz@)FM1dV`6)HV=w113@1KxF%qsBIwV3rwQ6fuK1siP{E&4#6a98wlD2 zlc;SV=oL(QK_&J}9I2fk=o(C-c7mXFFzLH0LH}S9wHX9Wgh|w95OfkIeNQE5CrqOD zgP^A{iP{f>#=<0OKM1-Dlc@b5XfaHp_Jg3$Fp1g^f@Z@cYCi}%4wI<;AZR;GqV|KJ z_b`dt4}u27Bx*khx)777{UB&XOrrLKpdT@b+7E)J#3X7z2s#s!exVYyCno(;CFoI1 zqP_q@qhb>E1&Az~67>a$<5GG}C5{W}f2c&(M~V6f#6=vbk3d|5BlQu8YjOO&N~C>B z)L$U3$C3IA#0@x7e}T9WN9r#Sufvi03&c%0Qh$NC8As|b5Vzn+{RQGy9I3xR+=e6d z7l=D?Jf{+O;YfW4;%*$N??BvxMDq#l8tpaObGj>ZFYA7%FX*tQ8h9!2W^hjMrr=lVchyfc z7#cp@SZMr4NEez2Umt0R?1)?wc`ovY=(6ZXqu*_EHXUwytVxblVxMYe&5N4f-~7|~ zSp3z*rxL$TE=fL_e5<9Y<$=}(tv9v)vF+}*zoZJOO{rt4CsKb%kEHKTKbNV?tj(Ot zyqayuuF9UwKASz)UTMFg{i7W%9XE6~Q3!(CtN`gPZv-Cye|^^Ekq);rky?Y^GA5BHtxZ|UFG|7gWs zxvuhBHCP?4URiyjDi5>_Y#MlAM%|3T86z`Z8eBH`%8++x)zEi`>xNei|8AyvW_H%9 zS$EHRV%E=R{c(1~>^ZYf%zkiAWX`5JUz+Qj+c)>*+-K*$Iaa0T=?L^vy1u`?O*gyiw%pHEk3;XfyJ*aX;^aSk}oYix%9`&LQI4w zVTpJntnbaxGUr2`NEUf9D_X@yuD5cx*T+LVS1NP8E+ke2o~Q`E5XUo@l{Y1lm}dn% z^jNt^7ZNH$0&j~qER#RM?cro98M41>v)gT4w6(M)ZG3ZwsP{C+qCWl9H@L=ZHCUXp z=W8uit42Pr(djh2Y%p@OuQBKl%x3QD_=SdVT;oM9+#X7Le*cOMS=!|DN|u}McSM7B z!B!s?9@SgxG@QGwYiCa#)@ijmE@&+_ie|aDxNt1!!Uk?C&J;# z$kdXs@W#|qVc#faD7+OJ4^RC858dJMvC+|~m-so^jDo;Tl|G_!o`HT2j^xrieEDL` zkuUPHBN_AL9Wl>HIE=T1J0cM}JQGIlRbgLc%1NbFrfygAA=b>q+xef!HsSK=lf|-6 zA5E5h9(}SraV#@Fo;fD$yM>OoaDFU3ksePUJBB|K>0|UN_0LDdEod+JZkgwKlB0|G zw|G~Ycc_JF7dne{3whgRhrAwX>G?%ltg0#rmRN@I-z5)Yw>Nr;_B}`&0L)@z!*{ zwX|I6DbznHG*EW(r}+Av{QPv{_tv4DM-QWa^t>B&pxpQaRDkl5(#B)x%h%L?iNWNE z`f_m#T8O?-I)ZVlri8AIE|xqv4DI}z@jm@j7_fA_CSN9IlFv@-4+Nu zFt}p0QtWEYmbF?zuo!Fxt25xM59j6|Z)y$X_N4q-r_1S#XZ@+w#=1JE$7=O#p4rvV zo;Y4?_oc0^MvF$!X69wn9it=jXHxsI`2G{~&XSa3?1d{G;32TQ?t`toJ)6uNR?rsBS%9Mxj&dq7G2 zjpL|St~@dEg!~zAYpX|oBpl}RO6d}x7m-sYH`ZpVo!>2=_8QYXC7Z|9A7S5w`XfAJ zY-urur*03IN?~E&)JIK5A>TfA-e?f~>Cx(Vbprn?_($D>dfzQ(Fc%GE`BN%s#M~2; zF}))yTBcqKmtbrc%GKXwe*?7hR^TXlaz=>(sD9d^wk(t%oDAK#dHK2;UFIm|MJH4m%p68iL-Mz(aDW}0vo*~5<$sf z!SyO0;@?dbezS6NBVaK2wKASPsBt4ojHBMAd@dw-+*Y0yN-l4nrfwn2t%A2)>s)?m zbwO_Zti+0w_v{Jv>`4`xs-3}}O*`j$T7FO6CfM5&v)1PpT;CJgbI(cnJB`84YExl# zi)Zf6P2X4hN}WeM7#ccoEB)!7oSYPTY8SX8 zpRQKND;27~(gqoMX%#6I)kD@0yUY88%jI9(aR-my@z3AfvgMnbg&t(`8T{1v-IVeU zcq2G|RG7L$P0R<7>O#J63jLV%K-(_x#3F{^uYdd7-#+-k5Aqr3&;RWToYeB7wxCrU z9FCt;>Poo)y({DS4CJ8$(lAVRP97^JArvtyNGQfJMYSG%5wpaT1mgnpa`+%I%SB9` z6R$?()8R8=8s(`MCnu40csw%6pB|N;pA1ig(It>`BVpN$d3|oATIo0$jzq$@XC^9@ zNj~FtZ#e9}P5y==msLJlg2n$DvcB*NuMM?FR2^u0XiRoIr^<<^6Jfsqj;Nn$v?VdPdu`ic5`K|BgJR)pq z-X))k_08^!Z4?^3p1JEbubb=fHV8s}b8dMj&n?e2BNK7?h|?(+gf+88%BQ`M%W4kC zuNUX66$+x$xp9TKCBCyc))&KXb5WePV(!qu#$0aWz|hS zYxM-TYy4NdPvQ4=NVs80R9{|YYZNOTJ66PW|yN9x?vn7e=E~zP#s8!*lf}i?-k6uk$qr?HW(GwWFoc z5sO}~6DVZyfbPg^7OMpBP?uRQhDuFj@sq|lLklG=q!i?etzeN?)!fxlg?k8U|BsYtqi@C`N6x!q*^8Dl;`BlUkFOe?%8)m6wZc z{Cm`nI1p$I==@LIo|J!@lz*1^XFB^C)*!KU72Dp3u~XWt2P*gR1Jfz^4EfC@Z>C>0 z?K@|H#g(+$Bwzt>|F#rK{}k_TPGfl{2<>0US6suVYJCZ=Z=BKb*5 ztk&T_A$$C|$b~d+tEMTdDO5E4T+={TChBxXGhGA2@16=he}6}PsPG&JQ&lDh$gdYy zrLiiR%K!x69V$CXf~9ymA*nBx(7#PXy-zEDKH0uFn_WEXU1>d;u02W5zahK09gkHW zcT9W?>)nfW-hujuv{p@4Q-p@AX!T%t8f^g@JQQ8DXU27xEz4Pg{p; z+K;c6k7rYYy>-j(-CLIQgoHP;si`+FT)oBPbG9FT-_iZ+`-7I;vdgZUvHIiJ4$AWf zNArR`ma^G1v)Aq{;cDv5=_~XpMiUsH_>dmxqyb*XKJt#KptI}%mIIp0m9QwS(5gu5 z4DooA&JCzkD(9iH#IjrjXUdbw!R;kHoWOHEsi#QlqgPeMcbe6VLUsi04TiauV}=HK zZLk@Ot-(02a*MISHaTtsM2Oq@ryUK3W0kpv20Ky9P3p0R{GN`Qv2oS500iMN7J*xua;*XUYbHNxSS;fsYSW zhcZVphvhBlBkAGFaJnSqM#mzRKsJT|n^-nbi9o{;{^qLJTkXzFL}NBJxu%{N=8NSg zhtfxm@Q%ZoVfjhEXc+dOnvG=-_@@b;ei}Q*74}F-pbXYaa3kgcsCATk1s{wdQ6HwP zP@leJO?nM}FG*i=yuzO*;U&+nf)!3yN9B2w@_haj?@eEV$7(u$FLdR3B;wF{Re;V3 z8P>NNkJJiF6|{X}bo4%c?zQx5)4$w3eTG|#ZuD)8?X~FXS;zv&6I~oDLb(90NpYY| zD9cGj&Ox^Iau12Lis-9|A(1O~3m+i8@E>AgxY)oOi^BFx?Ls3vAzGP0!PFhz?^*1B+RK)!z&Um-uX1cslB+EF17yMmx0e^b0jdeZ-Q zQ$)r5p{OQmQyS2c>#qCXv}J7UAKJ1NO-Ud7Z#Cr)%jD1VrAyMc+@kW||G@eunMB$N z^dQXXVj21qW)carBu_l_P_sj)8J)y4nqp@%XP>4}VTkiXU->}$AaPKwCM zPtheL#Q&FbF;7M@SX%z;Nhnn5!GAIJl>R@a@MaHLAD}gALYj)ESb`PQ0ksul@ehI` z&W9i5===|aH}LQj(lFBX-Z?3LPWTI?(gMUSjKKGQCHcuwn$XC> z3`kK5X>>3?Lrtm;d`yhN*qoq8mfMS~W2jDL}yDUgd-|Az=1Gg5*Yg zS~v1dpYU@KR6}Akye8^sOSeXx+-7Ss`TQO6H4k1pG<5BQYlNuT$wiaZ9}MOOXAcHU zA-lmGt*qLy_wp@^3tm&(?Dc!P`r{A_5Dnv`ndIa0{D7jP@b9VD)taXCXA-3K8K2h@ zwISp$+?r`~#MVcfHR!j;ATZCrY&W@@ErA)cX5{MY17@?xt#!Vx-5X}5Oy0s`C{8<9 z^+$z+kTQjMT<%bhJWN-G=8AgxBlQ6O0j&SdUCJ0bVch{b0*1xBi-BE%bHP09$osUI zfDk@VlO4V?S&T_Jo~+I(0-y_Tz%!&faAk5boWq(`<`9)n{F5vXR7M_#73kt3tVoamknf6NdaU?G{z#-M z@Ae*xi~$+Ji2P!B%==_m$WOgqckIdthgVFQ`zOT%!rN#~7V$N!k*A|Gg!oC|rBd0U za0O*$`Shf5i{7#a%p$28RpQgO9Lyd^7D_pwl}_&iq!Gct(j%^#>CVQOq|y_eHM4bs&7cdhF4^c zgV`+YP4Uaki$|)}k;P{DE`!ai6AE^Bu$hW&&_l~r##O~lWG{hV(FLhf20<*rnqDQz ztf;)B>7V^9{RQDIC{Gna$M;*PPAkuyU65%~wgGf?+_Gu6lsd`*Vx zeW4y?&(YU>7=Rscenfe+N#}83P@)x{bO6SY=D6pAw&=th4+?JtvFLs@I?B&Owt~-{ ziwER+=qTPChVQE-uh=@sZ3sQvQ4Vx z8Ob&Y4NWnj)=GeN^uNmUs(;K!)i<8t12o#i;dwXtefR*{M7a4|iY?v?>v%Wh{1S@n zbfHmjSV2t%wyy{-AmEA!hOL;HU@r5Lp|L_Iip^NDG{*H_pHA7WSQ{Fz z?@ze{{Y&rJUx^KE*n9ZU?v>p>Q+DCXwk`SL>o*s8sC)6q_HAqDbhzu11N_68TWpT* znH{>8p>U6(&f+w|jIJ?oSG$e#a5iO(eLmijUQ&sMvq8VExqs=p^=-lznwog!z&%U* z4s2hLHT%0(?Y{c(-jS&%WSzTX&f0C;M;7y+rf&%kwdgu$b~$Z( zwN6W&&7iTk9Cx)RTl@0afe#Nav_&DUah_bee$}jYrx}iNb^K2#w&EbH8^h>J=s8(( zX97h#V9)V+bC4uec$3QU9HflbO^$^ocp4IgGK_3+c3!yA&K)6MhEx(WD`(ApbndK` zi0T%Ns|II2FmrH~Q6q5q^z2HZDI9JpRBoF-;WGqHD4OrRtv4SHX@u^hgM&xAg-cSi zJqY*q%uea2e&mf;98RaB688!z{d$Mh=V|hI$+hWoH+g(k$JBmv@~TQwb5z3))F=2+WFA?Ld9F5b)!v>oc}+PHsXxBOAw)-rR+%ohF; zVd}gP_WM(!*^;lD>kiIIHz3d?k<(*EL^dP`ij;j z@y%!8!vd!96>~Je@Te*BFiGkrX&lL#?lIXD@*A}BZ>KF)d`Ecf=KC`{D?8I;S5-^~ zyU_(tML0b5Y?Z%8@@g!-3m%Tk@mQI6`12_21%&u86*&ygDk~`Z;7mbTE+V7}N zgIwf0?eg=)Zzspc1@qN6hr{x`aCr2p5Z^A}gQfrc?&w~1yp?=ae%1_)Y5;lX73YPc zoQF{o9vVlioyTlE=EK;jzUzcu3vp)^vM_H}gmUdZB%>hQ|GMJV2)|zRPIzUH@WvT$ z@e@VwnUUHGGdV3ha1qlBbdRLHOZQ$nz#ED)g(K6|FB*+gALi$brIN8?g2h|% zuUyPhs{@zrUFuDbbjN2F!HNl=sB5!kzvVUiEy**oDe{1VFw9}-Me=;|E|V*V#^d~- zV9ve0#@|)HIpu*Em}wg@aA zj*pXnNv)S^moO1te@~uy58Mjxu`Kg*@T0%CZliPuS^ZsJfp_yF8#Q?=X@S9P@4F~R z`FMU+j^|hHQ2ypGG#b@Mt6$2|1LY5d1l3h-zlin&9dN8#@uGed_Q|Kuyr=C)p=KVs zsNH{8N5mjq++K`B21?>Z)thpTPLOk$dhgxQkmpZKPL7joLZwu{8r6p)6R_5%{cAAW z5UYvBr)x+)WYB1scVossAFjfgGs#cA3nk%%ok7s)p;lpagV(G6;^LX`nFo4P`}ePEY)r}H89uY@!p{}+=ggU3P7BYR z30Hekq0q_$`&05nh7XtL&zU>#3b)JUE~k#F*zN$?{keI4Vb} z#R55^lQ<&rjk*XJh8Vf@*#7kBv-~|2!akld!apk%?<6imnhUA8WpadSc)Rf`G?D|b#40Pq<9*>ez7;X%#Os;gf8tXU9f810* zI}u(HP@Z_a@y;&!@lDCiS8YygPHwKBl?e9+Rwh=u+@av+HFe&2uAFoAexnBv@Zz~@ zRJ?@@Mp?b+iU`Z@YdBbm=KSj;>q>k1xxK<$Q|GPnJ8SN$6Ey3l z){n0Z)7^{nBOXY0(_~cDG?XY6CFmdu?V}hK9}UTEA^Ew+#s?aOt3v000PH#S(#8<% zBoBmneJCUw8s-1d*vQus2!cnhaidya6ml6qika^x>x`?0?R+J#cKS5u)kohwpM zwx5VAfDjHZo!i1Lz)0Rr4-B@56Bh%nuuWedk9j!|A;Y9D!isL4(v?vHlS0)a)lm+37!8EUjy*^G(dG^YAM!=g6~u;ZHD9s zV!n}ghN;*bMZkO(^G!<=#AdKf`1EdpJKhD1wpv5(c z6?KGSGjP9qV!VP!@bJP(GReEDfjFv(M~ZGfT?Ys1FdZGhpv8IeP#sZF*`Y;|@O`QN zRYic(9YPtLDnp@5D134frBD7U0E~X2E{MTVRyrOE&!8V_)u{vmwdzoX6@L!=bhWwp ze%KNJ27Xeey-s8vP%up`3xrahIT3jA&IluXaYTt~`%bMMyP~UxJ*Y%cD>3i=@ zpE^aq!du!{qcCp?{&RY zIKDR{4{f_~LDwI?#J~ExmtOjj@PpXaS9Z%?bKYEAFMo-@0LDzFLq%7h)s$Xg#}N9Zx~&5@4c%=ZwS9X>i0SYLEkZ2Snj&}ZrAd{Xh-9` zM&&YIXIdMpr(}m(1}veVw#gf8uJ<_2&6%d|{f%=HsimR%sNUJuKX<{bu4a=hY2w|& zTU^OlEu%iR)>IdNPp-8>^n&2@`lIiss(d`tY<7AY;z4hdHW;!Dv@~@$J?;-i!}T-g z&#PvRjcZnTOj^UEMVpnjv%QOqj69L73sqi_5!J`KrN1I(i!t0cp!QA z^nyCS3QLK8t5ZuUQV)@4M7SfL7T%gpMMk-)7nNmsTAlBQC;?7+mpXRp+H+vt(>EFz zZ_@h^E}~5NJcU6ev_2Tc@(8%}>3oRiAeV@*Y~(&2?70{sEd*aX2|yS^-~l`L!JWC4 zmv3LQGMBIRb#L7<^@D94MPA9Ijwg8MszQ9gKarYp^2k&11UiX#SL^y)s}{4tQCO7| zo|&KSF636O-hODu)}G$#hVDBT&pOgR+CErV)fx0Zo)#XLKk-N)+7oS^)1Bznb|L-} zc`E!Le+Ucsz@0l0x2I@SYAa$&E1GC^dh)8m0XB`gmoG%80Hs!YQQ0?lZ0+u==5s68 ze483D(Yb0D0ia#0Ix9`x!`)5FpKl(fRMfV^N;4_>cGO-;hw7kNwZzKWcv{f|RR0H1 zBag?l;9}Z*9N0Ww)Rr?`>(UnE;w|#&Zh1ab)vj*-RBY<^@^5({4A10)yxAk~=BI@E zu`^})-@C@nbirWIaPs$~g`2*Ar~I?;{CPt0zfuev#VlGOp&Buoo$#&?pu8}ra3cz& z!c0nP-HJ*MB;hOM+)adHih2(sb3~FTh=u{PeQy%so)-}bvmczXXu6`35zoI4jjBe(8{?d#U`YoJ@x`-y*%ZCJH&Ibb_% zK)h5dY#oS8gQW^a#C)+`P|S%%L@&m)H3f-5oj)_i5y^c2hQC_fZFQ>}Z^ zD~I4Tn&3~v*1lSe<%v{xr03q8ZsofCrtR`~D-T?2fv+g&bP^`49QVCsB$Nx;Jw6de z{hC; zFZyW0!4!&6K6E3gDsXKm5q>%ftj!g`VH58Zc<*Nr4dKL`B2TzlE#mCF2%{~q6o)AlW95mKFGT-Y zMPH26X8vnfsl(@gfEsms`B%Aob?aIIyr`C?}H6?r6#vn~@K}M4{Sr)On=N{Rr*T zRn{GWKdd+4KhzlOPpnOR3d%v8TM^3-Nt6|MW&&}m$I+9&!73b)=cCR~p$93Dy!ue) z;VZseTZgdVhR;m$KxA@UJ{?ihfw3JL8Nc%3%tMfj^nE27SK?z7Me_HNLUU}K)}DSl)*8oKw=n|$RA(CnoXjLWlY@SMaN!VjA_g8_JSkk9b=fj#v=9CB;x9d z#?eT)g5Ob~)XGJ~ZzxR^>ncz{5l~u^*AQC^k51jrKTz~>-&hzkXl%-fSMU!0VoIrh z=9IWu{xb$`7eA%Qr&_y6-+>CGu2EW)2shx$Qgzgpm=enlZbmCjSuUjc3L|E4Fj!15 z_0Uf={}+h&07F<1Yw076l+dyoeh59sk@UqdQc!*nP)j~=;U@sd2q5Hd_kFWGv32XH zY@UGk1XiH#aj}3WQz!fSp6%mrZ{3Pw_Q}Wks$lh`ucPvNYW91KP8{4ou@M7?0dCXu zlFbOBbW!f zXYd}VgF3>|dJ3jaB(3N%B@^hql!*rq6L?MNjatlFkE1c6&l>bjQzX{8vI74y*XpeH zU^wmcxPlIkR_jRT7o_!8uNjf~u4FuNc;0A96AHIAS(5!uo29{7ZSs07wzjDLn0|4i zm1|0!VY_?est!jgleGG0G!JxTGYy$`V}9{S&gS-nLWx*w-0AZ-MO&KNnp&H;9K5d2 z+n|Leam~7+HFf-p{`9g?46OVPd5 zSKks3qp!$k3(eJt*r0q|J&1=911uj;^AFPR^r`SdhL%@GKH!}`QSKJh=8e-*|Tg|~$e z3ApnG4oL9vLWnXMG!T41Ot7&@zPd!bZ$M|2Z&UbT@;zMe;=twS?#aDxSrYRV&O)zs zE%Co-h!&LbNremk^gU6`e|$dv`57IE_^;WvzOVRhDE@+BWx5bHk|h4Dcetpg9@sfi zdu`Meg%E+uGW1aB=7@X>YaGTT@MAAu1B0gg!^W!c^wf$=d6T!ucb9$q>Eu|XNDxZ+ zP{}xIEPB88ao%MFz?d%gT{(eXQVJx-pa^S}l%y^zQVrnKS)-H|7Bk@i0Gfce#7{sV zpi~kF*xMl-QAz^C*e6>?_#tDdQb!C7Ws&_}wckgs)vioZg-fR^(N(xQHz4S zI)@%?N7T{|rdr>s7}ABvw>BlVm5~Qpo#p~!u7O7o=9Kgxcn9D$3X42>KZKB&)HNc$ z7hwZ>@YIP(t^6xY^51x0GzQ`%SHXtQRN(Cf9-IzG`iyI|x$u78RqobOXshuh-^b$K zK==$cI!so>lklB~tNv`vO>szWSFi$G%lO0u%{SsT9}-@N+^8oliI{RR=23#f3F)fQ z;)$eag{cu^3?NeSl`w<|d(#V#1qPZciQ#;M;O`iWn=AFf{&~?*+S?uOSmd&Z(e5Uj zJrYV6g`k(84@9(+le&2KoP~4yTMUzv8dKnkp|-^#`7d67AswAnY10V;w>THKhr2xr zznF#ijJFY^*nw|PY=oqNoq#~T5(n!bcOtnQX&#X)-J2KTTLk3B%*8eam}qFTin6}} z^AB#^6nUO#&y&Jdu!m4h==1WImbBe`b9(UsL>BooL$2n<9g*I&pBK_rTRHg!e?u_i z7i{)ISBuFj+@Fnl{l(QAhMn5gttPL(!GH(pn=^|M za1`e2>IOHgDR6(fH-etgit;1SRW$bcOu_5-m|D6D@(yE@(rt0q(1z9Z4jo^YEH6=W z@MXHgQ;&=7Lk((LI~hz#-rpo%0pDA{5{iX= zdZX=&o1H`1P#_t14vnlX`qPb8Yv+RgnfkWMtVp`Z15>{bI-I(Wp?bd;&8%x^r$fPE z75o|gb01pdHMN$Dc9)(n_4*2Fi&fh;yt+fsVHQMt(gBX19x}>b*E#ByE?-0=gH?8F zW-_dcbz#2^O_#1`&Ax`AcD+j(BmQJW87iN*kg1n<_}?9p!3+KNIrLi-e6mXki^P4H z+C|6TcbO8QMln*!_w)(^IFwiqMeQtO3zXM$QSTL{nFp zaQsMEoq(P~HYl%)8u_{l&oYb4N%y<0+pL*#heAk|Jo8t26HT=+oeAk;$_sHOcdR!$w zESl*1B+8Bk9ql@yxGC&k!S)CGM|&Tjq;@LuD4~a_0{%nqE3RS~5n-XiZWek&M}iD7 z26RX!Fy~1u!O%#DaxqcHP1?c&pjpb(O)xkr04c=Fx)=8Db|Lm%+w7X1?g=#)^(Jog zxtrU3w;uPdP8zsL-_Y0;>dwryIqae%=1hnzvtVX#;<8m%C@O+Jssqx0B&jZGa| z|L(pe-A0|&rMCydZMhRCI@%%uhu+mFTr#}w)WTk8v~-`<;jrG9Z_Z&?O0IX)+}?0~ zUr=MThQy{OvDnxf2-nYwZS2Vf-NsI5%J(s|({5dDHrLhLn?#S^ENTs=IlU?K{Yd98*+7JMwu`N^h|K;L0MB3?h61_bgYlk@w!>=wY zAh<1|uoKm&O`axnSc*J{`h*_b7IBdT49G%@KG%_Wr!(9lt9T3?NN}UOLn5B!bLv)x z6witkQ3(%4)cf#_`&Sn&^#hxa9J}@C?gcHg-~XBQ*Jv~bt!T2fBqALqGk3c+8a=vG zW2q1NOk1~FjFw=~g58cY@CTZ*gq-#EPfGw+{${wrM6 z={1+TlU9w@(iv@OYwYrvd}dq7$_>~u-q2vw8q5Z64cW{-lc%e(wI!OfST%JGwmKeg z8LTD)K#G7lpx0Tfwz>wygbh)fysHm?;N-RIJ3H53d-4N^S9|H}xPAnPBDA&A z=6r-(?jo2Y>c@<)iW&*$)}QGOMvFIw4L>Gxmv@GlgMN?T>sp zawgorXtY^)D>gJzUb}hsn*2qPHbb$=p4HwZt0(NXj%;&%z+rESh9g{T?1uqqpg(*j z9_uR#oUhutX0dm5Pc^$K(_gJ`o}9JOzI;*7x@xL6)EFDjl%Sn`5iz^;qnmP8*-C6`g^k%;3 z`k|hjzWmTr!Vu!)%8N=>HG{0$zXc4d_ zl6Fl0#7EV@b#adp#irUBVQUBW(kVM+$kRo;V4-V}lMDNq!F*v3APWU2#T~oe5j#oF zfD89W#0BSnP#F!6B3@$z5w*1wghHx!5RsQY|E1B3V;O{{ib-f6c0j!(!NK7%ajjqsmAuiI)6uAD zZPhe7oUy34)K}?&CV4yG=PmX0&-Nsc0iS74wq;UDJA!U01N@~Mu+uBN@@BN zDw3l*4h1f+f9f^0{2^`R5DAGoZaf3O&f94jXv^M`;W>WG8{izcVBZIH~2%D zNGuk46jnj%QmhN|vyp$sg`Oq*0ydFH^&;&ag)O~i`qW?B>%Z_R{zy5@gZ$@SkK8H068Xv^n|)!$zHpIE;7`?bg$IT6 zu)UBcgY-N|0SZ(>RF-TKre zqaWH;y`m+Z(sy-c4jjF%xOBB~*Q&1TLugu6IA@qq>bd)qAFcK-3VG-3J9+Piu2~sB z|B87iSGxHFH{>#1=5TY@6W{uDd)UdxC*g;rd5jME0_IqNz80xKix{*x+AEIDR?u4n zM7lT>-9%C9gqZNXmU+Di-Pg^FMks6+FG0X+4ScF0nF=cOkzoU{ zr)C+UxJ0iKZ9~y}on?HI0t}i=qCZ-{cwx33QG(^t`i(yuSzqdc)pGsF-mR-wcBMP! zE?70PWKpKQJ+o*D|JAb0k5*+aPw&jjXideyv*`tk*7XH~S8QBgD!==FCcQ8{oNT3c z#+NM0X8Fs@(yy$}T(&d6Zj^lQv{9b)!e_ zPd>Qr@U6EV*-+9{+7@1V=;})sc|Pd>4nMl0r&3;D4Oj~+_Vf&2zkP-$FuZHv8vnOH z3tvv<;TIZ42X+nnJ%c-r&J6eM+tBB6_igCv=~+R;PxU^AxZ-DkLurN3q+ zGirgqI}rH$GlYgz6@BC-;XhC}tW&LC`KSk`hYJu4^AgSw#V|&J{2?ynb@Gdbtj%w7 zx!&inhT8NzqHA{egC4pHx!r=!=m-w-Z*(%@lY)FKw6q4_zn#E3B4hr2<$rJhjfkQwmPFI!glA6I(4uEILv0f0XK|w zZRJMXi2A`F(WW}Pz0P98=bCIti2qaKzxSeWO}{S{4Ack9^)81!V5{g2W(z(U<*F~& z2Lr*BuiqAEa(UWXlg$o`*=%t%CtKS*uBL!(>g0d-O+}8J7V^SZptA?)%N|--!Ai-J zVgz$tV41Lxy?f68)vm;ysWE7|=_s>zROxzjOEW9Rkx zp;)vExvs>0sPQ|bdrZfeC~>egKQ|&LJn&d}qVXDWSea=PzW6BF$g7BLCB0x2-{^W= zK22UFc=YfKnAYF2b5^)Lh?u1zmuwD1uX=$>Fju#42pCkQOU4nb_(2Se0h6XHcd?3rat z!}Hfio7TNT+~RF?Y|AVRw`}c6(n~H^JYSuY?CFF*xW=p7fjQ%frc7TNQTDaI zTTk#`EmaeC1Em?cQc?IxxXI!TIjBzNrbuhrO;C)Pow1q?oS`@FHji5Dc{z7703(>GLXz%OY>|yY zFp~{W18<&{-yTS1e2>EK4{h!O4G0=h123D&60(|XFc*tjtybhZ&A@1PQX|5H$8~m- z&1Q00jXKDEQKQvpVB`~QCP9nunjpDGWIh!L5RBCLy|sZMXH(`gKKW|OwAP7lKzzGI@uICa0`d-y47NQ6M?%QMQCXwbpb$?pMZFze`Lc3nD=?gh-pdC z9Yr(A>o0bg`^Xt4zy(CkFrlvxUm5s9pMOzHZ+j_U>K%Z;b>)qpSecst`hOf=a&OP9 z(BRD8xw-W}&6Hz<`TD-?dlq`yR@O&7`1%Wv_YJgL0>bN!@?U$V8V_)d&gDsE7kWCf z%kR9bB>d#ylh5weba&6&T#Ymu^>2mh^MkSS+BVO^J=_1)iO+9(Bjtc4JJ7GlrjLpr z5Os)9iNYf~%ogJ7dK(q5GnOh?5f~8`q!x7HTCZ4%n_w>%@~(>?Xmeh5Cv};Wd^&Ya z-@&YWH#dIH-rzNxy$uodAb-8i6$}MjCX*`=3cBiAEItSRKNN>ASUXzEMw{E~wi#;& zKH#peZ>g_;%NO-}qrQ7A6msX>>-G@6Q}C%qs@!oMMkjN)1cz~{1DVQL;7d@?R2 z^xTKY8Q>-pSEdSdRYfvBSF-K?b0@?6t%Ekg1qT5WuY_*dw`2Z5s+ z5Tk4ZRKzq38f=Fn%HC9UQls#x)dKS zhK|v8UOvEZ4`i=wb7SPnlr+PQufYPG&|dh5YN9N&Pzryvs7$@BOj>OU%% z@X^aaM`mSbcnn`+gY6{_#SU@@p(9X*mwSEo9-- zr$BrtPxz1x&f{8#c2pGG+Taf)}8=a}%u*npSUh`eOA(Zl19CuFeZ+{y_l72WP`h;s>ty>7~z>0`36o^2AT0}Vs zk60p!`*6Y{q#W$Y>nrE=I$~htY^sHwgh(q$QXq1^0LPxJi|el#Jp{`4iI)(fTl_1lVCCY! z!-IoYLfgzt6C702(?HYB{q#xJdC%$RpMUr#PqHod@LR~|4epPLe{1_ED737GQF0#UA;YXtW z$Bc!;$0FFd4-dz}gE(0QKUeCD8gtbG6c)VCuw0y!zu4>o0yP*1G!=%WlzRSmT$ae> z@&k_?yKXh{2^<_QEg8PGxifs>(!knFuj+Q!?+S4bpyUk{PRz=5Z1vplMsJ;hFAdPh z8TM&pXB98KFx)v-@9w_pQt`KLVxHlshdn!Tb87hSbHD%!n9l)2b0G%|?f*3gjFQ6^ za=;c@O4xFz#*c@lR>%FaRt0YN*JSOOeA21qmTSj{Tjp#}nF!82LJLdYtBg}2oy zZj0Sk3&Zh!_gO2e`QAHkpJDmVhg=Uj^WPSqV%vZy{_f+Ci&@s%x@s$Qpn}x?0?*b} z7yeq&+b0O6E4;CocSZMg*Ibudi@lV^h-~pYi?So8NREKQ8Qxj*do0Mk4gbKKz3d{IGw7KoH;g zXW_H2YG%*kjrl!re$sk1j2I#1`oZO9%VqkJ?iut+z-LT-9@(VyxLGN?nBDmUB{AAU z&LXFErQt<(IZrWu@$CYl+eX^oN%kVFc+eel8I3iOe@8J%6k1Ad;tDueqFoTN?&|AtTymMBP+bCkGspfCMQH6?HtN_OyDg)7AU4MZP!Aev-|zOi@w3=~o;gE?#4Vhyx+7Do8v)Rf-VAGyEufk?8sY>MOz^$9-A za~>0pD~CqF`8?+}dP*={oQ!;wGmubHCH^Uykghm@mVgin^;2=8f}}&!8YtPjk{?Dg z8*qvFg+@dgW*7eHg3ItPJWJV$@U74jJwRwKyrLXsWxZL`@i>RUy z;w4Q8timQxQjmhYZ+Hro!5d57Q3)L5Cx2UGgXA{mYc8c~5g7%4n$K*MQ53xn^hNda z4OtJ&t9+fw=JAzBgViO2CDp;U+7gdJnJ*V~t6LiSw=?ICf%-OaU8-qgS+vk&FLal> zYTK5!);UYvh4z+c*~X^#Js~&;%l_&qD+5%4eaBPMzC>UOg~{sE!E%%9%54VV4VJW* zc)EtK-?-N2@%Ywmyna|rs|~@*ExxvVn+m88076u@y7=aB5WKC{)(cw~{^qaEtuo>r zB)Jfzd=SbM0D3FH$1$bo12$d)>qyFurWg~hlX4!tWn?hgVnu%OwN>Jq2zvlPD%@ON zB6!M-dduyR+kNX+H#iKD;?n$LuZyGFfMSDhB`&^blq17#$EvvSMeakpQLvjE;&IPs zqIWnn1x>5hF0oiXlu2MUCjr-}zpyj;7@6biTq!&lOTeeGk8`WQ9_Lz8G5Xfb0Zjb< zk!eR@8@R|cFw@Bv<+5S1?6Dz0L4!aEPX=*~AWb~S4vRyOl|=m6Ujhk`N*gY)nqA;O zQ5lyR4GNjoY%^;Fz1k>>FNE0!W{ur?3`&*OOeUAjBv)qn;l&soJa*aqk#T%B zfzRNx#lCzaKI^vllp5IjN~0Ud9*y4kRX(?1qW|p{%z+OfPdtbo)&eU!fm%?XM}48M zV?HRQ5Cc!kr=XqELE%Jrp0OC`;Gr1!O>l20?F4clz!-87C=StFPvZkVvU*A_aB?$? zoI)JpL~tiyZQ$nylO?%_ko`>FYapAz2L@XPflCV8!0Lh5g#6){;XqD7)vbqZMjkf& zBh;CLWtORkIk^ZRH=)(H$j<8Eu6oG@e@DJI)Xc$+jwTIH{F-||oi2*NfYpK>rox%Y z*KM+UVZI15_J+B_am-m!WMMY7%YZ<8{*K9)t-rfXaGnfaYvz z+^T{3iY&IdAI2lT{Y+=gH{9T?@SB;pgn8{ZKZmcDvAfI`X7*P&zvZ!Mwd~U-ug(mM z!~1EbwdEVW<*X3j{|@hwO7Wdjb{M2arBy3V#;M=W-HZ(-UjFeLJY^8K5#c*NBu(p_ zHMl@iR=17uq&Tvb-@w?Igf2_`N`4YME4H1Yz_L!WzL0sg{XL zcFSt<+sx=G2^PDJU-Ni=hUgKZNUWg(P*Ate>rjdyK)|%qnPbc4I)hIBGq~Cm%&b;3 zLFXuN83mp851U_=v$_jxIE2w%VtswuyTSW2gUV!5;XpST3$c?Szfjn!G^jx*WYJ#` zpF2fI`472Xua`6P^D3*x;4;eSc&g|Al+#0>0MCpEXj+N$yrB#fs1o=JON^8}g2SMgJo(W<#uV>POfu+XPa2`Bgj=hP7K z@Tzr9M(}_UUSIqL_I5tzDQBPYMc`mE-Nwp2kKvdW@#jx#tp-30QM*R_^qUHmO7SMY z95~NYvO92|Hl9O{aSa!t!^J2*fwQ2Xv5BbKk)VyN*+!Qz(E3*GNceeicJJxq)g}7; z2X1mb>v=(LP^+fCv7|ZhN8_|`)^**zE`4$I3*v{T@2(iCd9zt-_;0_v%{%q7!6Sdh zz2*ehah{TuLx&PbpCa}(W|PW+=VAA`6FwI$ASX$@VINdF*9v5-Oa z!JUXfe8SU=?Nr$Zt^%m+5R@;)yM1LPMe8eK73+&i%6#3isaHMZ|G|oN5Yz=TzB6^Z zOA3REmtR%{3rlv_o$(<7_)51IUZUU({6M%k^Lkzz^gI)E=@3UV0l};Srp*R5sRTZ7 z7*bLutOH$w_6dy)!?*#xl%560ik5d9R{qQKwk>iwlPfl}yY5`MsV3aGjP34MnF2lR83zp8NXa`W3E1Ona#D4g6ZFIxW{;44fg^kvIDPDI@ z_sr%0FJ{6a4HPvY0y6T@W0?wJ*(S4U>Krv5vh<#%5f5rS_TDr!$Ehhi;zu|^g>c|A zXuMokGS|2>&#&0Mnbd%6I{&UgFYfdi8N_SXXNAQQ^=S75RwHh78fFbP=1;K z)5ZwF-#jHgDZ20-;fZU#M6E{Z4%|l=QuR=BD18u5_(-TB1cR*Xi_QvDk=i|R+9DuX zqonn^Sm;X|zie@^@-jz3Qb2ASjx9I_G}<9sS{W~=vrYoSs2 zkNvSMs%$-f%2%~|*~G;~KSh<1gJOa;ihqu|o)o{qzAV1uigP(9@$)%g6nrkKSEmsqh)ydXLdxR#`5-ww8~VFUbxF--cBgA-zwf zbdZim#td{oLXk8zD?V|ni@kE7p+#${SmSVQU$rx_>4IZyj<#4URy$nVq%CWNo$D{$ zaadOBFRfm;^QJ4Fz2=HtnZMt{=kwj*y(hba@EEm-a$E>3_fE(}3|#m*A?%tllrcc@ zgoPfPXbFOD2rrFYX#+43%At$404o9Lq6(>xYxpLr4R9!te!$HB2!#UZZ18$@Vj5=Mo zW03f;VJKU>1PB1!K8~%!6vkzP8m_`!Bukc}j;vXgQ`y0s+SH6}1BeG)y=Jmj$ygPB zCwW1{8@C@VudJ%NVAGx*8`ket$JG}siLdVJh?kWW`_rqsfz(7Dk-Gxzj;Qa#-CK~l zw&Z?k8&(uL1XJ%_zhTE7pzW$b9C&p5sc)4W-1hejnU|{*ux_ zB;RwN#D@!OWPUzN2x>{Df4t5`9?Nl!qJ&jb$kJ5Clj%veVKV3z z*W<$l>?L=pXppK_%n-J9q3981a7&I1Eo$_2$=-#Zs1PH&0(Y(rnC=enk*$NRnnT_r z+k>E8j*=>5k;8_9+GpcAk1oQj0eAvG5=TM_O zL9fZ=4cdc2%EzM=s*~HQkN#X72PMjF0dbsd5MTHeT7k!}6JO};Jem9Hz;kEk%{Q+V z4&W#_Kq%-ncQ8-YlI88yZUKk*=<$Hy2n6PSUCh3V&(Hlj(8<1g@>k-yBnFkHzQJS!_pOO~p@l@Jr|Dje)sxxSzFqTTy9uUj*e-|pDHB(`Gf+EtbK zS+#cS1uHtjZ2*ze&?2AGDcKnGEs5c=-a#o2Dq=a1ypCkd3hAW}QY7!er4RZZddT;n zs3UFQ)t;6_qNV56+_U&5Ig{vk&&fiNTRi6+xt7R}0HqIdu2D%b^uY%qp3glaie;3~ z{bMA3i|^64A|!n?D=Ok)08q!^+q;}B19BQl84qk36b*^TfqeNUXns|g^BcexI*Q8C zH^N%K1N$S03#2xI{BRES4#c9kn8SQ_Ky7tN7CB%UFvyz`Ac9I(48^vo4yZ9Gkg%~q z^Dr;!L0tm`B7_1;;4~DgpjXz{QQ@WBu0WzSH`1zr$g!)jjJyIM=w1}CliC*H2gVvV zE6jK4f)(MGS)Iu2JDJ$4tX z3D!C_K0`YzFR*LXdeciq09D#u`DG@(CsZ8~_r!%dP&K^))vOL|8AQJ?+)@|`Rn)m` zXNOjr9i9Ta%Via3udRr6TmAV4(C}LI-R%|O;VzA`(pIQcHxv{WwHwS1y~ZJ%n{gMh zqJjpsvd~tk)N~E6ffvW2(L0uCqXtin*HEo)jF#5|vL*4I5t0l3Y`mbzC}FoGz1#}B zf!J!hsQSAN4ty1y83exs6Nw|FsL$ONxRs!#TQFZK{4QO28C_GnhBMJYSC!wE1>ZaI zRh_!^rZCLDy?d=CZX;X4CYU7L~J$nEAG z=4A0;n}KtF-7PnV<9!DEQf71)+xj|=7seZEnuFJfuV3tN6&AXE#ct7P>TF!HN*A*P zmz7#r71&4M#N%9a9MAhS=Jhj(7eHz`aE|CP*>o6HG^df?*354D@WaT-16S_cHdq_? z79Q#Ay=nie!ZRO6Ka8C6dM^3gA*b_--Mv@%i~c#sy+dPLLf1FKch|*ruic1iFa207)0PcqSOH39#^T_xZuR@& z(;1$cicL?yisBZ`;&<5WbI*|TC(h(*i$>$uXe?^^RGd-^i2o9%!}{szZkd7dg<`Rw zo3&uoxG6>+mlzKva5*By^{euhVf^I8eIpn7v}$pzG+Y~~(+a`K%QeBu!|8!F8X+S} z(?TQ*$ukr>`fs6!D3fMp=Dt1iI@0)5GH8KJWzZnE@;k3P%Y9~?_uaAN|!*aq730JGF@ZP2guoo zpmuTDV!rQ1SX|j~+49vb1*ZBEjrt2;fI&bM?mR=mlmFC0`^f@NdBfb%oM(WzA-7Rm z4bn*R;@!Uh+ZEbMm-5gYp3(Wy!tzlTtD=h%1LzSVFYAUIN&9W$^pzS9f|GAe@jS3aq z;9}C4&D;U0R{3zZdgjKVtMDK8KJM2+cJxU2xw#j+tTR^OtvxYOe+G9O_}Yc>8k6p_ z-RAIH7z+IUn~4uy=8qhTUyczXwslWa*ee%bCT<~V-cs$cJZNMn3o}1exdQ@V1(JUh zWRp$?ux%sPB1Hf`DV=i^yYq!#{o<6UEoKTZ7N##ovSROuQ}d zow%AQ(+U(SQVj?UL=gPb<>0}SPpk<6C(3cSQ}8E!E3XcLZ>8!GSiAMh*Z~w9<6jIN z2>B3~LN7xVAIACIAqXTb5jqO)0_Ps&L77G=ZxGu!TZ*hO6oh55_2$6#!hz0}U7!-I zZD^$s;Q9t^Q%T^-AUWxLmvbo6`A>6hhYD>Ady-OGZZGVD1& zMrd7f-Og{Xu={?4B_Rf1zMolf*v$7L_1LN3AlSs-H4v@d5w5Jx`}M#DjDaJ z5SnB+9Xoc}0r4ZB29|_#+CLiK@X_}l+YocJKKG8zr{8K?ot}K~er;dZrCqcjksW~P0aThB;$yyPXN=9pG(ILfc-gUI;x8`T;TDg%V;de@^Mj2W4tMow?|*P| z|LPfdsn}0kh0qmD3=V$qZ{*2ggPf9m7uT1niZt-^LH?hN@|^2!fwBhp`*PcP;sB(8v757v%q+&*p^h*ZG!5nly2ZlYH>& z0);-1p|kCvESmf6|8_pm{9yw`;geUu108_=gZfXn#0~@-K?TIME0u$fcX|m$2wEuk zF{e^*-oGtgSN(5jUy&XELUrA2JY2DQ?L~ZQ@Hor& zczlOAF2RCmLlr$jK$#fWsepk3iEW%c5M>Yin^R1<-UN~RtVn47@8Fx7XG10Lv7;jR#A_v3FJT{ zRG%wU0tJLf;HU;6mkV^CB@BRxOT9A8L-cepLmSbv0jq+#IF0oV6er`|UA5>CYjJjK zrn>lAcQ>xppSjd6<7)=-`oaAUIf$=?Do0PH1N|{3X#Ndu+&jAk@d>p{IbFF&=~4sq^@M-9wvH{Y72X|;I(!X-v$J!z!KxXL z{}pOunD$k4S5B+2?+&p&R>Q3vU#Pjaw@2)gtArIV54CJfj^sUHNUO;ZA(SP_ybSe zyiw-$g*OhS2Jeb@5zdxTW$41TmF|^g?X}`;abX=(76WS=Tp}dP2U?b8%6)#VQT1OH zzlcBf=;ccs`|iA`pdjC>ZW-7Z4vQy=cdZuHqYJ5e^jmI7EM;wb*-9oCXKR-bY*+G0 zTqt`7Ts?&S%agQjj79)6(eIBX1YeqbdW)}9e71^hTK?#Rhnn*fcU-jf*5!f8$M4^Z zZnwx9#=df@OGIIh%j$jAnfo8Re#6|+z4twFsJP>nZPX_|4#|I!izmWkL9r*2!VCit zM*7?vRNaVB9p`f!O1c>7kt8!pkV71&YQ9us16-rPh0!Qm_@`8;5`+`^dz?;{Prrrt zQH&HUb7YnBLC;;HG;a9+aSVQtte(kLnFY~8TntOw#4t9}26~VE07R@{==JAzgogYP zYDy#bAL=LlK$}60j~O5Spk70Fp&uaL_&(sg%>7_=N#jf6r*`4oR>7N{2m6f!+`zyN zPZ26+lS{_c>;iIvmn25mgEM|3r-VmpI4BVoT~Hc#Scx(4aybgz#B$2ozwm{gqqi6T zOY!YTd(Jf<`P}DR`<5JSD&A7ubacr+*ZD8SZMYTru--rIikgM4Rsqc^;!*b>{i>0Z6o;Wj!;&1zp|IW23DDaR3$ z`Uor?U8t~~r>K%sp=>by5`?-5E(DNOKzjvRN3KHdAAlZC7aZ8g0jF}>CCGE7R9EDv zs$eJ*!y8RHFp>$f>h5jpTVTxwTACX2OG2@@9h_SE4NWZp*tjk0x9zPK?_u8B6`LYu z!Lndv(+Y6SXl)9A9Dw@5B2!(pzcseZ&vv$dhaw=X^EQ|O!~m%*Zz z>8(2Wisb&2OWT|Kwys;|6~6pbL+_3aD~bwSPIu9Y4LfS;8=hh^V}Vs`)Ch>(1l=qEQu(>JkNKwppOB{Rz-i>qd zEyA)b$6_29jM&a6e7{4QG7H}iH)!trU4(|l=)^Sq2j9=`5>K&49Gp6kh-DUaV1N9! za~*hVp#v1Zkm?gst~%B3Chs@-7$H)f3l*?<0#2^d`a(TG$3h)I_$|3zAVq~r7;CzW zSFQ!6@uG6JJI~coA3)W=3wXWshom3_Yn5vIooU!v&=fd)%K=|Y{>4qg=Szbfmp-)p z{7SlWSD;e*B{!}=zn~x60pC9rG-tWz4_H&QD7H%075CJ%(Y>C>r4hzgswO1y3gE8W zRD?Ole~3XkQ8a=g7W2;}=Ex>K?gI`ES$uzvL&hL=1JVYMlxGUX05%+o-ymS|h97m} z0IogvgYPE)gS3WA6{Mv~5ER|xWgy`3ZiGJ)8VtTVgnLhl8bgmDaO>et<1pk9u&M;{ zHPpcah=};q6oB1Q;Yqv!9i}zDE^>L~is)K|$!BKn)z*HU0_RgG8^J465Nk02K+|B* z`QzHi<(Eg`{vcg$oooc_QXII;?Ns%O@kA?lv?u`-erZb#vfs3cPB-p{BtHSFU$f7nU`%?S+yR=4)m@ zimoqLHE!PCVeki8fr~|zzN(hC`j7)Rt*xcXrxdSI7DZcH8!B8fOKELuYi)_fSGKBE z=BaEvU04lNSaYMVd2TXCV&`vWV-oQkeNk?X(!HZKk+LH4xb=-YL>4~%Q`8D0;EM=P zQRM-sTX-b(nQx^S7X9R3&+7HrOzxn2+yz7zw7 z2Mq$wJC%cQe6>!53-IegMMv0?g!_|$%|WOSID!6=$m2-D!?+||0p(D_bg7b{2GFUH zsLm)>3$QW){}8JntU?IKDF*Tu$?NnQH=mAxS&s$5#Z4gMp+oUA9GQNpC-f^Zt@Gnk z$O-#kD~=9hDa6PDOkqwHyBLX*g342DUDIc>HhGI>D@qDf*i>4Ve}!3T_abFjP-&Iy zp@zMy0}5FL3$|7P7E=ZC8+G=oNU^mlxTI`r<)i`%%_d#Ecv;L@p>I_M7C3Z{>wD_gwrL7YcC${2v`v5jG`gaYvvuu~klmoxMT0e1^Mg%n?(Vw6 z8n-sTRPebf{2DcDQK^B@QM%k}twyQcsPYvTFNwNw1esD_?kz8uJ2%)Wd_c!)OrD6# z>ToIZwMrFOVYNV01)OE;J(`LpARE`x7_kie0^kepuWV$h{%i2#b!1+`)N| zEJ@Y{ch9+F?l^Z$;p|^J9ubeQs~+k2%baELQKjRaf*y0!C0*Lx^uVs3ryHBqtedGeEnB{R)5?yrXPJD7IC-uP2>bTz1IyO! z=-Rl~Y+NxO2n2&myO)ZE=Sqs;mhtOF{LCjH!LSx`$%*AnRyg;Juz7ADYSj**^&qjp z)BD_Zk#ZP_wZ9FTI&@U5(hCb?@PCe)x}?Z!trX9LxZ!bCScK41KPh4gD?x&vp)%Zm zenK4dv0xDK)1rKrJ{LRv`S}r00;YW%$EYXlSN+_#U-`ti=28Shc~q3KJ(gThG<9A` zlTQ7dy)Wf;7QpvZMrV)II4Fk-#MuHWm?&Tg!%&AU6dV{iN@P{0i+%tVY#m}FV{g-ez(53bCy;S~N72+{2a{Ibyao_-fAdPp7 ze3IroLBj>nPt@2`UA0$NUtP0SxozdD3wNwvTMi_^&Vk--Tk0Bwr#4hyRdZGKI(b9g zmTf1uZKfa?y7PUqw=kxNmAaKi6)Y7DX)G}q)wOiD(XmEVnG|Y7Bp0wnlb~S%bP-Nf z5c=T#IFq%CDA~A=bw+P$Y+rlLMQT|%WOv1?Y9QVXwb8T4!e>XsU$QG%eyk|K1a)VB zONsv%8sUUS+#3;RZuZI*@q=q%+zgc4Ot+4iNw_+%Jqt*s>v(WM+S^g>6AY_t_TQgF<3zy9V@0^PNp*|IrsA8~Qo9W-y4C!twArnJZ z(ky(f^cv$ELG4dUwGWm?Eys1HpXe-bAK&Z>teRd~JaKgFUgOJa55x|vyhJ!_692Vy zr^&rrm)~I;40gCn_aS`x)uz_Qu6s7!y;1yIoaM#DtHd{6o@E{4heRVza+}X@w)kHi(RcXC3-*4F_-d?a-We}{9@`y}jP`wdYDU%y5N_J_{Rs}Q?qc&!? zwtH`|2P5{sb`?OSDm`NXUP64@C7fVtRZZ`%ixpsWV3mb;tIb*k+oM5zTcdbKW1{7p z&)sjpuK%)h9*iaxi0 zJkDrMT>f3paffBFNV|ah+=DzAaPN?R2KWj(5jzPXD7kP;NGE|LJ5WTxR|w1lN7ptr zLtrV16b3OXY@xs>BxpS{H)-fsGn3#7!C@H!1jk7^Nu(R2i6kTfi-u&!YOYy-rM@Cu zz0F@5v~E6_UEz>1Q-RM~Rh%)?1sQ1(@U$wlT z%waQtJ;IzmP??$Ay)P23lp9|NHpnx9PYWydus6crC@8Qs7MOM448JN@>U2tIcyeKv z{_3vlYmF>eT)Z<8*)%z^#uLE(M`29+^26ght-%#LY9e#@$-ow@03LqXf#IEcm-Ykp zmC}xSx4R%TTvy!SnFt@)e^s&Qe04tet3)2PSgZ1o( zCB@>?(mvpecouUM`!HbdSfg+Yy(gS-&#f$A`>G2wxqhp&s`pH5)8njsiMLrt=$tW|DcL;QOW-MV4jrJMr?e_+59!m%a2)%VKxm9pkb|>W@3mPrZR@NwDU6TuY!(7RWL}s&)q5 zkhRurt6!3^FE_4Awywx@!lMGN460#-0!5ck)org^)!ekThT*Mwjtsbcfx5@-<95yc zxPRp9A&+~Qs8iYf5;@S{v;P6H*7+RhsSDPuYK_z$yz*d8v~A^@4GsIsqs#7F z7A@ab-x#gRZz`z5jgf4cs5RAXs&nd-sikVw>P1=Cck@kr$PxIhE8E}7TP>zE}h=uu;`ohR=Y(f z6Le~|%Tm|e+&AL8YdAW5Pthe8X{m4OZW7<=*}jju1G#eU{xtpn z-yPgbtY51CqS|cxeK_ciJ%+` znh_}gVso>xZlA9^HWR0(IEcilyultQNVB+7>wNKP)Yb(ZHyFz3dd$~ADuMQWE+aWW z;3--$5D`Qb0`enEArc$E0K7nVQ2@$UtI`mjodK(dQ2I$#j!yWXdLs0P5;jGvP{9`1 z81cv_RybPR7m6DGgT5@}ry}=FIq#k{3LKX6u?~F^!Mq{_^DaVQuWp{=juP;Z7XSCX zdV->dMQumA>cHp&4w6O0c5tRh*J^#PUQ`s=vwzS((2rr#BB=#)))jJ4qS42@RlKYv z8n9Xe(U$nibIk`~(0x+3KE9vykq<7L$4FD0`UHGFHppVa6G8A(@EqnOFh%f2-bC?f zwqphU_02cWVZ)HC6qRihEYf5z*lg3jW5BfV)Zkxrf_Eq^zkn2XPGvtE1(_j%_ zh|gZmz9ufe{HLFn=7bav`It{#@`VF$&qp8T03UbrV-I0qWCo4{Uk-bh{3L_}ISZ^n zJ+9Nn2rpKJpnV~s&)MI{v&Ke$>@+u$sLyO{)%N{Oo}`L=^qs4av~@T&?f zfXJGFB5P3DK`2dpiJZa>K{4X-2RCcZpH3y{8{tr(Bf)q8bsO+Ogb~ig2vvbU>8;)} zmqV=*w8pYhD_i0ybjUSYxudYuuaD~*lzQMp6&lbADm7Y`R5(hU`8JKZwN-D`=<`bp zl*)FM-eNQBmGoo*kNj(Dhu5ZaC_U}f#TH9Z*yHpY706rF*ipz!u3%c>M^uB-FZNs& zdGW=_6gw>JHmYftD1Zj#L=Ln5C*0VNg1k|msS zGoSb*K9Dl_2YE%9=_2CUh9lP=+Ep!U*n9Zesh&3RS-4ze6_M`yAD;{?zx8(e|D58)VhH4vC)%mkZ^CE!%QXidn)6Ad8D+&bfY(YkUJb$0n*k_FIm&nWFxexpG>{?6GjZ);JJ~LFG26}d zAeyk3?PCen!+KdC6oP&>zy{e6yMzt15jM)kSc;9K7)qLDSQd#j2S8eJh)uG?>{50a zn_@@U^gQmyMf(^a*;Q)PqACrt?VefjeVMZhTYEYV4nrr`Yv`i zyNBJ&j;(HV`wIIin`Sd8So}}yYwQ&`V86j$W&g~+$-c#2V<*`u_Al&T+3W1v><#uN z`#1I-WaNF1eV_e+y~R$me`h~rZ?iM(9rh#kWA+pFQ}!-Ofc}jAC;Kn_heun`0vTn~*1f8%01hNzjNW z1r@ktHG)>q2}n{EjDkrp3rGqVY=T{IfHl=6CYJ5RX{^C*?JCwj9(2QcZPJ?Ug( zcsw;Umd(f#eSIp-*TJC!Nkt-^PE2a?m^v8kNo5Cf&A!yZv0QT`*`L)(JEVsO2D4_V zof%Dl^^5j9Zv*XZS-c1TjB)XniE*{`a$;QBgI*=m@*Yfoc~5Gj4-ctfH9d?b(!(k= zMv{rKz`5Q>A#nPJvJfqak?6$Ofn<89e<<1K{Nz2{i#GQqvWZ2XFn#Q;f<>=KQUiXdTQX)3Tn40d;R;BstcXNE>ONXeK$9L4R?ndk2%f z!y5iLGL*^c(K?V$jqz)^@Pe+NVg4O{?X>f+CdLiDL+Rd;WVC;1WF*;V%)LrYWJiX^ zlKR}s%t#_L$oHHW%Hp0T(tV0vY|Ciy(L_3m+otRt85$p-#D)}lhz-~QEh8Q$`gngv zaAJDt<-|C>kVA^&D^epPiE-&OTD(Z5qodfa;7u#U^k{M{8|@p)^iE_*{Ht=COn4qo zq?6I!!Nk}=GK1}78QfYmJ!cbRS!!g5#wL=w-gFZ8H`L! z`*5Nfdf+FirW@RYORnfk;x?H3l9}ObYJA~zY<E(!;8b+< zoEjU$tc=R(1P%0n%Qupk#Qjra{11(1hBEr(=y-NAdT?kAGs}`3o1nhZexu3Jo@82k zZi^y`Ih$4_58wi+l81UnCi;@vq)&%|15q$EmPk)( zc$@C3mbcL3p@f<@$NTz?ypfsc!Ff)MB%RXB$x#fnVcg#|moAf*^ET59=>Ug^#^v-1 z-#U`aDDjw0rWO4oxGb7}%yNEDRJ=8TJ+Z|=4@nG8l2^(3SE+I641G%JJ^8>81knIy z4(1d_Nme^R;{;=Fh&J;kjWG?iaoGlvW@?R3Kuo2R`zMl_tN|MaCwlm|q{is;{MATS zDK!-XBdMOGb|4karf8BSRRifn53aic&*Ou5g=vFVgP2EI)gZc(N>9oMQ=>`KU@ARy z7-JYxDUA!Jz=2a)#n4z!>X3YBtUslJapZOen+&t!3T?W46JU+gCzUp zW2tOX#b?V=6&*@8ZY=%(x=h`iLs%>{Df5FiQeJFKvF%Pzzyn6 zjA<~0FidH@jwdEENhLmo%P$)r8k3J>vf^Q4z<^^y+T${jh*#yl!91QG!dT>2Z~p{c zzMMX*#xo9+om5~jW|C??7IAqL`zO$CT^iSzM%=+K8G!k#!xX~}iQ*n-wCQ9& zZq!&W1SgvK?m^DA<8Ke(ktf$h$$v%8L+B9M2TbV&QZNnFg<38cDyz2{696iC!%PP|t70IkMol0eK zC_a&;@vK|4NtVuJB6-@T-K^$#HZhn^N-@x+87Epij%C)5@mNdu&Zl^kyg0NqJ^+tXGyz45+h- z%rH$;4Gg6uR+8}~T8AJBhYlyT*+E>hXip-YL33iXCquJQEj1^`6y(mE&`>*i5JFjXIF%ZuTg;zvTy8!6KTI&Tu>b%7 literal 0 HcmV?d00001 diff --git a/src/vs/base/browser/ui/codiconLabel/codiconLabel.mock.ts b/src/vs/base/browser/ui/codiconLabel/codiconLabel.mock.ts new file mode 100644 index 00000000000..37862376c2c --- /dev/null +++ b/src/vs/base/browser/ui/codiconLabel/codiconLabel.mock.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { escape } from 'vs/base/common/strings'; + +export function renderCodicons(text: string): string { + return escape(text); +} + +export class CodiconLabel { + + private _container: HTMLElement; + + constructor(container: HTMLElement) { + this._container = container; + } + + set text(text: string) { + this._container.innerHTML = renderCodicons(text || ''); + } + +} diff --git a/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts new file mode 100644 index 00000000000..42d38948e88 --- /dev/null +++ b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./codicon/codicon'; +import 'vs/css!./codicon/codicon-animations'; +import { escape } from 'vs/base/common/strings'; + +function expand(text: string): string { + return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => { + return ``; + }); +} + +export function renderCodicons(label: string): string { + return expand(escape(label)); +} + +export class CodiconLabel { + + constructor( + private readonly _container: HTMLElement + ) { } + + set text(text: string) { + this._container.innerHTML = renderCodicons(text || ''); + } + + set title(title: string) { + this._container.title = title; + } +} diff --git a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts index 63c805b4237..e7dcf431b0d 100644 --- a/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts +++ b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as objects from 'vs/base/common/objects'; -import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; +import { renderCodicons } from 'vs/base/browser/ui/codiconLabel/codiconLabel'; import { escape } from 'vs/base/common/strings'; export interface IHighlight { @@ -65,13 +65,13 @@ export class HighlightedLabel { if (pos < highlight.start) { htmlContent += ''; const substring = this.text.substring(pos, highlight.start); - htmlContent += this.supportOcticons ? renderOcticons(substring) : escape(substring); + htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); htmlContent += ''; pos = highlight.end; } htmlContent += ''; const substring = this.text.substring(highlight.start, highlight.end); - htmlContent += this.supportOcticons ? renderOcticons(substring) : escape(substring); + htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); htmlContent += ''; pos = highlight.end; } @@ -79,7 +79,7 @@ export class HighlightedLabel { if (pos < this.text.length) { htmlContent += ''; const substring = this.text.substring(pos); - htmlContent += this.supportOcticons ? renderOcticons(substring) : escape(substring); + htmlContent += this.supportOcticons ? renderCodicons(substring) : escape(substring); htmlContent += ''; } From 79e4024d11d7d4abb4332c89dfd0c7164e4b3525 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 16 Sep 2019 13:50:27 -0700 Subject: [PATCH 02/82] Update panel icons to use icon font --- src/vs/base/browser/ui/actionbar/actionbar.ts | 4 +- .../ui/codiconLabel/codicon/codicon.css | 3 +- .../parts/tree/browser/collapse-all-dark.svg | 4 -- .../parts/tree/browser/collapse-all-hc.svg | 4 -- .../parts/tree/browser/collapse-all-light.svg | 4 -- src/vs/base/parts/tree/browser/tree.css | 12 ----- .../parts/panel/media/chevron-down-dark.svg | 3 -- .../parts/panel/media/chevron-down-hc.svg | 3 -- .../parts/panel/media/chevron-down-light.svg | 3 -- .../parts/panel/media/chevron-up-dark.svg | 3 -- .../parts/panel/media/chevron-up-hc.svg | 3 -- .../parts/panel/media/chevron-up-light.svg | 3 -- .../browser/parts/panel/media/close-dark.svg | 4 -- .../browser/parts/panel/media/close-hc.svg | 4 -- .../browser/parts/panel/media/close-light.svg | 4 -- .../browser/parts/panel/media/panelpart.css | 14 ----- .../browser/parts/panel/panelActions.ts | 6 +-- .../debug/browser/media/clear-dark.svg | 7 --- .../contrib/debug/browser/media/clear-hc.svg | 7 --- .../debug/browser/media/clear-light.svg | 7 --- .../contrib/debug/browser/media/repl.css | 13 ----- .../workbench/contrib/debug/browser/repl.ts | 2 +- .../contrib/markers/browser/markersPanel.ts | 2 +- .../markers/browser/markersPanelActions.ts | 2 +- .../browser/media/exclude-settings-dark.svg | 3 -- .../browser/media/exclude-settings-hc.svg | 3 -- .../browser/media/exclude-settings-light.svg | 3 -- .../contrib/markers/browser/media/markers.css | 13 ----- .../output/browser/media/clear-dark.svg | 7 --- .../contrib/output/browser/media/clear-hc.svg | 7 --- .../output/browser/media/clear-light.svg | 7 --- .../output/browser/media/locked-dark.svg | 3 -- .../output/browser/media/locked-hc.svg | 3 -- .../output/browser/media/locked-light.svg | 3 -- .../output/browser/media/open-file-dark.svg | 3 -- .../output/browser/media/open-file-hc.svg | 3 -- .../output/browser/media/open-file-light.svg | 3 -- .../contrib/output/browser/media/output.css | 52 ------------------- .../output/browser/media/unlocked-dark.svg | 3 -- .../output/browser/media/unlocked-hc.svg | 3 -- .../output/browser/media/unlocked-light.svg | 3 -- .../contrib/output/browser/outputActions.ts | 10 ++-- .../terminal/browser/media/kill-dark.svg | 3 -- .../terminal/browser/media/kill-hc.svg | 3 -- .../terminal/browser/media/kill-light.svg | 3 -- .../terminal/browser/media/new-dark.svg | 3 -- .../contrib/terminal/browser/media/new-hc.svg | 3 -- .../terminal/browser/media/new-light.svg | 3 -- .../media/split-editor-horizontal-dark.svg | 3 -- .../media/split-editor-horizontal-hc.svg | 3 -- .../media/split-editor-horizontal-light.svg | 3 -- .../media/split-editor-vertical-dark.svg | 3 -- .../media/split-editor-vertical-hc.svg | 3 -- .../media/split-editor-vertical-light.svg | 3 -- .../terminal/browser/media/terminal.css | 18 ------- .../terminal/browser/terminalActions.ts | 6 +-- 56 files changed, 18 insertions(+), 295 deletions(-) delete mode 100644 src/vs/base/parts/tree/browser/collapse-all-dark.svg delete mode 100644 src/vs/base/parts/tree/browser/collapse-all-hc.svg delete mode 100644 src/vs/base/parts/tree/browser/collapse-all-light.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-down-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-down-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-down-light.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-up-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-up-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-up-light.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/close-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/close-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/close-light.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/clear-dark.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/clear-hc.svg delete mode 100644 src/vs/workbench/contrib/debug/browser/media/clear-light.svg delete mode 100644 src/vs/workbench/contrib/markers/browser/media/exclude-settings-dark.svg delete mode 100644 src/vs/workbench/contrib/markers/browser/media/exclude-settings-hc.svg delete mode 100644 src/vs/workbench/contrib/markers/browser/media/exclude-settings-light.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/clear-dark.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/clear-hc.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/clear-light.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/locked-dark.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/locked-hc.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/locked-light.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/open-file-dark.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/open-file-hc.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/open-file-light.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/output.css delete mode 100644 src/vs/workbench/contrib/output/browser/media/unlocked-dark.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/unlocked-hc.svg delete mode 100644 src/vs/workbench/contrib/output/browser/media/unlocked-light.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/kill-dark.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/kill-hc.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/kill-light.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/new-dark.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/new-hc.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/new-light.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-dark.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-hc.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-light.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-dark.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-hc.svg delete mode 100644 src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-light.svg diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 538f7fa0dbe..38ec0a60a51 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -311,14 +311,14 @@ export class ActionViewItem extends BaseActionViewItem { if (this.options.icon) { this.cssClass = this.getAction().class; - DOM.addClass(this.label, 'icon'); + DOM.addClass(this.label, 'codicon'); if (this.cssClass) { DOM.addClasses(this.label, this.cssClass); } this.updateEnabled(); } else { - DOM.removeClass(this.label, 'icon'); + DOM.removeClass(this.label, 'codicon'); } } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 04309db0ca4..689f29ba4c6 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -9,11 +9,12 @@ url("./codicon.svg?e042d2dda15ef7b36b910e3edf539f26#codicon") format("svg"); } -.codicon { +.codicon[class*='codicon-'] { font: normal normal normal 16px/1 codicon; display: inline-block; text-decoration: none; text-rendering: auto; + text-align: center; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-user-select: none; diff --git a/src/vs/base/parts/tree/browser/collapse-all-dark.svg b/src/vs/base/parts/tree/browser/collapse-all-dark.svg deleted file mode 100644 index 4862c55dbeb..00000000000 --- a/src/vs/base/parts/tree/browser/collapse-all-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/base/parts/tree/browser/collapse-all-hc.svg b/src/vs/base/parts/tree/browser/collapse-all-hc.svg deleted file mode 100644 index 05f920b29b6..00000000000 --- a/src/vs/base/parts/tree/browser/collapse-all-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/base/parts/tree/browser/collapse-all-light.svg b/src/vs/base/parts/tree/browser/collapse-all-light.svg deleted file mode 100644 index 6359b42e623..00000000000 --- a/src/vs/base/parts/tree/browser/collapse-all-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/base/parts/tree/browser/tree.css b/src/vs/base/parts/tree/browser/tree.css index 2a3cb47ddbb..6eb5f9b7aff 100644 --- a/src/vs/base/parts/tree/browser/tree.css +++ b/src/vs/base/parts/tree/browser/tree.css @@ -110,15 +110,3 @@ .hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { background-image: url('loading-hc.svg'); } - -.monaco-tree-action.collapse-all { - background: url('collapse-all-light.svg') center center no-repeat; -} - -.vs-dark .monaco-tree-action.collapse-all { - background: url('collapse-all-dark.svg') center center no-repeat; -} - -.hc-black .monaco-tree-action.collapse-all { - background: url('collapse-all-hc.svg') center center no-repeat; -} diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-down-dark.svg b/src/vs/workbench/browser/parts/panel/media/chevron-down-dark.svg deleted file mode 100644 index a1df6a8d44a..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-down-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-down-hc.svg b/src/vs/workbench/browser/parts/panel/media/chevron-down-hc.svg deleted file mode 100644 index 4f2ec146927..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-down-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-down-light.svg b/src/vs/workbench/browser/parts/panel/media/chevron-down-light.svg deleted file mode 100644 index e60e357f573..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-down-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-up-dark.svg b/src/vs/workbench/browser/parts/panel/media/chevron-up-dark.svg deleted file mode 100644 index 5b9da8932e1..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-up-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-up-hc.svg b/src/vs/workbench/browser/parts/panel/media/chevron-up-hc.svg deleted file mode 100644 index 13bad537364..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-up-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-up-light.svg b/src/vs/workbench/browser/parts/panel/media/chevron-up-light.svg deleted file mode 100644 index 5498cda5bc4..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-up-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/close-dark.svg b/src/vs/workbench/browser/parts/panel/media/close-dark.svg deleted file mode 100644 index e0475f7b85a..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/close-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/close-hc.svg b/src/vs/workbench/browser/parts/panel/media/close-hc.svg deleted file mode 100644 index 64618b61760..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/close-hc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/close-light.svg b/src/vs/workbench/browser/parts/panel/media/close-light.svg deleted file mode 100644 index 3bd44674699..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/close-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 9dc9bb2000f..0f4232c4e44 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -124,20 +124,6 @@ margin-right: 10px; } -/* Close */ -.monaco-workbench .hide-panel-action { - background: url('close-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .hide-panel-action { - background: url('close-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .hide-panel-action { - background: url('close-hc.svg') center center no-repeat; -} - - /* Up */ .monaco-workbench .maximize-panel-action { background-image: url('chevron-up-light.svg'); diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 904f8a364ba..c8419eed7e7 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -28,7 +28,7 @@ export class ClosePanelAction extends Action { name: string, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService ) { - super(id, name, 'hide-panel-action'); + super(id, name, 'codicon-close'); } run(): Promise { @@ -141,11 +141,11 @@ export class ToggleMaximizedPanelAction extends Action { @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IEditorGroupsService editorGroupsService: IEditorGroupsService ) { - super(id, label, layoutService.isPanelMaximized() ? 'minimize-panel-action' : 'maximize-panel-action'); + super(id, label, layoutService.isPanelMaximized() ? 'codicon-chevron-down' : 'codicon-chevron-up'); this.toDispose.add(editorGroupsService.onDidLayout(() => { const maximized = this.layoutService.isPanelMaximized(); - this.class = maximized ? 'minimize-panel-action' : 'maximize-panel-action'; + this.class = maximized ? 'codicon-chevron-down' : 'codicon-chevron-up'; this.label = maximized ? ToggleMaximizedPanelAction.RESTORE_LABEL : ToggleMaximizedPanelAction.MAXIMIZE_LABEL; })); } diff --git a/src/vs/workbench/contrib/debug/browser/media/clear-dark.svg b/src/vs/workbench/contrib/debug/browser/media/clear-dark.svg deleted file mode 100644 index 04d64ab41ca..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/clear-dark.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/clear-hc.svg b/src/vs/workbench/contrib/debug/browser/media/clear-hc.svg deleted file mode 100644 index 44a41edd3b3..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/clear-hc.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/clear-light.svg b/src/vs/workbench/contrib/debug/browser/media/clear-light.svg deleted file mode 100644 index f6a51c856f0..00000000000 --- a/src/vs/workbench/contrib/debug/browser/media/clear-light.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 9d92c972d48..e7befa20952 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -88,19 +88,6 @@ font-size: 9px; } -/* Actions */ -.debug-action.clear-repl { - background: url('clear-light.svg') center center no-repeat; -} - -.vs-dark .debug-action.clear-repl { - background: url('clear-dark.svg') center center no-repeat; -} - -.hc-black .debug-action.clear-repl { - background: url('clear-hc.svg') center center no-repeat; -} - /* Output coloring and styling */ .repl .repl-tree .output.expression > .ignore { font-style: italic; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index ba438198881..ec21ca71f2c 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -1008,7 +1008,7 @@ export class ClearReplAction extends Action { constructor(id: string, label: string, @IPanelService private readonly panelService: IPanelService ) { - super(id, label, 'debug-action clear-repl'); + super(id, label, 'debug-action codicon-clear-all'); } run(): Promise { diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index bbc4392c7f7..01ef11a2cd4 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -117,7 +117,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); // actions - this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll())); + this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action codicon-collapse-all', true, async () => this.collapseAll())); this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] })); } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index c45dee82e5d..1bc91c2d7cf 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -213,7 +213,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { private createFilesExcludeCheckbox(container: HTMLElement): void { const filesExcludeFilter = this._register(new Checkbox({ - actionClassName: 'markers-panel-filter-filesExclude', + actionClassName: 'codicon codicon-exclude', title: this.action.useFilesExclude ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE, isChecked: this.action.useFilesExclude })); diff --git a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-dark.svg b/src/vs/workbench/contrib/markers/browser/media/exclude-settings-dark.svg deleted file mode 100644 index 0b1694dc2f1..00000000000 --- a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-hc.svg b/src/vs/workbench/contrib/markers/browser/media/exclude-settings-hc.svg deleted file mode 100644 index ba88235419a..00000000000 --- a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-light.svg b/src/vs/workbench/contrib/markers/browser/media/exclude-settings-light.svg deleted file mode 100644 index 114ec3f0fec..00000000000 --- a/src/vs/workbench/contrib/markers/browser/media/exclude-settings-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css index 42321b8dba4..c8e96443126 100644 --- a/src/vs/workbench/contrib/markers/browser/media/markers.css +++ b/src/vs/workbench/contrib/markers/browser/media/markers.css @@ -56,19 +56,6 @@ display: none; } -.vs .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude { - background: url('exclude-settings-light.svg') center center no-repeat; -} - -.vs-dark .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude, -.hc-black .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude { - background: url('exclude-settings-dark.svg') center center no-repeat; -} - -.hc-black .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude { - background: url('exclude-settings-hc.svg') center center no-repeat; -} - .markers-panel .markers-panel-container { height: 100%; } diff --git a/src/vs/workbench/contrib/output/browser/media/clear-dark.svg b/src/vs/workbench/contrib/output/browser/media/clear-dark.svg deleted file mode 100644 index 04d64ab41ca..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/clear-dark.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/output/browser/media/clear-hc.svg b/src/vs/workbench/contrib/output/browser/media/clear-hc.svg deleted file mode 100644 index 44a41edd3b3..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/clear-hc.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/output/browser/media/clear-light.svg b/src/vs/workbench/contrib/output/browser/media/clear-light.svg deleted file mode 100644 index f6a51c856f0..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/clear-light.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/contrib/output/browser/media/locked-dark.svg b/src/vs/workbench/contrib/output/browser/media/locked-dark.svg deleted file mode 100644 index ebdc1c0078a..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/locked-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/locked-hc.svg b/src/vs/workbench/contrib/output/browser/media/locked-hc.svg deleted file mode 100644 index 350dc417710..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/locked-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/locked-light.svg b/src/vs/workbench/contrib/output/browser/media/locked-light.svg deleted file mode 100644 index 03b03513688..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/locked-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/open-file-dark.svg b/src/vs/workbench/contrib/output/browser/media/open-file-dark.svg deleted file mode 100644 index ed302ae1398..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/open-file-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/open-file-hc.svg b/src/vs/workbench/contrib/output/browser/media/open-file-hc.svg deleted file mode 100644 index bba63494e6f..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/open-file-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/open-file-light.svg b/src/vs/workbench/contrib/output/browser/media/open-file-light.svg deleted file mode 100644 index 392a840c5ef..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/open-file-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/output.css b/src/vs/workbench/contrib/output/browser/media/output.css deleted file mode 100644 index 0f19102cc38..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/output.css +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.monaco-workbench .output-action.clear-output { - background: url('clear-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .output-action.clear-output { - background: url('clear-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .output-action.clear-output { - background: url('clear-hc.svg') center center no-repeat; -} - -.monaco-workbench .output-action.output-scroll-lock { - background: url('locked-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .output-action.output-scroll-lock { - background: url('locked-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .output-action.output-scroll-lock { - background: url('locked-hc.svg') center center no-repeat; -} - -.monaco-workbench .output-action.output-scroll-unlock { - background: url('unlocked-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .output-action.output-scroll-unlock { - background: url('unlocked-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .output-action.output-scroll-unlock { - background: url('unlocked-hc.svg') center center no-repeat; -} - -.monaco-workbench .output-action.open-log-file { - background: url('open-file-light.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .output-action.open-log-file { - background: url('open-file-dark.svg') center center no-repeat; -} - -.hc-black .monaco-workbench .output-action.open-log-file { - background: url('open-file-hc.svg') center center no-repeat; -} diff --git a/src/vs/workbench/contrib/output/browser/media/unlocked-dark.svg b/src/vs/workbench/contrib/output/browser/media/unlocked-dark.svg deleted file mode 100644 index 3b7947f9752..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/unlocked-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/unlocked-hc.svg b/src/vs/workbench/contrib/output/browser/media/unlocked-hc.svg deleted file mode 100644 index 100cfc1385a..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/unlocked-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/media/unlocked-light.svg b/src/vs/workbench/contrib/output/browser/media/unlocked-light.svg deleted file mode 100644 index 0c3cb4b93b0..00000000000 --- a/src/vs/workbench/contrib/output/browser/media/unlocked-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index 561891fc62e..3760d018bf5 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -45,7 +45,7 @@ export class ClearOutputAction extends Action { id: string, label: string, @IOutputService private readonly outputService: IOutputService ) { - super(id, label, 'output-action clear-output'); + super(id, label, 'output-action codicon-clear-all'); } public run(): Promise { @@ -67,7 +67,7 @@ export class ToggleOrSetOutputScrollLockAction extends Action { public static readonly LABEL = nls.localize({ key: 'toggleOutputScrollLock', comment: ['Turn on / off automatic output scrolling'] }, "Toggle Output Scroll Lock"); constructor(id: string, label: string, @IOutputService private readonly outputService: IOutputService) { - super(id, label, 'output-action output-scroll-unlock'); + super(id, label, 'output-action codicon-unlock'); this._register(this.outputService.onActiveOutputChannel(channel => { const activeChannel = this.outputService.getActiveChannel(); if (activeChannel) { @@ -94,10 +94,10 @@ export class ToggleOrSetOutputScrollLockAction extends Action { private setClassAndLabel(locked: boolean) { if (locked) { - this.class = 'output-action output-scroll-lock'; + this.class = 'output-action codicon-lock'; this.label = nls.localize('outputScrollOn', "Turn Auto Scrolling On"); } else { - this.class = 'output-action output-scroll-unlock'; + this.class = 'output-action codicon-unlock'; this.label = nls.localize('outputScrollOff', "Turn Auto Scrolling Off"); } } @@ -185,7 +185,7 @@ export class OpenLogOutputFile extends Action { @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { - super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action open-log-file'); + super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action codicon-go-to-file'); this._register(this.outputService.onActiveOutputChannel(this.update, this)); this.update(); } diff --git a/src/vs/workbench/contrib/terminal/browser/media/kill-dark.svg b/src/vs/workbench/contrib/terminal/browser/media/kill-dark.svg deleted file mode 100644 index 9831c96a166..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/kill-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/kill-hc.svg b/src/vs/workbench/contrib/terminal/browser/media/kill-hc.svg deleted file mode 100644 index 656f3bd7a42..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/kill-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/kill-light.svg b/src/vs/workbench/contrib/terminal/browser/media/kill-light.svg deleted file mode 100644 index d5ac851860b..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/kill-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/new-dark.svg b/src/vs/workbench/contrib/terminal/browser/media/new-dark.svg deleted file mode 100644 index 4d9389336b9..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/new-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/new-hc.svg b/src/vs/workbench/contrib/terminal/browser/media/new-hc.svg deleted file mode 100644 index fb50c6c2849..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/new-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/new-light.svg b/src/vs/workbench/contrib/terminal/browser/media/new-light.svg deleted file mode 100644 index 01a9de7d5ab..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/new-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-dark.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-dark.svg deleted file mode 100644 index 8c22a7c5bfe..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-hc.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-hc.svg deleted file mode 100644 index 82c19d0c8fc..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-light.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-light.svg deleted file mode 100644 index 2d53ab6d3c2..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-horizontal-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-dark.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-dark.svg deleted file mode 100644 index 419c21be4f6..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-hc.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-hc.svg deleted file mode 100644 index 7565fd3c168..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-light.svg b/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-light.svg deleted file mode 100644 index 7e95763b463..00000000000 --- a/src/vs/workbench/contrib/terminal/browser/media/split-editor-vertical-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index be6edf706dc..d50dd4b9253 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -144,24 +144,6 @@ opacity: 0 !important; } -/* Light theme */ -.monaco-workbench .terminal-action.kill { background: url('kill-light.svg') center center no-repeat; } -.monaco-workbench .terminal-action.new { background: url('new-light.svg') center center no-repeat; } -.monaco-workbench .terminal-action.split { background: url('split-editor-horizontal-light.svg') center center no-repeat; } -.monaco-workbench .panel.right .terminal-action.split { background: url('split-editor-vertical-light.svg') center center no-repeat; } - -/* Dark theme */ -.vs-dark .monaco-workbench .terminal-action.kill, .hc-black .monaco-workbench .terminal-action.kill { background: url('kill-dark.svg') center center no-repeat; } -.vs-dark .monaco-workbench .terminal-action.new, .hc-black .monaco-workbench .terminal-action.new { background: url('new-dark.svg') center center no-repeat; } -.vs-dark .monaco-workbench .terminal-action.split, .hc-black .monaco-workbench .terminal-action.split { background: url('split-editor-horizontal-dark.svg') center center no-repeat; } -.vs-dark .monaco-workbench .panel.right .terminal-action.split, .hc-black .monaco-workbench .panel.right .terminal-action.split { background: url('split-editor-vertical-dark.svg') center center no-repeat; } - -/* HC theme */ -.hc-black .monaco-workbench .terminal-action.kill, .hc-black .monaco-workbench .terminal-action.kill { background: url('kill-hc.svg') center center no-repeat; } -.hc-black .monaco-workbench .terminal-action.new, .hc-black .monaco-workbench .terminal-action.new { background: url('new-hc.svg') center center no-repeat; } -.hc-black .monaco-workbench .terminal-action.split, .hc-black .monaco-workbench .terminal-action.split { background: url('split-editor-horizontal-hc.svg') center center no-repeat; } -.hc-black .monaco-workbench .panel.right .terminal-action.split, .hc-black .monaco-workbench .panel.right .terminal-action.split { background: url('split-editor-vertical-hc.svg') center center no-repeat; } - .vs-dark .monaco-workbench.mac .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events), .hc-black .monaco-workbench.mac .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events) { cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=') 1x, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC') 2x) 5 8, text; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 6357326ade2..5c6c751e720 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -105,7 +105,7 @@ export class KillTerminalAction extends Action { id: string, label: string, @ITerminalService private readonly terminalService: ITerminalService ) { - super(id, label, 'terminal-action kill'); + super(id, label, 'terminal-action codicon-trash'); } public run(event?: any): Promise { @@ -336,7 +336,7 @@ export class CreateNewTerminalAction extends Action { @ICommandService private readonly commandService: ICommandService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService ) { - super(id, label, 'terminal-action new'); + super(id, label, 'terminal-action codicon-add'); } public run(event?: any): Promise { @@ -412,7 +412,7 @@ export class SplitTerminalAction extends Action { @ICommandService private readonly commandService: ICommandService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService ) { - super(id, label, 'terminal-action split'); + super(id, label, 'terminal-action codicon-split-horizontal'); } public run(event?: any): Promise { From 801585eda1207d422773a235c6af8cd7a7354de6 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 16 Sep 2019 14:33:24 -0700 Subject: [PATCH 03/82] Add icon default color style --- src/vs/platform/theme/common/colorRegistry.ts | 2 ++ src/vs/workbench/browser/style.ts | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index f5fc75c9324..0c6eef628ac 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -187,6 +187,8 @@ export const activeContrastBorder = registerColor('contrastActiveBorder', { ligh export const selectionBackground = registerColor('selection.background', { light: null, dark: null, hc: null }, nls.localize('selectionBackground', "The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor.")); +export const iconDefault = registerColor('icon.default', { light: '#424242', dark: '#C5C5C5', hc: '#FFFFFF' }, nls.localize('iconDefault', "The default color for icons in the workbench.")); + // ------ text colors export const textSeparatorForeground = registerColor('textSeparator.foreground', { light: '#0000002e', dark: '#ffffff2e', hc: Color.black }, nls.localize('textSeparatorForeground', "Color for text separators.")); diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index dbb318045f5..5ab87d454dc 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -6,11 +6,17 @@ import 'vs/css!./media/style'; import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; -import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; +import { iconDefault, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + // Icon defaults + const iconDefaultColor = theme.getColor(iconDefault); + if (iconDefaultColor) { + collector.addRule(`.monaco-workbench { color: ${iconDefaultColor}; }`); + } + // Foreground const windowForeground = theme.getColor(foreground); if (windowForeground) { @@ -136,4 +142,5 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } `); } + }); From 73fdbc9765a4d1efe3ba1288bb16f7355f7714ac Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Sep 2019 15:02:31 -0700 Subject: [PATCH 04/82] Fix another bad import --- .../services/environment/browser/environmentService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 4f923d0e94b..a68e9cef955 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -11,11 +11,11 @@ import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { BACKUPS, IDebugParams, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; import { LogLevel } from 'vs/platform/log/common/log'; -import product from 'vs/platform/product/browser/product'; import { IPath, IPathsToWaitFor, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; +import product from 'vs/platform/product/common/product'; export class BrowserWindowConfiguration implements IWindowConfiguration { From d54dbd33f4af1c57bd4f2764f2418d787d735ebe Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Sep 2019 16:02:39 -0700 Subject: [PATCH 05/82] Add icon for image preview ext Fixes #80677 --- extensions/image-preview/icon.png | Bin 0 -> 1979 bytes extensions/image-preview/icon.svg | 18 ++++++++++++++++++ extensions/image-preview/package.json | 1 + 3 files changed, 19 insertions(+) create mode 100644 extensions/image-preview/icon.png create mode 100644 extensions/image-preview/icon.svg diff --git a/extensions/image-preview/icon.png b/extensions/image-preview/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..64dcf7d463c2678de271c4bae155092982e9bd50 GIT binary patch literal 1979 zcmbtVX;4#F6ut>TmI@IRWRF!`DuPf(D_VsXESnLG?1Bj@s0gy8s3=(kg@R70r3xqn zoe^X+2}Qwx1ZWy@VHstK$daV22Ez+QAdv9V2X>~`;YY1M?woVx-h1x(?tI@lY2JHX zb+k>i0RTGgZY~4>P>72HnoAH999I;M7_At$Kr#U38|N1)^v)&-0F5Yjmv4N|(gIJ;PL8rlxVHDi0>aZa zE<`Jhz2~cD+b$jNZ;bAHm@ttlZf(tX+}zmM*l`edZD?TNb}oZKP4wwl?JdbD zsAwK8)K{zciicHnv-ORn%!cQFfY;E&ArG@~yAtJOJEiS)9jo)T(MBd=>LhvSc2hsJ zkV(ZqnD8J$2K5p?k*WJg#&g+PhB?IzJ;pMii&M`cflaj0tJzL*o*GGhi(9^iJ-N1C zqMjn$P2KM?Q*A^oI@vbpB%H3IdXciM8^(yePa0*;lq~zx&KTWFhwKof2#w_}HY%m0 zqqLSQU+=|uGYQ=a+u!6RobHWM)rOq^9AOT-t5TiV&u1@B$GLGyyc;8qn+Bg92m&p` zuW;rOBh?3p41clyqP+5~!HO#UaLx?n6?b;>L=bk;%#(}?&{1_+!xrsRk@sD{vkyiu zaMSuAI=BKFE)K=rg^q@*e-u;ML(^(6{YUeM!yR8M+yhVx3CFVlF2OER`mkutp~y>T zcd2?XqUuoMbYW$D_zur=Nc{K9AE=^<0tDu>JI7Z-wsV-^wLrjezP!N(HLoGI+>`#c zH950cdr`C>B>G2p&5(v@24?TDT992C-;*w$nQJwSF_V=~bhfyWQ6mbtijaO(&eL4H zrZSEKR5NQJW9UR4Yb-PS@JxNcv!a3L)eC!Q7!&8thfoz@vckSL>{|z z97{a~mvTVaR7iBhXxPc9m;SUDP?R8^YwG{tT^XO&a*$sPAh)WIRFArE5~b?5@V+T^?R|P9g;zlg{=RrKIZ|sKn(fztcv7tmXjz(sM;z)|;e!#;!i`~q s0`Ei$jQmXZ6DJfxm-mMq;VJ=Ei{i)j|LLooAJf2n_g)v~x1^-M04RAv?EnA( literal 0 HcmV?d00001 diff --git a/extensions/image-preview/icon.svg b/extensions/image-preview/icon.svg new file mode 100644 index 00000000000..0eb0f4c103b --- /dev/null +++ b/extensions/image-preview/icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index ef321ccde25..b7f2aeb6b8e 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "icon": "icon.png", "enableProposedApi": true, "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", From a6c689dc5ef9415a8d55dbf60d09985875f9fd9b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Sep 2019 16:09:15 -0700 Subject: [PATCH 06/82] Revert ":lipstick:" This reverts commit 7a9dfd33eeeec96a39091ba0508b05a8e7c05345. --- src/vs/platform/userDataSync/common/settingsSync.ts | 2 +- src/vs/platform/userDataSync/common/userDataSync.ts | 2 +- src/vs/platform/userDataSync/common/userDataSyncService.ts | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index 9ebf057bd4f..ae1174b8583 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE as SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index a311d5185da..757d62ebf9c 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -87,7 +87,7 @@ export enum SyncStatus { } export const USER_DATA_PREVIEW_SCHEME = 'vscode-userdata-preview'; -export const SETTINGS_CONFLICTS_RESOURCE = URI.file('Settings-Preview').with({ scheme: USER_DATA_PREVIEW_SCHEME }); +export const SETTINGS_PREVIEW_RESOURCE = URI.file('Settings-Preview').with({ scheme: USER_DATA_PREVIEW_SCHEME }); export interface ISynchroniser { diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 814ea6d5d0c..287d971a205 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -8,6 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; import { Emitter, Event } from 'vs/base/common/event'; +import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -24,6 +25,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ readonly onDidChangeLocal: Event; constructor( + @IFileService fileService: IFileService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { From 2320972f5f1206d6e9a047e3850b4d0bee4d2e87 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 16 Sep 2019 16:09:20 -0700 Subject: [PATCH 07/82] Revert "Move user data sync service to platform" This reverts commit 0772a8fcc90f50bf125c2ab3286a3b950276516b. --- .../contrib/userData/browser/userData.contribution.ts | 4 ---- .../services/userData}/common/settingsSync.ts | 4 ++-- .../services/userData}/common/userDataSyncService.ts | 9 +++++++-- src/vs/workbench/workbench.common.main.ts | 4 +--- 4 files changed, 10 insertions(+), 11 deletions(-) rename src/vs/{platform/userDataSync => workbench/services/userData}/common/settingsSync.ts (98%) rename src/vs/{platform/userDataSync => workbench/services/userData}/common/userDataSyncService.ts (83%) diff --git a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts index d1c64c8f11a..02c6bdc3797 100644 --- a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts +++ b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts @@ -25,8 +25,6 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IFileService } from 'vs/platform/files/common/files'; -import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; const CONTEXT_SYNC_STATE = new RawContextKey('syncStatus', SyncStatus.Uninitialized); @@ -49,13 +47,11 @@ Registry.as(ConfigurationExtensions.Configuration) class UserDataSyncContribution extends Disposable implements IWorkbenchContribution { constructor( - @IFileService fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, ) { super(); - this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); this.sync(true); this._register(Event.any( Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue('userConfiguration.enableSync')), diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/workbench/services/userData/common/settingsSync.ts similarity index 98% rename from src/vs/platform/userDataSync/common/settingsSync.ts rename to src/vs/workbench/services/userData/common/settingsSync.ts index ae1174b8583..fee382b9750 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/workbench/services/userData/common/settingsSync.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE as SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; @@ -40,7 +40,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { private _onDidChangeLocal: Emitter = this._register(new Emitter()); readonly onDidChangeLocal: Event = this._onDidChangeLocal.event; - readonly conflicts: URI = SETTINGS_CONFLICTS_RESOURCE; + readonly conflicts: URI = SETTINGS_PREVIEW_RESOURCE; constructor( @IFileService private readonly fileService: IFileService, diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/workbench/services/userData/common/userDataSyncService.ts similarity index 83% rename from src/vs/platform/userDataSync/common/userDataSyncService.ts rename to src/vs/workbench/services/userData/common/userDataSyncService.ts index 287d971a205..9a048f2678d 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/workbench/services/userData/common/userDataSyncService.ts @@ -3,12 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, ISynchroniser, USER_DATA_PREVIEW_SCHEME, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; +import { SettingsSynchroniser } from 'vs/workbench/services/userData/common/settingsSync'; import { Emitter, Event } from 'vs/base/common/event'; import { IFileService } from 'vs/platform/files/common/files'; +import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; import { URI } from 'vs/base/common/uri'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -30,6 +32,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); + this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); this.synchronisers = [ this.instantiationService.createInstance(SettingsSynchroniser) ]; @@ -92,3 +95,5 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ } } + +registerSingleton(IUserDataSyncService, UserDataSyncService); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index a8653dce509..3b9fd5060ff 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -107,9 +107,8 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; -import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(IContextViewService, ContextViewService, true); @@ -124,7 +123,6 @@ registerSingleton(IMenuService, MenuService, true); registerSingleton(IDownloadService, DownloadService, true); registerSingleton(IOpenerService, OpenerService, true); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); -registerSingleton(IUserDataSyncService, UserDataSyncService); //#endregion From 5764546fa65c5a377890160e2ce88f61004683b6 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 16 Sep 2019 19:28:11 -0700 Subject: [PATCH 08/82] Remove output style --- src/vs/workbench/contrib/output/browser/outputPanel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index f1c0b211d32..9f58f043851 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/output'; import * as nls from 'vs/nls'; import { Action, IAction } from 'vs/base/common/actions'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; From 9b9b142852f8d41253518a8f0bc28a5d5b2e5a12 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 16 Sep 2019 19:30:11 -0700 Subject: [PATCH 09/82] Scope icon color token --- src/vs/workbench/browser/style.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index 5ab87d454dc..b7c6fc80afa 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -14,7 +14,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { // Icon defaults const iconDefaultColor = theme.getColor(iconDefault); if (iconDefaultColor) { - collector.addRule(`.monaco-workbench { color: ${iconDefaultColor}; }`); + collector.addRule(`.monaco-workbench .codicon { color: ${iconDefaultColor}; }`); } // Foreground From 663b07c8e9857ebb98b2eec9c995e6b8193d3500 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Mon, 16 Sep 2019 19:38:39 -0700 Subject: [PATCH 10/82] Update icon ref to codicon --- src/vs/base/browser/ui/actionbar/actionbar.css | 4 ++-- src/vs/base/browser/ui/inputbox/inputBox.css | 2 +- .../contrib/extensions/browser/media/extensionActions.css | 2 +- src/vs/workbench/contrib/search/browser/media/searchview.css | 2 +- test/automation/src/keybindings.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 25795ddb631..08b4920ae47 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -40,7 +40,7 @@ transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */ } -.monaco-action-bar .action-item .icon { +.monaco-action-bar .action-item .codicon { display: inline-block; } @@ -95,4 +95,4 @@ display: flex; align-items: center; justify-content: center; -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css index ae4cd429a07..939d0cb5f01 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.css +++ b/src/vs/base/browser/ui/inputbox/inputBox.css @@ -123,7 +123,7 @@ margin-left: 2px; } -.monaco-inputbox .monaco-action-bar .action-item .icon { +.monaco-inputbox .monaco-action-bar .action-item .codicon { background-repeat: no-repeat; width: 16px; height: 16px; diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css index 79d7e01a69c..ed1ba80ba46 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css @@ -78,7 +78,7 @@ margin: 0.15em; } -.monaco-action-bar .action-item .action-label.system-disable.icon { +.monaco-action-bar .action-item .action-label.system-disable.codicon { opacity: 1; height: 18px; width: 10px; diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index f530bce968a..decc6173962 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -86,7 +86,7 @@ height: 25px; } -.search-view .search-widget .replace-container .monaco-action-bar .action-item .icon { +.search-view .search-widget .replace-container .monaco-action-bar .action-item .codicon { background-repeat: no-repeat; width: 20px; height: 25px; diff --git a/test/automation/src/keybindings.ts b/test/automation/src/keybindings.ts index 9544b5992db..70be12b2378 100644 --- a/test/automation/src/keybindings.ts +++ b/test/automation/src/keybindings.ts @@ -24,7 +24,7 @@ export class KeybindingsEditor { await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item'); await this.code.waitForElement('.keybindings-list-container .monaco-list-row.keybinding-item.focused.selected'); - await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item .action-item .icon.add'); + await this.code.waitAndClick('.keybindings-list-container .monaco-list-row.keybinding-item .action-item .codicon.add'); await this.code.waitForActiveElement('.defineKeybindingWidget .monaco-inputbox input'); await this.code.dispatchKeybinding(keybinding); From bdd1971f2cd9d08a8a90e02740f1850afe03da66 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 07:35:44 +0200 Subject: [PATCH 11/82] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc20c456077..1cfb2db79c6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.39.0", - "distro": "76b346a469f422d14a1c3558188b81261eb93af7", + "distro": "e892717dc1ae3cea3824697bc2c28d64f8476f93", "author": { "name": "Microsoft Corporation" }, From 08a596464583b9c956f7b4f20e7689f4aeb844a9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 07:43:53 +0200 Subject: [PATCH 12/82] web - change API to URI (from UriComponents) --- src/vs/base/common/network.ts | 9 ++++----- src/vs/code/browser/workbench/workbench.ts | 14 +++++++++++--- .../browser/remoteAuthorityResolverService.ts | 4 ++-- src/vs/workbench/browser/web.main.ts | 4 ++-- .../credentials/browser/credentialsService.ts | 2 ++ .../services/extensions/common/staticExtensions.ts | 3 +-- .../workbench/services/url/browser/urlService.ts | 4 ++-- src/vs/workbench/workbench.web.api.ts | 10 +++++----- 8 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 01c7df0fdda..7d525614421 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; export namespace Schemas { @@ -60,7 +60,7 @@ class RemoteAuthoritiesImpl { private readonly _ports: { [authority: string]: number; }; private readonly _connectionTokens: { [authority: string]: string; }; private _preferredWebSchema: 'http' | 'https'; - private _delegate: ((uri: URI) => UriComponents) | null; + private _delegate: ((uri: URI) => URI) | null; constructor() { this._hosts = Object.create(null); @@ -74,7 +74,7 @@ class RemoteAuthoritiesImpl { this._preferredWebSchema = schema; } - public setDelegate(delegate: (uri: URI) => UriComponents): void { + public setDelegate(delegate: (uri: URI) => URI): void { this._delegate = delegate; } @@ -89,8 +89,7 @@ class RemoteAuthoritiesImpl { public rewrite(uri: URI): URI { if (this._delegate) { - const result = this._delegate(uri); - return URI.revive(result); + return this._delegate(uri); } const authority = uri.authority; const host = this._hosts[authority]; diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 156d501ce43..a70fb06b7bc 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -113,8 +113,8 @@ class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvi FRAGMENT: 'vscode-fragment' }; - private readonly _onCallback: Emitter = this._register(new Emitter()); - readonly onCallback: Event = this._onCallback.event; + private readonly _onCallback: Emitter = this._register(new Emitter()); + readonly onCallback: Event = this._onCallback.event; create(options?: Partial): URI { const queryValues: Map = new Map(); @@ -164,7 +164,7 @@ class PollingURLCallbackProvider extends Disposable implements IURLCallbackProvi const content = await streamToBuffer(result.stream); if (content.byteLength > 0) { try { - this._onCallback.fire(JSON.parse(content.toString())); + this._onCallback.fire(URI.revive(JSON.parse(content.toString()))); } catch (error) { console.error(error); } @@ -201,4 +201,12 @@ const options: IWorkbenchConstructionOptions = JSON.parse(document.getElementByI options.urlCallbackProvider = new PollingURLCallbackProvider(); options.credentialsProvider = new LocalStorageCredentialsProvider(); +if (options.folderUri) { + options.folderUri = URI.revive(options.folderUri); +} + +if (options.workspaceUri) { + options.workspaceUri = URI.revive(options.workspaceUri); +} + create(document.body, options); diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index fa22819f880..ed6281a5dde 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -5,14 +5,14 @@ import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorities } from 'vs/base/common/network'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { _serviceBrand: undefined; constructor( - resourceUriProvider: ((uri: URI) => UriComponents) | undefined + resourceUriProvider: ((uri: URI) => URI) | undefined ) { if (resourceUriProvider) { RemoteAuthorities.setDelegate(resourceUriProvider); diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index be720535c85..59a528f66d8 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -266,12 +266,12 @@ class CodeRendererMain extends Disposable { // Multi-root workspace if (this.configuration.workspaceUri) { - return { id: hash(URI.revive(this.configuration.workspaceUri).toString()).toString(16), configPath: URI.revive(this.configuration.workspaceUri) }; + return { id: hash(this.configuration.workspaceUri.toString()).toString(16), configPath: this.configuration.workspaceUri }; } // Single-folder workspace if (this.configuration.folderUri) { - return { id: hash(URI.revive(this.configuration.folderUri).toString()).toString(16), folder: URI.revive(this.configuration.folderUri) }; + return { id: hash(this.configuration.folderUri.toString()).toString(16), folder: this.configuration.folderUri }; } return { id: 'empty-window' }; diff --git a/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts index d4b425e4adc..e005f8bc302 100644 --- a/src/vs/workbench/services/credentials/browser/credentialsService.ts +++ b/src/vs/workbench/services/credentials/browser/credentialsService.ts @@ -10,7 +10,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ export interface ICredentialsProvider { getPassword(service: string, account: string): Promise; setPassword(service: string, account: string, password: string): Promise; + deletePassword(service: string, account: string): Promise; + findPassword(service: string): Promise; findCredentials(service: string): Promise>; } diff --git a/src/vs/workbench/services/extensions/common/staticExtensions.ts b/src/vs/workbench/services/extensions/common/staticExtensions.ts index 8eebb7aa782..2bce503265d 100644 --- a/src/vs/workbench/services/extensions/common/staticExtensions.ts +++ b/src/vs/workbench/services/extensions/common/staticExtensions.ts @@ -5,7 +5,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { URI } from 'vs/base/common/uri'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -27,7 +26,7 @@ export class StaticExtensionsService implements IStaticExtensionsService { this._descriptions = staticExtensions.map(data => { identifier: new ExtensionIdentifier(`${data.packageJSON.publisher}.${data.packageJSON.name}`), - extensionLocation: URI.revive(data.extensionLocation), + extensionLocation: data.extensionLocation, ...data.packageJSON, }); } diff --git a/src/vs/workbench/services/url/browser/urlService.ts b/src/vs/workbench/services/url/browser/urlService.ts index 6a1c901313b..b073447fc26 100644 --- a/src/vs/workbench/services/url/browser/urlService.ts +++ b/src/vs/workbench/services/url/browser/urlService.ts @@ -16,7 +16,7 @@ export interface IURLCallbackProvider { * Indicates that a Uri has been opened outside of VSCode. The Uri * will be forwarded to all installed Uri handlers in the system. */ - readonly onCallback: Event; + readonly onCallback: Event; /** * Creates a Uri that - if opened in a browser - must result in @@ -54,7 +54,7 @@ export class BrowserURLService extends AbstractURLService { private registerListeners(): void { if (this.provider) { - this._register(this.provider.onCallback(uri => this.open(URI.revive(uri)))); + this._register(this.provider.onCallback(uri => this.open(uri))); } } diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 4a1ccfaade2..cd4351d6016 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -38,12 +38,12 @@ interface IWorkbenchConstructionOptions { /** * Experimental: An optional folder that is set as workspace context for the workbench. */ - folderUri?: UriComponents; + folderUri?: URI; /** * Experimental: An optional workspace that is set as workspace context for the workbench. */ - workspaceUri?: UriComponents; + workspaceUri?: URI; /** * Experimental: The userDataProvider is used to handle user specific application @@ -59,7 +59,7 @@ interface IWorkbenchConstructionOptions { /** * A provider for resource URIs. */ - resourceUriProvider?: (uri: URI) => UriComponents; + resourceUriProvider?: (uri: URI) => URI; /** * Experimental: Whether to enable the smoke test driver. @@ -74,7 +74,7 @@ interface IWorkbenchConstructionOptions { /** * Experimental: Add static extensions that cannot be uninstalled but only be disabled. */ - staticExtensions?: { packageJSON: IExtensionManifest, extensionLocation: UriComponents }[]; + staticExtensions?: { packageJSON: IExtensionManifest, extensionLocation: URI }[]; /** * Experimental: Support for URL callbacks. @@ -109,8 +109,8 @@ export { IWorkbenchConstructionOptions, // Basic Types - UriComponents, URI, + UriComponents, Event, Emitter, IDisposable, From 753de26cd6bedbf0006598bf2aa1e8f2d2994fb6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 07:44:14 +0200 Subject: [PATCH 13/82] debt - remove some internal commands --- .../api/browser/mainThreadWorkspace.ts | 21 +------------------ .../browser/actions/layoutActions.ts | 10 --------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index 2d84b1751ea..11b31a4edda 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -9,16 +9,13 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { isNative } from 'vs/base/common/platform'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol'; @@ -224,19 +221,3 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return this._windowService.resolveProxy(url); } } - -CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (accessor: ServicesAccessor, workspace: URI, disableExtensions: string[]) { - const workspaceEditingService = accessor.get(IWorkspaceEditingService); - const extensionService = accessor.get(IExtensionService); - const windowService = accessor.get(IWindowService); - - if (disableExtensions && disableExtensions.length) { - const runningExtensions = await extensionService.getExtensions(); - // If requested extension to disable is running, then reload window with given workspace - if (disableExtensions && runningExtensions.some(runningExtension => disableExtensions.some(id => ExtensionIdentifier.equals(runningExtension.identifier, id)))) { - return windowService.openWindow([{ workspaceUri: workspace }], { args: { _: [], 'disable-extension': disableExtensions } }); - } - } - - return workspaceEditingService.enterWorkspace(workspace); -}); diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 59b4771c906..4b164c1e8ab 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -12,7 +12,6 @@ import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/ import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; @@ -142,15 +141,6 @@ export class ToggleEditorLayoutAction extends Action { } } -CommandsRegistry.registerCommand('_workbench.editor.setGroupOrientation', function (accessor: ServicesAccessor, args: [GroupOrientation]) { - const editorGroupService = accessor.get(IEditorGroupsService); - const [orientation] = args; - - editorGroupService.setGroupOrientation(orientation); - - return Promise.resolve(); -}); - const group = viewCategory; registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Toggle Vertical/Horizontal Editor Layout', group); From 849034f59ab0751c7d5d9caaec4183869bb88a12 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 07:44:30 +0200 Subject: [PATCH 14/82] electron - fix deprecation warning (accessibility) --- src/vs/code/electron-main/window.ts | 2 +- src/vs/platform/launch/electron-main/launchService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 51f71cb1af6..0ec81879f16 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -561,7 +561,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { autoDetectHighContrast = false; } windowConfiguration.highContrast = isWindows && autoDetectHighContrast && systemPreferences.isInvertedColorScheme(); - windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled(); + windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled; // Title style related windowConfiguration.maximized = this._win.isMaximized(); diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index bb3e497e3d2..e33e293b214 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -268,7 +268,7 @@ export class LaunchService implements ILaunchService { mainPID: process.pid, mainArguments: process.argv.slice(1), windows, - screenReader: app.isAccessibilitySupportEnabled(), + screenReader: !!app.accessibilitySupportEnabled, gpuFeatureStatus: app.getGPUFeatureStatus() }); } From d3e114317115486bd295e03f09f3892a543f46be Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 00:00:29 +0200 Subject: [PATCH 15/82] Move user data sync service to platform --- .../userDataSync}/common/settingsSync.ts | 4 ++-- .../userDataSync}/common/userDataSyncService.ts | 9 ++------- .../contrib/userData/browser/userData.contribution.ts | 4 ++++ src/vs/workbench/workbench.common.main.ts | 4 +++- 4 files changed, 11 insertions(+), 10 deletions(-) rename src/vs/{workbench/services/userData => platform/userDataSync}/common/settingsSync.ts (98%) rename src/vs/{workbench/services/userData => platform/userDataSync}/common/userDataSyncService.ts (83%) diff --git a/src/vs/workbench/services/userData/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts similarity index 98% rename from src/vs/workbench/services/userData/common/settingsSync.ts rename to src/vs/platform/userDataSync/common/settingsSync.ts index fee382b9750..ae1174b8583 100644 --- a/src/vs/workbench/services/userData/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE as SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; @@ -40,7 +40,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { private _onDidChangeLocal: Emitter = this._register(new Emitter()); readonly onDidChangeLocal: Event = this._onDidChangeLocal.event; - readonly conflicts: URI = SETTINGS_PREVIEW_RESOURCE; + readonly conflicts: URI = SETTINGS_CONFLICTS_RESOURCE; constructor( @IFileService private readonly fileService: IFileService, diff --git a/src/vs/workbench/services/userData/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts similarity index 83% rename from src/vs/workbench/services/userData/common/userDataSyncService.ts rename to src/vs/platform/userDataSync/common/userDataSyncService.ts index 9a048f2678d..287d971a205 100644 --- a/src/vs/workbench/services/userData/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -3,14 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, ISynchroniser, USER_DATA_PREVIEW_SCHEME, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { SettingsSynchroniser } from 'vs/workbench/services/userData/common/settingsSync'; +import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; import { Emitter, Event } from 'vs/base/common/event'; import { IFileService } from 'vs/platform/files/common/files'; -import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; import { URI } from 'vs/base/common/uri'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -32,7 +30,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); - this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); this.synchronisers = [ this.instantiationService.createInstance(SettingsSynchroniser) ]; @@ -95,5 +92,3 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ } } - -registerSingleton(IUserDataSyncService, UserDataSyncService); diff --git a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts index 02c6bdc3797..d1c64c8f11a 100644 --- a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts +++ b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts @@ -25,6 +25,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IFileService } from 'vs/platform/files/common/files'; +import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; const CONTEXT_SYNC_STATE = new RawContextKey('syncStatus', SyncStatus.Uninitialized); @@ -47,11 +49,13 @@ Registry.as(ConfigurationExtensions.Configuration) class UserDataSyncContribution extends Disposable implements IWorkbenchContribution { constructor( + @IFileService fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, ) { super(); + this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); this.sync(true); this._register(Event.any( Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue('userConfiguration.enableSync')), diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 3b9fd5060ff..a8653dce509 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -107,8 +107,9 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(IContextViewService, ContextViewService, true); @@ -123,6 +124,7 @@ registerSingleton(IMenuService, MenuService, true); registerSingleton(IDownloadService, DownloadService, true); registerSingleton(IOpenerService, OpenerService, true); registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); +registerSingleton(IUserDataSyncService, UserDataSyncService); //#endregion From b29d98337fe0b3029e030e4893b2ac0166da3d6a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 00:04:18 +0200 Subject: [PATCH 16/82] :lipstick: --- src/vs/platform/userDataSync/common/settingsSync.ts | 2 +- src/vs/platform/userDataSync/common/userDataSync.ts | 2 +- src/vs/platform/userDataSync/common/userDataSyncService.ts | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index ae1174b8583..9ebf057bd4f 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE as SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 757d62ebf9c..a311d5185da 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -87,7 +87,7 @@ export enum SyncStatus { } export const USER_DATA_PREVIEW_SCHEME = 'vscode-userdata-preview'; -export const SETTINGS_PREVIEW_RESOURCE = URI.file('Settings-Preview').with({ scheme: USER_DATA_PREVIEW_SCHEME }); +export const SETTINGS_CONFLICTS_RESOURCE = URI.file('Settings-Preview').with({ scheme: USER_DATA_PREVIEW_SCHEME }); export interface ISynchroniser { diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 287d971a205..814ea6d5d0c 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -8,7 +8,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; import { Emitter, Event } from 'vs/base/common/event'; -import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -25,7 +24,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ readonly onDidChangeLocal: Event; constructor( - @IFileService fileService: IFileService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { From c38aea395c16f3aa511498e7cb69542423076874 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 08:27:33 +0200 Subject: [PATCH 17/82] remote invalid import --- src/vs/workbench/workbench.common.main.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index a8653dce509..73fc63f220c 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -79,7 +79,6 @@ import 'vs/workbench/services/label/common/labelService'; import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; -import 'vs/workbench/services/userData/common/userDataSyncService'; import 'vs/workbench/services/userData/common/settingsMergeService'; import 'vs/workbench/services/workspace/browser/workspaceEditingService'; From d8d6c2daad9ca3a2a215c8929821362a70022d06 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 08:33:19 +0200 Subject: [PATCH 18/82] :up: chokidar@3 (#81028) * :up: chokidar@3 * :up: chokidar@3.1.0 * update also in remote --- package.json | 2 +- remote/package.json | 2 +- remote/yarn.lock | 816 ++---------------- src/typings/chokidar.d.ts | 4 +- .../watcher/unix/chokidarWatcherService.ts | 2 +- yarn.lock | 126 ++- 6 files changed, 158 insertions(+), 794 deletions(-) diff --git a/package.json b/package.json index 1cfb2db79c6..673662926a8 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "dependencies": { "@microsoft/applicationinsights-web": "^2.1.1", "applicationinsights": "1.0.8", + "chokidar": "3.1.0", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", @@ -46,7 +47,6 @@ "spdlog": "^0.9.0", "sudo-prompt": "9.0.0", "v8-inspect-profiler": "^0.0.20", - "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.7", diff --git a/remote/package.json b/remote/package.json index 0d57945f25b..4c37100ec67 100644 --- a/remote/package.json +++ b/remote/package.json @@ -4,6 +4,7 @@ "dependencies": { "@microsoft/applicationinsights-web": "^2.1.1", "applicationinsights": "1.0.8", + "chokidar": "3.1.0", "cookie": "^0.4.0", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", @@ -16,7 +17,6 @@ "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", "spdlog": "^0.9.0", - "vscode-chokidar": "2.1.7", "vscode-minimist": "^1.2.1", "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.7", diff --git a/remote/yarn.lock b/remote/yarn.lock index 6a545c78298..037aedc8cfd 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -79,6 +79,14 @@ agent-base@~4.2.0: dependencies: es6-promisify "^5.0.0" +anymatch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.0.tgz#e609350e50a9313b472789b2f14ef35808ee14d6" + integrity sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + applicationinsights@1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" @@ -88,58 +96,10 @@ applicationinsights@1.0.8: diagnostic-channel-publishers "0.2.1" zone.js "0.7.6" -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" - integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== bindings@^1.5.0: version "1.5.0" @@ -148,80 +108,38 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" + fill-range "^7.0.1" buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== +chokidar@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.1.0.tgz#ff23d077682a90eadd209bfa76eb10ed6d359668" + integrity sha512-6vZfo+7W0EOlbSo0nhVKMz4yyssrwiPbBZ8wj1lq8/+l4ZhGZ2U4Md7PspvmijXp1a26D3B7AHEBmIB7aVtaOQ== dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + anymatch "^3.1.0" + braces "^3.0.2" + glob-parent "^5.0.0" + is-binary-path "^2.1.0" + is-glob "^4.0.1" + normalize-path "^3.0.0" + readdirp "^3.1.1" + optionalDependencies: + fsevents "^2.0.6" cookie@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -229,40 +147,6 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - diagnostic-channel-publishers@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" @@ -287,48 +171,6 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -341,27 +183,12 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" + to-regex-range "^5.0.1" fs-extra@^7.0.0: version "7.0.1" @@ -372,60 +199,28 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +fsevents@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" + integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" + is-glob "^4.0.1" graceful-fs@4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -graceful-fs@^4.1.11, graceful-fs@^4.1.6: +graceful-fs@^4.1.6: version "4.2.0" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" @@ -449,150 +244,34 @@ iconv-lite@0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" -inherits@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= +is-binary-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: - kind-of "^3.0.2" + binary-extensions "^2.0.0" -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.0.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" - integrity sha1-z8hszV3FpS+oBIkRHGkgxFfi2Ys= - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: +is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0: +is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== dependencies: is-extglob "^2.1.1" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== jschardet@1.6.0: version "1.6.0" @@ -606,37 +285,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -kind-of@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" - integrity sha1-e47PGKThf4Jp1ztQHJ8jLJaIenQ= - dependencies: - is-buffer "^1.0.2" - -kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - lodash.isinteger@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" @@ -647,50 +295,11 @@ lodash.isundefined@^3.0.1: resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" integrity sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g= -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -708,23 +317,6 @@ nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - native-watchdog@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.2.0.tgz#9c710093ac6e9e60b19517cb1ef4ac9d7c997395" @@ -757,29 +349,6 @@ nsfw@1.2.5: lodash.isundefined "^3.0.1" nan "^2.0.0" -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - onigasm-umd@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" @@ -792,21 +361,6 @@ oniguruma@^7.2.0: dependencies: nan "^2.14.0" -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -817,77 +371,12 @@ picomatch@^2.0.4: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= - -readable-stream@^2.0.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== +readdirp@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.2.tgz#fa85d2d14d4289920e4671dead96431add2ee78a" + integrity sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw== dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" + picomatch "^2.0.4" "safer-buffer@>= 2.1.2 < 3": version "2.1.2" @@ -904,51 +393,11 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - smart-buffer@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - socks-proxy-agent@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" @@ -965,27 +414,6 @@ socks@~2.2.0: ip "^1.1.5" smart-buffer "^4.0.1" -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - spdlog@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.9.0.tgz#c85dd9d0b9cd385f6f3f5b92dc9d2e1691092b5c" @@ -995,135 +423,23 @@ spdlog@^0.9.0: mkdirp "^0.5.1" nan "^2.14.0" -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: - extend-shallow "^3.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ== - dependencies: - safe-buffer "~5.1.0" - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" + is-number "^7.0.0" tslib@^1.9.3: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -vscode-anymatch@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-anymatch/-/vscode-anymatch-3.0.3.tgz#5a79101e6df7e659a1f070367bc42f190eb4ae76" - integrity sha512-qQgfbzJJ5nNShh4jjC3BBekY4d8emcxHFgnqcXwsB/PUKvJPCg7AZYXM7hqS7EDnKrX9tsIFwFMihZ7yut92Qg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -vscode-chokidar@2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/vscode-chokidar/-/vscode-chokidar-2.1.7.tgz#c5b31eb87402f4779bb4170915245bdcb6f7854b" - integrity sha512-uSNEQetPjAlgIAHmcF9E6M+KCw0f842rsEnJ64aamUAV6TO7gkXNCvLSzb4MuLsPU7ZQyCa++DrLQFjvciK5dg== - dependencies: - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - vscode-anymatch "3.0.3" - optionalDependencies: - vscode-fsevents "1.2.12" - -vscode-fsevents@1.2.12: - version "1.2.12" - resolved "https://registry.yarnpkg.com/vscode-fsevents/-/vscode-fsevents-1.2.12.tgz#01a71a01f90ee95ca822c34427aba437a17c03a7" - integrity sha512-bH/jRdDpSesGpqiVLjp6gHLSKUOh7oNvppzZ17JIrdbRYCcDmV7dIWR5gQc27DFy0RD9JDT+t+ixMid94MkM1A== - dependencies: - nan "^2.14.0" - vscode-minimist@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a" diff --git a/src/typings/chokidar.d.ts b/src/typings/chokidar.d.ts index 7f78ded23d4..a3b4c20a6a1 100644 --- a/src/typings/chokidar.d.ts +++ b/src/typings/chokidar.d.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -declare module 'vscode-chokidar' { +declare module 'chokidar' { // TypeScript Version: 3.0 @@ -197,4 +197,4 @@ declare module 'vscode-chokidar' { paths: string | string[], options?: WatchOptions ): FSWatcher; -} \ No newline at end of file +} diff --git a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts index 5976158610b..2600512e0e7 100644 --- a/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts +++ b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as chokidar from 'vscode-chokidar'; +import * as chokidar from 'chokidar'; import * as fs from 'fs'; import * as gracefulFs from 'graceful-fs'; gracefulFs.gracefulify(fs); diff --git a/yarn.lock b/yarn.lock index 6af38b749cd..589e9f9e31c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -585,6 +585,14 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.0.tgz#e609350e50a9313b472789b2f14ef35808ee14d6" + integrity sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + append-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" @@ -974,6 +982,11 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + binary-search-bounds@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/binary-search-bounds/-/binary-search-bounds-2.0.3.tgz#5ff8616d6dd2ca5388bc85b2d6266e2b9da502dc" @@ -1104,6 +1117,13 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -1403,6 +1423,21 @@ cheerio@^1.0.0-rc.1: lodash "^4.15.0" parse5 "^3.0.1" +chokidar@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.1.0.tgz#ff23d077682a90eadd209bfa76eb10ed6d359668" + integrity sha512-6vZfo+7W0EOlbSo0nhVKMz4yyssrwiPbBZ8wj1lq8/+l4ZhGZ2U4Md7PspvmijXp1a26D3B7AHEBmIB7aVtaOQ== + dependencies: + anymatch "^3.1.0" + braces "^3.0.2" + glob-parent "^5.0.0" + is-binary-path "^2.1.0" + is-glob "^4.0.1" + normalize-path "^3.0.0" + readdirp "^3.1.1" + optionalDependencies: + fsevents "^2.0.6" + chokidar@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.0.tgz#5fcb70d0b28ebe0867eb0f09d5f6a08f29a1efa0" @@ -2956,6 +2991,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" @@ -3228,6 +3270,11 @@ fsevents@^1.2.7: nan "^2.9.2" node-pre-gyp "^0.10.0" +fsevents@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a" + integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ== + fstream@^1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" @@ -3341,6 +3388,13 @@ glob-parent@^3.0.0, glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + glob-stream@^5.3.2: version "5.3.5" resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" @@ -4261,6 +4315,13 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-binary-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-buffer@^1.0.2: version "1.1.4" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" @@ -4377,6 +4438,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-my-json-valid@^2.12.4: version "2.16.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" @@ -4411,6 +4479,11 @@ is-number@^4.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -7056,6 +7129,13 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +readdirp@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.2.tgz#fa85d2d14d4289920e4671dead96431add2ee78a" + integrity sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw== + dependencies: + picomatch "^2.0.4" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -8295,6 +8375,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -8611,11 +8698,6 @@ upath@^1.0.5, upath@^1.1.0: resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== -upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - uri-js@^4.2.1, uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -8883,45 +8965,11 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" -vscode-anymatch@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vscode-anymatch/-/vscode-anymatch-3.0.3.tgz#5a79101e6df7e659a1f070367bc42f190eb4ae76" - integrity sha512-qQgfbzJJ5nNShh4jjC3BBekY4d8emcxHFgnqcXwsB/PUKvJPCg7AZYXM7hqS7EDnKrX9tsIFwFMihZ7yut92Qg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -vscode-chokidar@2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/vscode-chokidar/-/vscode-chokidar-2.1.7.tgz#c5b31eb87402f4779bb4170915245bdcb6f7854b" - integrity sha512-uSNEQetPjAlgIAHmcF9E6M+KCw0f842rsEnJ64aamUAV6TO7gkXNCvLSzb4MuLsPU7ZQyCa++DrLQFjvciK5dg== - dependencies: - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - vscode-anymatch "3.0.3" - optionalDependencies: - vscode-fsevents "1.2.12" - vscode-debugprotocol@1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.36.0.tgz#88e6246045480a9cc643e819b597396eaa9d0f4b" integrity sha512-F0MfcUkF88TfNf4iQbcmC+K9rA+zsrQpEz1XpTKidy5sMq8sYsJGUadYDGmmktfjRX+S/ebjHgM+YV/2qm6lVQ== -vscode-fsevents@1.2.12: - version "1.2.12" - resolved "https://registry.yarnpkg.com/vscode-fsevents/-/vscode-fsevents-1.2.12.tgz#01a71a01f90ee95ca822c34427aba437a17c03a7" - integrity sha512-bH/jRdDpSesGpqiVLjp6gHLSKUOh7oNvppzZ17JIrdbRYCcDmV7dIWR5gQc27DFy0RD9JDT+t+ixMid94MkM1A== - dependencies: - nan "^2.14.0" - vscode-minimist@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/vscode-minimist/-/vscode-minimist-1.2.1.tgz#e63d3f4a9bf3680dcb8f9304eed612323fd6926a" From 136600a7bba1ac75a7256b5cd9cd52b103f75208 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 17 Sep 2019 09:58:33 +0200 Subject: [PATCH 19/82] miss compilation --- build/lib/i18n.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/lib/i18n.js b/build/lib/i18n.js index b8a396a8d67..27a4054a1e4 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -176,6 +176,7 @@ class XLF { this.buffer.push(line.toString()); } } +exports.XLF = XLF; XLF.parsePseudo = function (xlfString) { return new Promise((resolve) => { let parser = new xml2js.Parser(); @@ -248,7 +249,6 @@ XLF.parse = function (xlfString) { }); }); }; -exports.XLF = XLF; class Limiter { constructor(maxDegreeOfParalellism) { this.maxDegreeOfParalellism = maxDegreeOfParalellism; From 227cebfac7c8b0f6dfeff122b5f9686b8286e903 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 17 Sep 2019 09:58:43 +0200 Subject: [PATCH 20/82] fixes #80671 --- extensions/git/src/decorationProvider.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index 92f2ffd126a..f0c419e502d 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor } from 'vscode'; +import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor, StatusBarAlignment } from 'vscode'; import * as path from 'path'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; import { debounce } from './decorators'; import { filterEvent, dispose, anyEvent, fireEvent } from './util'; -import { GitErrorCodes } from './api/git'; +import { GitErrorCodes, Status } from './api/git'; type Callback = { resolve: (status: boolean) => void, reject: (err: any) => void }; @@ -122,12 +122,18 @@ class GitDecorationProvider implements DecorationProvider { } private collectDecorationData(group: GitResourceGroup, bucket: Map): void { - group.resourceStates.forEach(r => { - if (r.resourceDecoration) { + for (const r of group.resourceStates) { + const decoration = r.resourceDecoration; + + if (decoration) { // not deleted and has a decoration - bucket.set(r.original.toString(), r.resourceDecoration); + bucket.set(r.original.toString(), decoration); + + if (r.type === Status.INDEX_RENAMED) { + bucket.set(r.resourceUri.toString(), decoration); + } } - }); + } } private collectSubmoduleDecorationData(bucket: Map): void { From 4aa94e20ed1946b95c42338a76b9223526539f12 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 17 Sep 2019 10:30:12 +0200 Subject: [PATCH 21/82] remove unused import --- extensions/git/src/decorationProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts index f0c419e502d..1b36349886e 100644 --- a/extensions/git/src/decorationProvider.ts +++ b/extensions/git/src/decorationProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor, StatusBarAlignment } from 'vscode'; +import { window, workspace, Uri, Disposable, Event, EventEmitter, Decoration, DecorationProvider, ThemeColor } from 'vscode'; import * as path from 'path'; import { Repository, GitResourceGroup } from './repository'; import { Model } from './model'; From 2105bcef65f603bfe364e5bc0e5d2468657f2081 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 11:28:03 +0200 Subject: [PATCH 22/82] debt - introduce electron service and adopt for showMessageBox --- src/vs/code/electron-main/app.ts | 9 ++- .../standalone/browser/simpleServices.ts | 4 ++ src/vs/platform/dialogs/common/dialogs.ts | 6 +- .../{node => electron-browser}/dialogIpc.ts | 21 +----- .../electron-browser/electronService.ts | 28 ++++++++ .../electron-main/electronMainService.ts | 59 +++++++++++++++ src/vs/platform/electron/node/electron.ts | 17 +++++ src/vs/platform/windows/common/windows.ts | 1 - src/vs/platform/windows/common/windowsIpc.ts | 1 - .../electron-browser/windowsService.ts | 4 -- .../windows/electron-main/windowsService.ts | 54 +------------- .../browser/actions/windowActions.ts | 7 +- .../workbench/browser/web.simpleservices.ts | 28 -------- .../electron-browser/remote.contribution.ts | 2 +- .../dialogs/browser/dialogService.ts | 26 ++++++- .../dialogs/electron-browser/dialogService.ts | 71 +++++++++++++++++-- .../api/extHostMessagerService.test.ts | 4 ++ .../workbench/test/workbenchTestServices.ts | 8 +-- src/vs/workbench/workbench.desktop.main.ts | 3 + src/vs/workbench/workbench.web.main.ts | 4 +- 20 files changed, 232 insertions(+), 125 deletions(-) rename src/vs/platform/dialogs/{node => electron-browser}/dialogIpc.ts (58%) create mode 100644 src/vs/platform/electron/electron-browser/electronService.ts create mode 100644 src/vs/platform/electron/electron-main/electronMainService.ts create mode 100644 src/vs/platform/electron/node/electron.ts rename src/vs/{platform => workbench/services}/dialogs/browser/dialogService.ts (82%) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 12c5430291d..48fdc991536 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -77,6 +77,8 @@ import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { ElectronMainService, ElectronChannel } from 'vs/platform/electron/electron-main/electronMainService'; export class CodeApplication extends Disposable { @@ -423,7 +425,6 @@ export class CodeApplication extends Disposable { private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise>): Promise { const services = new ServiceCollection(); - // Files const fileService = this._register(new FileService(this.logService)); services.set(IFileService, fileService); @@ -456,6 +457,7 @@ export class CodeApplication extends Disposable { services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel])); services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv])); + services.set(IElectronService, new SyncDescriptor(ElectronMainService)); services.set(IMenubarService, new SyncDescriptor(MenubarService)); const storageMainService = new StorageMainService(this.logService, this.environmentService); @@ -541,6 +543,10 @@ export class CodeApplication extends Disposable { const issueChannel = new IssueChannel(issueService); electronIpcServer.registerChannel('issue', issueChannel); + const electronService = accessor.get(IElectronService); + const electronChannel = new ElectronChannel(electronService); + electronIpcServer.registerChannel('electron', electronChannel); + const workspacesService = accessor.get(IWorkspacesMainService); const workspacesChannel = new WorkspacesChannel(workspacesService); electronIpcServer.registerChannel('workspaces', workspacesChannel); @@ -562,7 +568,6 @@ export class CodeApplication extends Disposable { const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService)); electronIpcServer.registerChannel('storage', storageChannel); - // Log level management const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService)); electronIpcServer.registerChannel('loglevel', logLevelChannel); sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 8989321aead..d0da84973a7 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -186,6 +186,10 @@ export class SimpleDialogService implements IDialogService { public show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { return Promise.resolve({ choice: 0 }); } + + public about(): Promise { + return Promise.resolve(undefined); + } } export class SimpleNotificationService implements INotificationService { diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 559f1c3afb4..faffec2aa1e 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -172,6 +172,11 @@ export interface IDialogService { * option then promise with index `0` is returned. */ show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise; + + /** + * Present the about dialog to the user. + */ + about(): Promise; } export const IFileDialogService = createDecorator('fileDialogService'); @@ -235,7 +240,6 @@ export interface IFileDialogService { * Shows a open file dialog and returns the chosen file URI. */ showOpenDialog(options: IOpenDialogOptions): Promise; - } const MAX_CONFIRM_FILES = 10; diff --git a/src/vs/platform/dialogs/node/dialogIpc.ts b/src/vs/platform/dialogs/electron-browser/dialogIpc.ts similarity index 58% rename from src/vs/platform/dialogs/node/dialogIpc.ts rename to src/vs/platform/dialogs/electron-browser/dialogIpc.ts index 00db1a7bf21..d3d57643920 100644 --- a/src/vs/platform/dialogs/node/dialogIpc.ts +++ b/src/vs/platform/dialogs/electron-browser/dialogIpc.ts @@ -3,9 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IDialogService, IConfirmation, IConfirmationResult, IShowResult } from 'vs/platform/dialogs/common/dialogs'; -import Severity from 'vs/base/common/severity'; +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { Event } from 'vs/base/common/event'; export class DialogChannel implements IServerChannel { @@ -20,22 +19,8 @@ export class DialogChannel implements IServerChannel { switch (command) { case 'show': return this.dialogService.show(args![0], args![1], args![2]); case 'confirm': return this.dialogService.confirm(args![0]); + case 'about': return this.dialogService.about(); } return Promise.reject(new Error('invalid command')); } } - -export class DialogChannelClient implements IDialogService { - - _serviceBrand: undefined; - - constructor(private channel: IChannel) { } - - show(severity: Severity, message: string, options: string[]): Promise { - return this.channel.call('show', [severity, message, options]); - } - - confirm(confirmation: IConfirmation): Promise { - return this.channel.call('confirm', [confirmation]); - } -} diff --git a/src/vs/platform/electron/electron-browser/electronService.ts b/src/vs/platform/electron/electron-browser/electronService.ts new file mode 100644 index 00000000000..fa2b5f09b18 --- /dev/null +++ b/src/vs/platform/electron/electron-browser/electronService.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; + +export class ElectronService { + + _serviceBrand: undefined; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + const channel = mainProcessService.getChannel('electron'); + + // Proxy: forward any property access to the channel + return new Proxy({}, { + get(_target, propKey, _receiver) { + if (typeof propKey === 'string') { + return function (...args: any[]) { + return channel.call(propKey, ...args); + }; + } + + throw new Error(`Not Implemented in ElectronService: ${String(propKey)}`); + } + }) as ElectronService; + } +} diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts new file mode 100644 index 00000000000..a8c92d2414b --- /dev/null +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { MessageBoxOptions, MessageBoxReturnValue } from 'electron'; +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; + +export class ElectronMainService implements IElectronService { + + _serviceBrand: undefined; + + constructor( + @IWindowsMainService private readonly windowsMainService: IWindowsMainService + ) { + } + + private get window(): ICodeWindow | undefined { + return this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); + } + + async showMessageBox(options: MessageBoxOptions): Promise { + const result = await this.windowsMainService.showMessageBox(options, this.window); + + return { + response: result.button, + checkboxChecked: !!result.checkboxChecked + }; + } +} + +export class ElectronChannel implements IServerChannel { + + private service: { [key: string]: unknown }; + + constructor(service: IElectronService) { + this.service = service as unknown as { [key: string]: unknown }; + } + + listen(_: unknown, event: string): Event { + throw new Error(`Event not found: ${event}`); + } + + call(_: unknown, command: string, arg?: any): Promise { + const target = this.service[command]; + if (typeof target === 'function') { + if (Array.isArray(arg)) { + return target.apply(this.service, arg); + } + + return target.call(this.service, arg); + } + + throw new Error(`Call Not Found in ElectronService: ${command}`); + } +} diff --git a/src/vs/platform/electron/node/electron.ts b/src/vs/platform/electron/node/electron.ts new file mode 100644 index 00000000000..0f6c3a83091 --- /dev/null +++ b/src/vs/platform/electron/node/electron.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { MessageBoxOptions, MessageBoxReturnValue } from 'electron'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IElectronService = createDecorator('electronService'); + +export interface IElectronService { + + _serviceBrand: undefined; + + // Dialogs + showMessageBox(options: MessageBoxOptions): Promise; +} diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 57ffdc63bc0..7f697c0d445 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -167,7 +167,6 @@ export interface IWindowsService { // TODO: this is a bit backwards startCrashReporter(config: CrashReporterStartOptions): Promise; - openAboutDialog(): Promise; resolveProxy(windowId: number, url: string): Promise; } diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 3cdf71e2f4a..5e3c0944d94 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -114,7 +114,6 @@ export class WindowsChannel implements IServerChannel { case 'getActiveWindowId': return this.service.getActiveWindowId(); case 'openExternal': return this.service.openExternal(arg); case 'startCrashReporter': return this.service.startCrashReporter(arg); - case 'openAboutDialog': return this.service.openAboutDialog(); case 'resolveProxy': return this.service.resolveProxy(arg[0], arg[1]); } diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index 9321a89c8a6..d6089d90776 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -250,10 +250,6 @@ export class WindowsService implements IWindowsService { return this.channel.call('updateTouchBar', [windowId, items]); } - openAboutDialog(): Promise { - return this.channel.call('openAboutDialog'); - } - resolveProxy(windowId: number, url: string): Promise { return Promise.resolve(this.channel.call('resolveProxy', [windowId, url])); } diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 81b232cd0ba..7d7d9b4f201 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -3,15 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; -import * as os from 'os'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; -import product from 'vs/platform/product/common/product'; import { IWindowsService, OpenContext, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IDevToolsOptions, INewWindowOptions, IOpenSettings, IURIToOpen } from 'vs/platform/windows/common/windows'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { shell, crashReporter, app, Menu, clipboard } from 'electron'; +import { shell, crashReporter, app, Menu } from 'electron'; import { Event } from 'vs/base/common/event'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; @@ -20,8 +17,7 @@ import { IHistoryMainService, IRecentlyOpened, IRecent } from 'vs/platform/histo import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { Schemas } from 'vs/base/common/network'; -import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { isMacintosh, isLinux, IProcessEnvironment } from 'vs/base/common/platform'; +import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; export class WindowsService extends Disposable implements IWindowsService, IURLHandler { @@ -407,52 +403,6 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH } - async openAboutDialog(): Promise { - this.logService.trace('windowsService#openAboutDialog'); - - let version = app.getVersion(); - if (product.target) { - version = `${version} (${product.target} setup)`; - } - - const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION; - const detail = nls.localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", - version, - product.commit || 'Unknown', - product.date || 'Unknown', - process.versions['electron'], - process.versions['chrome'], - process.versions['node'], - process.versions['v8'], - `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}` - ); - - const ok = nls.localize('okButton', "OK"); - const copy = mnemonicButtonLabel(nls.localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy")); - let buttons: string[]; - if (isLinux) { - buttons = [copy, ok]; - } else { - buttons = [ok, copy]; - } - - const result = await this.windowsMainService.showMessageBox({ - title: product.nameLong, - type: 'info', - message: product.nameLong, - detail: `\n${detail}`, - buttons, - noLink: true, - defaultId: buttons.indexOf(ok), - cancelId: buttons.indexOf(ok) - }, this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow()); - - if (buttons[result.button] === copy) { - clipboard.writeText(detail); - } - } - async handleURL(uri: URI): Promise { // Catch file URLs diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 0f57a22be53..5c4d1d63c1e 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -7,7 +7,8 @@ import 'vs/css!./media/actions'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IWindowService, IURIToOpen, IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -234,13 +235,13 @@ class ShowAboutDialogAction extends Action { constructor( id: string, label: string, - @IWindowsService private readonly windowsService: IWindowsService + @IDialogService private readonly dialogService: IDialogService ) { super(id, label); } run(): Promise { - return this.windowsService.openAboutDialog(); + return this.dialogService.about(); } } diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 81f898eb98d..86e496ceedd 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -23,11 +23,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IProductService } from 'vs/platform/product/common/productService'; -import Severity from 'vs/base/common/severity'; -import { localize } from 'vs/nls'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; //#region Window @@ -332,13 +327,6 @@ export class SimpleWindowsService implements IWindowsService { readonly onWindowUnmaximize: Event = Event.None; readonly onRecentlyOpenedChange: Event = Event.None; - constructor( - @IDialogService private readonly dialogService: IDialogService, - @IProductService private readonly productService: IProductService, - @IClipboardService private readonly clipboardService: IClipboardService - ) { - } - isFocused(_windowId: number): Promise { return Promise.resolve(true); } @@ -585,22 +573,6 @@ export class SimpleWindowsService implements IWindowsService { throw new Error('not implemented'); } - async openAboutDialog(): Promise { - const detail = localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", - this.productService.version || 'Unknown', - this.productService.commit || 'Unknown', - this.productService.date || 'Unknown', - navigator.userAgent - ); - - const { choice } = await this.dialogService.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail }); - - if (choice === 0) { - this.clipboardService.writeText(detail); - } - } - resolveProxy(windowId: number, url: string): Promise { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 185c5a1d085..3af7ae70e3a 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -24,7 +24,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { ILogService } from 'vs/platform/log/common/log'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; +import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc'; import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; import { ipcRenderer as ipc } from 'electron'; diff --git a/src/vs/platform/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts similarity index 82% rename from src/vs/platform/dialogs/browser/dialogService.ts rename to src/vs/workbench/services/dialogs/browser/dialogService.ts index 5ddc105e993..495d0ea725f 100644 --- a/src/vs/platform/dialogs/browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts @@ -15,8 +15,12 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventHelper } from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class DialogService implements IDialogService { + _serviceBrand: undefined; private allowableCommands = ['copy', 'cut']; @@ -25,7 +29,9 @@ export class DialogService implements IDialogService { @ILogService private readonly logService: ILogService, @ILayoutService private readonly layoutService: ILayoutService, @IThemeService private readonly themeService: IThemeService, - @IKeybindingService private readonly keybindingService: IKeybindingService + @IKeybindingService private readonly keybindingService: IKeybindingService, + @IProductService private readonly productService: IProductService, + @IClipboardService private readonly clipboardService: IClipboardService ) { } async confirm(confirmation: IConfirmation): Promise { @@ -113,4 +119,22 @@ export class DialogService implements IDialogService { checkboxChecked: result.checkboxChecked }; } + + async about(): Promise { + const detail = nls.localize('aboutDetail', + "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + this.productService.version || 'Unknown', + this.productService.commit || 'Unknown', + this.productService.date || 'Unknown', + navigator.userAgent + ); + + const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail }); + + if (choice === 0) { + this.clipboardService.writeText(detail); + } + } } + +registerSingleton(IDialogService, DialogService, true); diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index cdc8cf34c4f..974ab501949 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -4,21 +4,25 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; +import * as os from 'os'; import product from 'vs/platform/product/common/product'; import Severity from 'vs/base/common/severity'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IShowResult } from 'vs/platform/dialogs/common/dialogs'; -import { DialogService as HTMLDialogService } from 'vs/platform/dialogs/browser/dialogService'; +import { DialogService as HTMLDialogService } from 'vs/workbench/services/dialogs/browser/dialogService'; import { ILogService } from 'vs/platform/log/common/log'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; +import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IElectronService } from 'vs/platform/electron/node/electron'; interface IMassagedMessageBoxOptions { @@ -36,6 +40,7 @@ interface IMassagedMessageBoxOptions { } export class DialogService implements IDialogService { + _serviceBrand: undefined; private impl: IDialogService; @@ -47,25 +52,33 @@ export class DialogService implements IDialogService { @IThemeService themeService: IThemeService, @IWindowService windowService: IWindowService, @ISharedProcessService sharedProcessService: ISharedProcessService, - @IKeybindingService keybindingService: IKeybindingService + @IKeybindingService keybindingService: IKeybindingService, + @IProductService productService: IProductService, + @IClipboardService clipboardService: IClipboardService, + @IElectronService electronService: IElectronService ) { // Use HTML based dialogs if (configurationService.getValue('workbench.dialogs.customEnabled') === true) { - this.impl = new HTMLDialogService(logService, layoutService, themeService, keybindingService); + this.impl = new HTMLDialogService(logService, layoutService, themeService, keybindingService, productService, clipboardService); } // Electron dialog service else { - this.impl = new NativeDialogService(windowService, logService, sharedProcessService); + this.impl = new NativeDialogService(windowService, logService, sharedProcessService, electronService, clipboardService); } } confirm(confirmation: IConfirmation): Promise { return this.impl.confirm(confirmation); } + show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions | undefined): Promise { return this.impl.show(severity, message, buttons, options); } + + about(): Promise { + return this.impl.about(); + } } class NativeDialogService implements IDialogService { @@ -75,7 +88,9 @@ class NativeDialogService implements IDialogService { constructor( @IWindowService private readonly windowService: IWindowService, @ILogService private readonly logService: ILogService, - @ISharedProcessService sharedProcessService: ISharedProcessService + @ISharedProcessService sharedProcessService: ISharedProcessService, + @IElectronService private readonly electronService: IElectronService, + @IClipboardService private readonly clipboardService: IClipboardService ) { sharedProcessService.registerChannel('dialog', new DialogChannel(this)); } @@ -189,6 +204,50 @@ class NativeDialogService implements IDialogService { return { options, buttonIndexMap }; } + + async about(): Promise { + let version = product.version; + if (product.target) { + version = `${version} (${product.target} setup)`; + } + + const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION; + const detail = nls.localize('aboutDetail', + "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", + version, + product.commit || 'Unknown', + product.date || 'Unknown', + process.versions['electron'], + process.versions['chrome'], + process.versions['node'], + process.versions['v8'], + `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}` + ); + + const ok = nls.localize('okButton', "OK"); + const copy = mnemonicButtonLabel(nls.localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy")); + let buttons: string[]; + if (isLinux) { + buttons = [copy, ok]; + } else { + buttons = [ok, copy]; + } + + const result = await this.electronService.showMessageBox({ + title: product.nameLong, + type: 'info', + message: product.nameLong, + detail: `\n${detail}`, + buttons, + noLink: true, + defaultId: buttons.indexOf(ok), + cancelId: buttons.indexOf(ok) + }); + + if (buttons[result.response] === copy) { + this.clipboardService.writeText(detail); + } + } } registerSingleton(IDialogService, DialogService, true); diff --git a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts index b3f8ec0258a..307a8e3cf63 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -20,6 +20,10 @@ const emptyDialogService = new class implements IDialogService { confirm(): never { throw new Error('not implemented'); } + + about(): never { + throw new Error('not implemented'); + } }; const emptyCommandService: ICommandService = { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 240bdc365f3..6c4add507aa 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -402,6 +402,10 @@ export class TestDialogService implements IDialogService { public show(_severity: Severity, _message: string, _buttons: string[], _options?: IDialogOptions): Promise { return Promise.resolve({ choice: 0 }); } + + public about(): Promise { + return Promise.resolve(); + } } export class TestFileDialogService implements IFileDialogService { @@ -1553,10 +1557,6 @@ export class TestWindowsService implements IWindowsService { throw new Error('not implemented'); } - openAboutDialog(): Promise { - return Promise.resolve(); - } - resolveProxy(windowId: number, url: string): Promise { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 8cfb27e7fa1..f22592cb8fe 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -68,6 +68,8 @@ import { IIssueService } from 'vs/platform/issue/node/issue'; import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { ElectronService } from 'vs/platform/electron/electron-browser/electronService'; registerSingleton(IClipboardService, ClipboardService, true); registerSingleton(IRequestService, RequestService, true); @@ -78,6 +80,7 @@ registerSingleton(IWindowsService, WindowsService); registerSingleton(IUpdateService, UpdateService); registerSingleton(IIssueService, IssueService); registerSingleton(IMenubarService, MenubarService); +registerSingleton(IElectronService, ElectronService, true); //#endregion diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 8c8a470aa8a..dc8eb1bb5e6 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -41,6 +41,7 @@ import 'vs/workbench/services/url/browser/urlService'; import 'vs/workbench/services/update/browser/updateService'; import 'vs/workbench/contrib/stats/browser/workspaceStatsService'; import 'vs/workbench/services/workspace/browser/workspacesService'; +import 'vs/workbench/services/dialogs/browser/dialogService'; import 'vs/workbench/browser/web.simpleservices'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -53,8 +54,6 @@ import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/ac import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { DialogService } from 'vs/platform/dialogs/browser/dialogService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -66,7 +65,6 @@ import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; registerSingleton(IRequestService, RequestService, true); registerSingleton(IExtensionManagementService, ExtensionManagementService); registerSingleton(IBackupFileService, BackupFileService); -registerSingleton(IDialogService, DialogService, true); registerSingleton(IClipboardService, BrowserClipboardService, true); registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); registerSingleton(ILifecycleService, BrowserLifecycleService); From 703480e6a131143c5d3f98839d1d83d930a77943 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Sep 2019 11:48:41 +0200 Subject: [PATCH 23/82] breakpoints: introduce InlineBreakpointWidget --- .../browser/breakpointEditorContribution.ts | 102 ++++++++++++++++-- .../browser/media/debug.contribution.css | 31 ++++-- 2 files changed, 115 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 37109a1ba9f..53be1139b22 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -5,11 +5,12 @@ import * as nls from 'vs/nls'; import * as env from 'vs/base/common/platform'; +import * as dom from 'vs/base/browser/dom'; import { URI as uri } from 'vs/base/common/uri'; import severity from 'vs/base/common/severity'; import { IAction, Action } from 'vs/base/common/actions'; import { Range } from 'vs/editor/common/core/range'; -import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -25,11 +26,16 @@ import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointW import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView'; +import { generateUuid } from 'vs/base/common/uuid'; +import { memoize } from 'vs/base/common/decorators'; + +const $ = dom.$; interface IBreakpointDecoration { decorationId: string; breakpointId: string; range: Range; + inlineWidget?: InlineBreakpointWidget; } const breakpointHelperDecoration: IModelDecorationOptions = { @@ -74,7 +80,7 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi glyphMarginClassName: className, glyphMarginHoverMessage, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - beforeContentClassName: breakpoint.column ? `debug-breakpoint-column ${className}-column` : undefined + beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined }; } @@ -85,6 +91,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { private breakpointWidgetVisible: IContextKey; private toDispose: IDisposable[] = []; private ignoreDecorationsChangedEvent = false; + private ignoreFirstBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; constructor( @@ -191,7 +198,13 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.closeBreakpointWidget(); this.setDecorations(); })); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.setDecorations())); + this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => { + if (this.ignoreFirstBreakpointsChangeEvent) { + this.ignoreFirstBreakpointsChangeEvent = false; + return; + } + this.setDecorations(); + })); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); } @@ -304,17 +317,24 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { return; } - const model = this.editor.getModel(); + const activeCodeEditor = this.editor; + const model = activeCodeEditor.getModel(); const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri }); const desiredDecorations = createBreakpointDecorations(model, breakpoints, this.debugService); try { this.ignoreDecorationsChangedEvent = true; - const decorationIds = this.editor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredDecorations); + const decorationIds = activeCodeEditor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredDecorations); + this.breakpointDecorations.forEach(bpd => { + if (bpd.inlineWidget) { + bpd.inlineWidget.dispose(); + } + }); this.breakpointDecorations = decorationIds.map((decorationId, index) => ({ decorationId, breakpointId: breakpoints[index].getId(), - range: desiredDecorations[index].range + range: desiredDecorations[index].range, + inlineWidget: breakpoints[index].column ? new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredDecorations[index].options.glyphMarginClassName) : undefined })); } finally { this.ignoreDecorationsChangedEvent = false; @@ -360,7 +380,12 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } } - await this.debugService.updateBreakpoints(model.uri, data, true); + try { + this.ignoreFirstBreakpointsChangeEvent = true; + await this.debugService.updateBreakpoints(model.uri, data, true); + } finally { + this.ignoreFirstBreakpointsChangeEvent = false; + } } // breakpoint widget @@ -392,4 +417,67 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } } +class InlineBreakpointWidget implements IContentWidget, IDisposable { + + // editor.IContentWidget.allowEditorOverflow + allowEditorOverflow = false; + suppressMouseDown = true; + + private domNode!: HTMLElement; + private range: Range | null; + private toDispose: IDisposable[] = []; + + constructor( + private readonly editor: IActiveCodeEditor, + private readonly decorationId: string, + cssClass: string | null | undefined, + ) { + this.range = this.editor.getModel().getDecorationRange(decorationId); + this.toDispose.push(this.editor.onDidChangeModelDecorations(() => { + const model = this.editor.getModel(); + const range = model.getDecorationRange(this.decorationId); + if (this.range && !this.range.equalsRange(range)) { + this.range = range; + this.editor.layoutContentWidget(this); + } + })); + this.create(cssClass); + + this.editor.addContentWidget(this); + this.editor.layoutContentWidget(this); + } + + private create(cssClass: string | null | undefined): void { + this.domNode = $('.inline-breakpoint-widget'); + if (cssClass) { + this.domNode.classList.add(cssClass); + } + } + + @memoize + getId(): string { + return generateUuid(); + } + + getDomNode(): HTMLElement { + return this.domNode; + } + + getPosition(): IContentWidgetPosition | null { + if (!this.range) { + return null; + } + + return { + position: { lineNumber: this.range.startLineNumber, column: this.range.startColumn - 1 }, + preference: [ContentWidgetPositionPreference.EXACT] + }; + } + + dispose(): void { + this.editor.removeContentWidget(this); + dispose(this.toDispose); + } +} + registerEditorContribution(BreakpointEditorContribution); diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 12269752f10..69be074454c 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -17,12 +17,12 @@ } .debug-breakpoint-disabled, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-disabled-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled { background: url('breakpoint-disabled.svg') center center no-repeat; } .debug-breakpoint-unverified, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-unverified-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified { background: url('breakpoint-unverified.svg') center center no-repeat; } @@ -35,21 +35,30 @@ } .debug-breakpoint, -.monaco-editor .debug-breakpoint-column::before { +.monaco-editor .inline-breakpoint-widget { background: url('breakpoint.svg') center center no-repeat; } -.monaco-editor .debug-breakpoint-column::before, +.monaco-editor .debug-breakpoint-placeholder::before, .monaco-editor .debug-top-stack-frame-column::before { content: " "; width: 1.3em; - height: 1.3em; display: inline-block; vertical-align: text-bottom; margin-right: 2px; margin-left: 2px; } +.monaco-editor .debug-top-stack-frame-column::before { + height: 1.3em; +} + +.monaco-editor .inline-breakpoint-widget { + width: 1.3em; + height: 1.3em; + margin-left: 0.61em; +} + .debug-function-breakpoint { background: url('breakpoint-function.svg') center center no-repeat; } @@ -75,34 +84,34 @@ } .debug-breakpoint-conditional, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-conditional { background: url('breakpoint-conditional.svg') center center no-repeat; } .debug-breakpoint-log, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-log-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log { background: url('breakpoint-log.svg') center center no-repeat; } .debug-breakpoint-log-disabled, -.monaco-editor .debug-breakpoint-log-disabled-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-disabled { background: url('breakpoint-log-disabled.svg') center center no-repeat; } .debug-breakpoint-log-unverified, -.monaco-editor .debug-breakpoint-log-unverified-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-unverified { background: url('breakpoint-log-unverified.svg') center center no-repeat; } .debug-breakpoint-unsupported, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-unsupported-column::before { +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unsupported { background: url('breakpoint-unsupported.svg') center center no-repeat; } .monaco-editor .debug-top-stack-frame.debug-breakpoint, .monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional, .monaco-editor .debug-top-stack-frame.debug-breakpoint-log, -.monaco-editor .debug-breakpoint-column.debug-breakpoint-column.debug-top-stack-frame-column::before { +.monaco-editor .inline-breakpoint-widget.debug-top-stack-frame-column { background: url('current-and-breakpoint.svg') center center no-repeat; } From f8c9cc7d6a09f97bf4e270c2782de653f17aa5af Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 17 Sep 2019 11:57:17 +0200 Subject: [PATCH 24/82] Move TreeView message API to stable Fixes #80401 --- src/vs/vscode.d.ts | 5 +++++ src/vs/vscode.proposed.d.ts | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 2fe649dab60..0d562ddd9cc 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -7014,6 +7014,11 @@ declare module 'vscode' { */ readonly onDidChangeVisibility: Event; + /** + * An optional human-readable message that will be rendered in the view. + */ + message?: string; + /** * Reveals the given element in the tree view. * If the tree view is not visible then the tree view is shown and element is revealed. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6e19978908a..8ca0b13ea65 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -820,12 +820,6 @@ declare module 'vscode' { //#region Tree View export interface TreeView { - - /** - * An optional human-readable message that will be rendered in the view. - */ - message?: string; - /** * The name of the tree view. It is set from the extension package.json and can be changed later. */ From 09daf8869e92b2ff4391b4574172efd37febd731 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 17 Sep 2019 12:54:27 +0200 Subject: [PATCH 25/82] Move remote file dialog local commands to electron browser Fixes #80959 --- .../browser/actions/workspaceActions.ts | 61 +------------------ src/vs/workbench/common/actions.ts | 21 +++++++ .../electron-browser/remote.contribution.ts | 13 ++-- .../actions/workspaceActions.ts | 49 +++++++++++++++ .../dialogs/browser/remoteFileDialog.ts | 2 +- 5 files changed, 79 insertions(+), 67 deletions(-) diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 8818bc1131c..49a07317c43 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -9,13 +9,9 @@ import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ICommandService, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { Schemas } from 'vs/base/common/network'; -import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; -import { toResource } from 'vs/workbench/common/editor'; -import { URI } from 'vs/base/common/uri'; import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { WorkbenchStateContext, SupportsWorkspacesContext } from 'vs/workbench/browser/contextkeys'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -40,36 +36,6 @@ export class OpenFileAction extends Action { } } -export namespace OpenLocalFileCommand { - export const ID = 'workbench.action.files.openLocalFile'; - export const LABEL = nls.localize('openLocalFile', "Open Local File..."); - - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} - -export namespace SaveLocalFileCommand { - export const ID = 'workbench.action.files.saveLocalFile'; - export const LABEL = nls.localize('saveLocalFile', "Save Local File..."); - - export function handler(): ICommandHandler { - return accessor => { - const textFileService = accessor.get(ITextFileService); - const editorService = accessor.get(IEditorService); - let resource: URI | undefined = toResource(editorService.activeEditor); - const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] }; - if (resource) { - return textFileService.saveAs(resource, undefined, options); - } - return Promise.resolve(undefined); - }; - } -} - export class OpenFolderAction extends Action { static readonly ID = 'workbench.action.files.openFolder'; @@ -88,18 +54,6 @@ export class OpenFolderAction extends Action { } } -export namespace OpenLocalFolderCommand { - export const ID = 'workbench.action.files.openLocalFolder'; - export const LABEL = nls.localize('openLocalFolder', "Open Local Folder..."); - - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} - export class OpenFileFolderAction extends Action { static readonly ID = 'workbench.action.files.openFileFolder'; @@ -118,19 +72,6 @@ export class OpenFileFolderAction extends Action { } } -export namespace OpenLocalFileFolderCommand { - - export const ID = 'workbench.action.files.openLocalFileFolder'; - export const LABEL = nls.localize('openLocalFileFolder', "Open Local..."); - - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} - export class OpenWorkspaceAction extends Action { static readonly ID = 'workbench.action.openWorkspace'; diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 72c8dcaecc7..7a7b727662c 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -119,3 +120,23 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR } } }); + +export namespace OpenLocalFileCommand { + export const ID = 'workbench.action.files.openLocalFile'; + export const LABEL = nls.localize('openLocalFile', "Open Local File..."); +} + +export namespace SaveLocalFileCommand { + export const ID = 'workbench.action.files.saveLocalFile'; + export const LABEL = nls.localize('saveLocalFile', "Save Local File..."); +} + +export namespace OpenLocalFolderCommand { + export const ID = 'workbench.action.files.openLocalFolder'; + export const LABEL = nls.localize('openLocalFolder', "Open Local Folder..."); +} + +export namespace OpenLocalFileFolderCommand { + export const ID = 'workbench.action.files.openLocalFileFolder'; + export const LABEL = nls.localize('openLocalFileFolder', "Open Local..."); +} diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 3af7ae70e3a..eefaf76296a 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -33,12 +33,13 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { OpenFileFolderAction, OpenLocalFileFolderCommand, OpenFileAction, OpenFolderAction, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions, OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/common/actions'; +import { OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; import { IDownloadService } from 'vs/platform/download/common/download'; +import * as workspaceActions from 'vs/workbench/electron-browser/actions/workspaceActions'; const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions'; const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote'; @@ -387,7 +388,7 @@ if (isMacintosh) { primary: KeyMod.CtrlCmd | KeyCode.KEY_O, when: RemoteFileDialogContext, description: { description: OpenLocalFileFolderCommand.LABEL, args: [] }, - handler: OpenLocalFileFolderCommand.handler() + handler: workspaceActions.OpenLocalFileFolderCommand.handler() }); } else { registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); @@ -398,7 +399,7 @@ if (isMacintosh) { primary: KeyMod.CtrlCmd | KeyCode.KEY_O, when: RemoteFileDialogContext, description: { description: OpenLocalFileCommand.LABEL, args: [] }, - handler: OpenLocalFileCommand.handler() + handler: workspaceActions.OpenLocalFileCommand.handler() }); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OpenLocalFolderCommand.ID, @@ -406,7 +407,7 @@ if (isMacintosh) { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O), when: RemoteFileDialogContext, description: { description: OpenLocalFolderCommand.LABEL, args: [] }, - handler: OpenLocalFolderCommand.handler() + handler: workspaceActions.OpenLocalFolderCommand.handler() }); } @@ -416,5 +417,5 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S, when: RemoteFileDialogContext, description: { description: SaveLocalFileCommand.LABEL, args: [] }, - handler: SaveLocalFileCommand.handler() + handler: workspaceActions.SaveLocalFileCommand.handler() }); diff --git a/src/vs/workbench/electron-browser/actions/workspaceActions.ts b/src/vs/workbench/electron-browser/actions/workspaceActions.ts index c01580637dd..0e3d0d43e5c 100644 --- a/src/vs/workbench/electron-browser/actions/workspaceActions.ts +++ b/src/vs/workbench/electron-browser/actions/workspaceActions.ts @@ -11,6 +11,13 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { ICommandHandler } from 'vs/platform/commands/common/commands'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { Schemas } from 'vs/base/common/network'; +import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { toResource } from 'vs/workbench/common/editor'; +import { URI } from 'vs/base/common/uri'; export class SaveWorkspaceAsAction extends Action { @@ -95,3 +102,45 @@ export class CloseWorkspaceAction extends Action { return this.windowService.closeWorkspace(); } } + +export namespace OpenLocalFileCommand { + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} + +export namespace SaveLocalFileCommand { + export function handler(): ICommandHandler { + return accessor => { + const textFileService = accessor.get(ITextFileService); + const editorService = accessor.get(IEditorService); + let resource: URI | undefined = toResource(editorService.activeEditor); + const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] }; + if (resource) { + return textFileService.saveAs(resource, undefined, options); + } + return Promise.resolve(undefined); + }; + } +} + +export namespace OpenLocalFolderCommand { + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} + +export namespace OpenLocalFileFolderCommand { + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 9354baad058..f21dad72cef 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -23,7 +23,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings'; -import { OpenLocalFileCommand, OpenLocalFileFolderCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions'; +import { OpenLocalFileCommand, OpenLocalFileFolderCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { isValidBasename } from 'vs/base/common/extpath'; From 96bf508c70035d9a3a4b6d492063ea5019b79ba3 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 17 Sep 2019 15:17:10 +0200 Subject: [PATCH 26/82] Move remote dialog local commands into remoteFileDialog.ts Fixes #80959 --- src/vs/workbench/common/actions.ts | 21 ------- .../electron-browser/remote.contribution.ts | 12 ++-- .../actions/workspaceActions.ts | 49 ----------------- .../dialogs/browser/remoteFileDialog.ts | 55 ++++++++++++++++++- 4 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 7a7b727662c..72c8dcaecc7 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -120,23 +119,3 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR } } }); - -export namespace OpenLocalFileCommand { - export const ID = 'workbench.action.files.openLocalFile'; - export const LABEL = nls.localize('openLocalFile', "Open Local File..."); -} - -export namespace SaveLocalFileCommand { - export const ID = 'workbench.action.files.saveLocalFile'; - export const LABEL = nls.localize('saveLocalFile', "Save Local File..."); -} - -export namespace OpenLocalFolderCommand { - export const ID = 'workbench.action.files.openLocalFolder'; - export const LABEL = nls.localize('openLocalFolder', "Open Local Folder..."); -} - -export namespace OpenLocalFileFolderCommand { - export const ID = 'workbench.action.files.openLocalFileFolder'; - export const LABEL = nls.localize('openLocalFileFolder', "Open Local..."); -} diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index eefaf76296a..37cae45ace2 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -33,13 +33,13 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions, OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/common/actions'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; import { IDownloadService } from 'vs/platform/download/common/download'; -import * as workspaceActions from 'vs/workbench/electron-browser/actions/workspaceActions'; +import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/services/dialogs/browser/remoteFileDialog'; const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions'; const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote'; @@ -388,7 +388,7 @@ if (isMacintosh) { primary: KeyMod.CtrlCmd | KeyCode.KEY_O, when: RemoteFileDialogContext, description: { description: OpenLocalFileFolderCommand.LABEL, args: [] }, - handler: workspaceActions.OpenLocalFileFolderCommand.handler() + handler: OpenLocalFileFolderCommand.handler() }); } else { registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); @@ -399,7 +399,7 @@ if (isMacintosh) { primary: KeyMod.CtrlCmd | KeyCode.KEY_O, when: RemoteFileDialogContext, description: { description: OpenLocalFileCommand.LABEL, args: [] }, - handler: workspaceActions.OpenLocalFileCommand.handler() + handler: OpenLocalFileCommand.handler() }); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OpenLocalFolderCommand.ID, @@ -407,7 +407,7 @@ if (isMacintosh) { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O), when: RemoteFileDialogContext, description: { description: OpenLocalFolderCommand.LABEL, args: [] }, - handler: workspaceActions.OpenLocalFolderCommand.handler() + handler: OpenLocalFolderCommand.handler() }); } @@ -417,5 +417,5 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S, when: RemoteFileDialogContext, description: { description: SaveLocalFileCommand.LABEL, args: [] }, - handler: workspaceActions.SaveLocalFileCommand.handler() + handler: SaveLocalFileCommand.handler() }); diff --git a/src/vs/workbench/electron-browser/actions/workspaceActions.ts b/src/vs/workbench/electron-browser/actions/workspaceActions.ts index 0e3d0d43e5c..c01580637dd 100644 --- a/src/vs/workbench/electron-browser/actions/workspaceActions.ts +++ b/src/vs/workbench/electron-browser/actions/workspaceActions.ts @@ -11,13 +11,6 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { Schemas } from 'vs/base/common/network'; -import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { toResource } from 'vs/workbench/common/editor'; -import { URI } from 'vs/base/common/uri'; export class SaveWorkspaceAsAction extends Action { @@ -102,45 +95,3 @@ export class CloseWorkspaceAction extends Action { return this.windowService.closeWorkspace(); } } - -export namespace OpenLocalFileCommand { - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} - -export namespace SaveLocalFileCommand { - export function handler(): ICommandHandler { - return accessor => { - const textFileService = accessor.get(ITextFileService); - const editorService = accessor.get(IEditorService); - let resource: URI | undefined = toResource(editorService.activeEditor); - const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] }; - if (resource) { - return textFileService.saveAs(resource, undefined, options); - } - return Promise.resolve(undefined); - }; - } -} - -export namespace OpenLocalFolderCommand { - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} - -export namespace OpenLocalFileFolderCommand { - export function handler(): ICommandHandler { - return accessor => { - const dialogService = accessor.get(IFileDialogService); - return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); - }; - } -} diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index f21dad72cef..d042a953970 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -23,7 +23,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings'; -import { OpenLocalFileCommand, OpenLocalFileFolderCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { isValidBasename } from 'vs/base/common/extpath'; @@ -32,6 +31,60 @@ import { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { ICommandHandler } from 'vs/platform/commands/common/commands'; +import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { toResource } from 'vs/workbench/common/editor'; + +export namespace OpenLocalFileCommand { + export const ID = 'workbench.action.files.openLocalFile'; + export const LABEL = nls.localize('openLocalFile', "Open Local File..."); + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} + +export namespace SaveLocalFileCommand { + export const ID = 'workbench.action.files.saveLocalFile'; + export const LABEL = nls.localize('saveLocalFile', "Save Local File..."); + export function handler(): ICommandHandler { + return accessor => { + const textFileService = accessor.get(ITextFileService); + const editorService = accessor.get(IEditorService); + let resource: URI | undefined = toResource(editorService.activeEditor); + const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] }; + if (resource) { + return textFileService.saveAs(resource, undefined, options); + } + return Promise.resolve(undefined); + }; + } +} + +export namespace OpenLocalFolderCommand { + export const ID = 'workbench.action.files.openLocalFolder'; + export const LABEL = nls.localize('openLocalFolder', "Open Local Folder..."); + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} + +export namespace OpenLocalFileFolderCommand { + export const ID = 'workbench.action.files.openLocalFileFolder'; + export const LABEL = nls.localize('openLocalFileFolder', "Open Local..."); + export function handler(): ICommandHandler { + return accessor => { + const dialogService = accessor.get(IFileDialogService); + return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] }); + }; + } +} interface FileQuickPickItem extends IQuickPickItem { uri: URI; From 3e439112ba6986b8b871290edba6b39cec5e8dcd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 15:29:54 +0200 Subject: [PATCH 27/82] debt - clean up platform/electron-main (part 1) --- .../contrib/storageDataCleaner.ts | 2 +- src/vs/code/electron-main/app.ts | 17 +++++++------- src/vs/code/electron-main/window.ts | 2 +- src/vs/code/electron-main/windows.ts | 6 +++-- .../{common => electron-main}/backup.ts | 21 ++---------------- .../backup/electron-main/backupMainService.ts | 3 ++- src/vs/platform/backup/node/backup.ts | 22 +++++++++++++++++++ .../electron-main/backupMainService.test.ts | 3 ++- .../diagnostics/node/diagnosticsIpc.ts | 2 +- .../diagnostics/node/diagnosticsService.ts | 2 +- src/vs/platform/history/common/history.ts | 18 --------------- .../electron-main/historyMainService.ts | 18 ++++++++++++++- .../issue/{node => electron-main}/issueIpc.ts | 0 .../{issueService.ts => issueMainService.ts} | 6 ++--- .../common/{launchService.ts => launch.ts} | 0 .../launch/electron-main/launchService.ts | 14 ++++++------ .../platform/menubar/electron-main/menubar.ts | 2 +- .../windows/electron-main/windowsService.ts | 3 ++- 18 files changed, 74 insertions(+), 67 deletions(-) rename src/vs/platform/backup/{common => electron-main}/backup.ts (71%) create mode 100644 src/vs/platform/backup/node/backup.ts rename src/vs/platform/issue/{node => electron-main}/issueIpc.ts (100%) rename src/vs/platform/issue/electron-main/{issueService.ts => issueMainService.ts} (98%) rename src/vs/platform/launch/common/{launchService.ts => launch.ts} (100%) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts index 5a2968a8357..d3a0e9dab87 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts @@ -8,7 +8,7 @@ import { join } from 'vs/base/common/path'; import { readdir, readFile, rimraf } from 'vs/base/node/pfs'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup'; +import { IBackupWorkspacesFormat } from 'vs/platform/backup/node/backup'; export class StorageDataCleaner extends Disposable { diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 48fdc991536..0f0c530c832 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -17,7 +17,7 @@ import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { Server, connect } from 'vs/base/parts/ipc/node/ipc.net'; import { SharedProcess } from 'vs/code/electron-main/sharedProcess'; -import { LaunchService, LaunchChannel, ILaunchService } from 'vs/platform/launch/electron-main/launchService'; +import { LaunchMainService, LaunchChannel, ILaunchMainService } from 'vs/platform/launch/electron-main/launchService'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -37,7 +37,6 @@ import product from 'vs/platform/product/common/product'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { IHistoryMainService } from 'vs/platform/history/common/history'; import { URI } from 'vs/base/common/uri'; import { WorkspacesChannel } from 'vs/platform/workspaces/electron-main/workspacesIpc'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; @@ -46,8 +45,8 @@ import { Win32UpdateService } from 'vs/platform/update/electron-main/updateServi import { LinuxUpdateService } from 'vs/platform/update/electron-main/updateService.linux'; import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateService.darwin'; import { IIssueService } from 'vs/platform/issue/node/issue'; -import { IssueChannel } from 'vs/platform/issue/node/issueIpc'; -import { IssueService } from 'vs/platform/issue/electron-main/issueService'; +import { IssueChannel } from 'vs/platform/issue/electron-main/issueIpc'; +import { IssueMainService } from 'vs/platform/issue/electron-main/issueMainService'; import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/errors'; import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener'; @@ -66,8 +65,8 @@ import { IStorageMainService, StorageMainService } from 'vs/platform/storage/nod import { GlobalStorageDatabaseChannel } from 'vs/platform/storage/node/storageIpc'; import { startsWith } from 'vs/base/common/strings'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; -import { IBackupMainService } from 'vs/platform/backup/common/backup'; -import { HistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; +import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; +import { HistoryMainService, IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; import { URLService } from 'vs/platform/url/node/urlService'; import { WorkspacesMainService, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { statSync } from 'fs'; @@ -451,12 +450,12 @@ export class CodeApplication extends Disposable { services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv])); services.set(IWindowsService, new SyncDescriptor(WindowsService, [sharedProcess])); - services.set(ILaunchService, new SyncDescriptor(LaunchService)); + services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService)); const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics'))); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel])); - services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv])); + services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv])); services.set(IElectronService, new SyncDescriptor(ElectronMainService)); services.set(IMenubarService, new SyncDescriptor(MenubarService)); @@ -530,7 +529,7 @@ export class CodeApplication extends Disposable { private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise>): ICodeWindow[] { // Register more Main IPC services - const launchService = accessor.get(ILaunchService); + const launchService = accessor.get(ILaunchMainService); const launchChannel = new LaunchChannel(launchService); this.mainIpcServer.registerChannel('launch', launchChannel); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 0ec81879f16..b31d99e0315 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -19,7 +19,7 @@ import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IBackupMainService } from 'vs/platform/backup/common/backup'; +import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import * as perf from 'vs/base/common/performance'; import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService'; diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 9739fb60c6e..d00c5e99aab 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -8,7 +8,8 @@ import { basename, normalize, join, dirname } from 'vs/base/common/path'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; -import { IBackupMainService, IEmptyWindowBackupInfo } from 'vs/platform/backup/common/backup'; +import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; +import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IStateService } from 'vs/platform/state/common/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; @@ -23,7 +24,8 @@ import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product/common/product'; import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; -import { IHistoryMainService, IRecent } from 'vs/platform/history/common/history'; +import { IRecent } from 'vs/platform/history/common/history'; +import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform'; import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/platform/backup/common/backup.ts b/src/vs/platform/backup/electron-main/backup.ts similarity index 71% rename from src/vs/platform/backup/common/backup.ts rename to src/vs/platform/backup/electron-main/backup.ts index eafe3e2ed5f..2b471039ae0 100644 --- a/src/vs/platform/backup/common/backup.ts +++ b/src/vs/platform/backup/electron-main/backup.ts @@ -6,27 +6,10 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; - -export interface ISerializedWorkspace { id: string; configURIPath: string; remoteAuthority?: string; } - -export interface IBackupWorkspacesFormat { - rootURIWorkspaces: ISerializedWorkspace[]; - folderURIWorkspaces: string[]; - emptyWorkspaceInfos: IEmptyWindowBackupInfo[]; - - // deprecated - folderWorkspaces?: string[]; // use folderURIWorkspaces instead - emptyWorkspaces?: string[]; - rootWorkspaces?: { id: string, configPath: string }[]; // use rootURIWorkspaces instead -} +import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; export const IBackupMainService = createDecorator('backupMainService'); -export interface IEmptyWindowBackupInfo { - backupFolder: string; - remoteAuthority?: string; -} - export interface IWorkspaceBackupInfo { workspace: IWorkspaceIdentifier; remoteAuthority?: string; @@ -48,4 +31,4 @@ export interface IBackupMainService { unregisterWorkspaceBackupSync(workspace: IWorkspaceIdentifier): void; unregisterFolderBackupSync(folderUri: URI): void; unregisterEmptyWindowBackupSync(backupFolder: string): void; -} \ No newline at end of file +} diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index 66ca2b6c3db..ab24a78884b 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -9,7 +9,8 @@ import * as path from 'vs/base/common/path'; import * as platform from 'vs/base/common/platform'; import { writeFileSync, writeFile, readFile, readdir, exists, rimraf, rename, RimRafMode } from 'vs/base/node/pfs'; import * as arrays from 'vs/base/common/arrays'; -import { IBackupMainService, IBackupWorkspacesFormat, IEmptyWindowBackupInfo, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; +import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup'; +import { IBackupWorkspacesFormat, IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFilesConfiguration, HotExitConfiguration } from 'vs/platform/files/common/files'; diff --git a/src/vs/platform/backup/node/backup.ts b/src/vs/platform/backup/node/backup.ts new file mode 100644 index 00000000000..d40d01b1866 --- /dev/null +++ b/src/vs/platform/backup/node/backup.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface ISerializedWorkspace { id: string; configURIPath: string; remoteAuthority?: string; } + +export interface IBackupWorkspacesFormat { + rootURIWorkspaces: ISerializedWorkspace[]; + folderURIWorkspaces: string[]; + emptyWorkspaceInfos: IEmptyWindowBackupInfo[]; + + // deprecated + folderWorkspaces?: string[]; // use folderURIWorkspaces instead + emptyWorkspaces?: string[]; + rootWorkspaces?: { id: string, configPath: string }[]; // use rootURIWorkspaces instead +} + +export interface IEmptyWindowBackupInfo { + backupFolder: string; + remoteAuthority?: string; +} diff --git a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 087876e5e8e..b4dc3452beb 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -13,7 +13,8 @@ import { URI } from 'vs/base/common/uri'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; -import { IBackupWorkspacesFormat, ISerializedWorkspace, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; +import { IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup'; +import { IBackupWorkspacesFormat, ISerializedWorkspace } from 'vs/platform/backup/node/backup'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ConsoleLogMainService } from 'vs/platform/log/common/log'; diff --git a/src/vs/platform/diagnostics/node/diagnosticsIpc.ts b/src/vs/platform/diagnostics/node/diagnosticsIpc.ts index d159c07d8ca..4315b7f8b6a 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsIpc.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsIpc.ts @@ -7,7 +7,7 @@ import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IRemoteDiagnosticInfo, IRemoteDiagnosticError, SystemInfo, PerformanceInfo } from 'vs/platform/diagnostics/common/diagnostics'; import { IDiagnosticsService } from './diagnosticsService'; import { Event } from 'vs/base/common/event'; -import { IMainProcessInfo } from 'vs/platform/launch/common/launchService'; +import { IMainProcessInfo } from 'vs/platform/launch/common/launch'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; export class DiagnosticsChannel implements IServerChannel { diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts index d34c3064f55..43dd25b6a5f 100644 --- a/src/vs/platform/diagnostics/node/diagnosticsService.ts +++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts @@ -14,7 +14,7 @@ import { repeat, pad } from 'vs/base/common/strings'; import { isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ProcessItem } from 'vs/base/common/processes'; -import { IMainProcessInfo } from 'vs/platform/launch/common/launchService'; +import { IMainProcessInfo } from 'vs/platform/launch/common/launch'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/platform/history/common/history.ts b/src/vs/platform/history/common/history.ts index 2813f2fa9cb..e43836ec7c6 100644 --- a/src/vs/platform/history/common/history.ts +++ b/src/vs/platform/history/common/history.ts @@ -3,13 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event as CommonEvent } from 'vs/base/common/event'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; -import { IPath } from 'vs/platform/windows/common/windows'; - -export const IHistoryMainService = createDecorator('historyMainService'); export interface IRecentlyOpened { workspaces: Array; @@ -45,16 +40,3 @@ export function isRecentFile(curr: IRecent): curr is IRecentFile { return curr.hasOwnProperty('fileUri'); } - -export interface IHistoryMainService { - _serviceBrand: undefined; - - onRecentlyOpenedChange: CommonEvent; - - addRecentlyOpened(recents: IRecent[]): void; - getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier, currentFolder?: ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened; - removeFromRecentlyOpened(paths: URI[]): void; - clearRecentlyOpened(): void; - - updateWindowsJumpList(): void; -} \ No newline at end of file diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index e71c67be003..69815a03a6e 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -14,7 +14,7 @@ import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import { isWindows, isMacintosh } from 'vs/base/common/platform'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IHistoryMainService, IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile } from 'vs/platform/history/common/history'; +import { IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile } from 'vs/platform/history/common/history'; import { ThrottledDelayer } from 'vs/base/common/async'; import { isEqual as areResourcesEqual, dirname, originalFSPath, basename } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; @@ -24,6 +24,22 @@ import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/common/historyStorage'; import { exists } from 'vs/base/node/pfs'; import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IHistoryMainService = createDecorator('historyMainService'); + +export interface IHistoryMainService { + _serviceBrand: undefined; + + onRecentlyOpenedChange: CommonEvent; + + addRecentlyOpened(recents: IRecent[]): void; + getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier, currentFolder?: ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened; + removeFromRecentlyOpened(paths: URI[]): void; + clearRecentlyOpened(): void; + + updateWindowsJumpList(): void; +} export class HistoryMainService implements IHistoryMainService { diff --git a/src/vs/platform/issue/node/issueIpc.ts b/src/vs/platform/issue/electron-main/issueIpc.ts similarity index 100% rename from src/vs/platform/issue/node/issueIpc.ts rename to src/vs/platform/issue/electron-main/issueIpc.ts diff --git a/src/vs/platform/issue/electron-main/issueService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts similarity index 98% rename from src/vs/platform/issue/electron-main/issueService.ts rename to src/vs/platform/issue/electron-main/issueMainService.ts index 72882814d3a..2278e311a04 100644 --- a/src/vs/platform/issue/electron-main/issueService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -8,7 +8,7 @@ import * as objects from 'vs/base/common/objects'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue'; import { BrowserWindow, ipcMain, screen, dialog } from 'electron'; -import { ILaunchService } from 'vs/platform/launch/electron-main/launchService'; +import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchService'; import { PerformanceInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -20,7 +20,7 @@ import { listProcesses } from 'vs/base/node/ps'; const DEFAULT_BACKGROUND_COLOR = '#1E1E1E'; -export class IssueService implements IIssueService { +export class IssueMainService implements IIssueService { _serviceBrand: undefined; _issueWindow: BrowserWindow | null = null; _issueParentWindow: BrowserWindow | null = null; @@ -31,7 +31,7 @@ export class IssueService implements IIssueService { private machineId: string, private userEnv: IProcessEnvironment, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILaunchService private readonly launchService: ILaunchService, + @ILaunchMainService private readonly launchService: ILaunchMainService, @ILogService private readonly logService: ILogService, @IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService, @IWindowsService private readonly windowsService: IWindowsService diff --git a/src/vs/platform/launch/common/launchService.ts b/src/vs/platform/launch/common/launch.ts similarity index 100% rename from src/vs/platform/launch/common/launchService.ts rename to src/vs/platform/launch/common/launch.ts diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index e33e293b214..5a1fa9862b6 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -19,10 +19,10 @@ import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron'; import { Event } from 'vs/base/common/event'; import { coalesce } from 'vs/base/common/arrays'; import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; -import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launchService'; +import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launch'; -export const ID = 'launchService'; -export const ILaunchService = createDecorator(ID); +export const ID = 'launchMainService'; +export const ILaunchMainService = createDecorator(ID); export interface IStartArguments { args: ParsedArgs; @@ -51,7 +51,7 @@ function parseOpenUrl(args: ParsedArgs): URI[] { return []; } -export interface ILaunchService { +export interface ILaunchMainService { _serviceBrand: undefined; start(args: ParsedArgs, userEnv: IProcessEnvironment): Promise; getMainProcessId(): Promise; @@ -62,7 +62,7 @@ export interface ILaunchService { export class LaunchChannel implements IServerChannel { - constructor(private service: ILaunchService) { } + constructor(private service: ILaunchMainService) { } listen(_: unknown, event: string): Event { throw new Error(`Event not found: ${event}`); @@ -91,7 +91,7 @@ export class LaunchChannel implements IServerChannel { } } -export class LaunchChannelClient implements ILaunchService { +export class LaunchChannelClient implements ILaunchMainService { _serviceBrand: undefined; @@ -118,7 +118,7 @@ export class LaunchChannelClient implements ILaunchService { } } -export class LaunchService implements ILaunchService { +export class LaunchMainService implements ILaunchMainService { _serviceBrand: undefined; diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index e891d78f2b4..85d1b197e54 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -16,7 +16,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels'; import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows'; -import { IHistoryMainService } from 'vs/platform/history/common/history'; +import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar'; import { URI } from 'vs/base/common/uri'; import { IStateService } from 'vs/platform/state/common/state'; diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 7d7d9b4f201..c1bc389a681 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -13,7 +13,8 @@ import { Event } from 'vs/base/common/event'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { IWindowsMainService, ISharedProcess, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { IHistoryMainService, IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; +import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; +import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { Schemas } from 'vs/base/common/network'; From 19fed1d5b01b51b86ad4ebc916d2379d800c424b Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 17 Sep 2019 15:33:06 +0200 Subject: [PATCH 28/82] Include tooltip on custom tree item icon Fixes #80694 --- src/vs/workbench/browser/parts/views/customView.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 3860b90cbbd..414c1e6abde 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -768,6 +768,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle }; templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false }); From a8d5382619771e27e5f5ce1d41261b3b750e5111 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 15:39:02 +0200 Subject: [PATCH 29/82] debt - more platform/electron-main cleanup --- src/vs/code/electron-main/app.ts | 8 ++++---- src/vs/code/electron-main/main.ts | 14 +++++++------- src/vs/code/electron-main/sharedProcess.ts | 4 ++-- src/vs/code/electron-main/windows.ts | 6 +++--- src/vs/platform/history/common/history.ts | 1 - .../history/electron-main/historyMainService.ts | 4 ++-- src/vs/platform/launch/common/launch.ts | 3 ++- .../{lifecycleMain.ts => lifecycleMainService.ts} | 14 +++++++------- src/vs/platform/menubar/electron-main/menubar.ts | 4 ++-- .../{menubarService.ts => menubarMainService.ts} | 5 +++-- .../{requestService.ts => requestMainService.ts} | 2 +- .../theme/electron-main/themeMainService.ts | 4 ++-- .../update/electron-main/abstractUpdateService.ts | 4 ++-- .../update/electron-main/updateService.darwin.ts | 4 ++-- .../update/electron-main/updateService.linux.ts | 4 ++-- .../update/electron-main/updateService.snap.ts | 6 +++--- .../update/electron-main/updateService.win32.ts | 4 ++-- .../windows/electron-main/windowsService.ts | 4 ++-- 18 files changed, 48 insertions(+), 47 deletions(-) rename src/vs/platform/lifecycle/electron-main/{lifecycleMain.ts => lifecycleMainService.ts} (96%) rename src/vs/platform/menubar/electron-main/{menubarService.ts => menubarMainService.ts} (94%) rename src/vs/platform/request/electron-main/{requestService.ts => requestMainService.ts} (94%) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 0f0c530c832..4e2f8842a9e 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -9,7 +9,7 @@ import { WindowsManager } from 'vs/code/electron-main/windows'; import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows'; import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc'; import { WindowsService } from 'vs/platform/windows/electron-main/windowsService'; -import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { getShellEnvironment } from 'vs/code/node/shellEnv'; import { IUpdateService } from 'vs/platform/update/common/update'; import { UpdateChannel } from 'vs/platform/update/electron-main/updateIpc'; @@ -52,7 +52,7 @@ import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/err import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener'; import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; import { IMenubarService } from 'vs/platform/menubar/node/menubar'; -import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService'; +import { MenubarMainService } from 'vs/platform/menubar/electron-main/menubarMainService'; import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; @@ -92,7 +92,7 @@ export class CodeApplication extends Disposable { @IInstantiationService private readonly instantiationService: IInstantiationService, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStateService private readonly stateService: IStateService ) { @@ -457,7 +457,7 @@ export class CodeApplication extends Disposable { services.set(IIssueService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv])); services.set(IElectronService, new SyncDescriptor(ElectronMainService)); - services.set(IMenubarService, new SyncDescriptor(MenubarService)); + services.set(IMenubarService, new SyncDescriptor(MenubarMainService)); const storageMainService = new StorageMainService(this.logService, this.environmentService); services.set(IStorageMainService, storageMainService); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 013fafa3b95..f2d5cf7b88d 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -12,7 +12,7 @@ import { parseMainProcessArgv } from 'vs/platform/environment/node/argvHelper'; import { addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv'; import { mkdirp } from 'vs/base/node/pfs'; import { validatePaths } from 'vs/code/node/paths'; -import { LifecycleService, ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { LifecycleMainService, ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net'; import { LaunchChannelClient } from 'vs/platform/launch/electron-main/launchService'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -27,7 +27,7 @@ import { EnvironmentService, xdgRuntimeDir } from 'vs/platform/environment/node/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { IRequestService } from 'vs/platform/request/common/request'; -import { RequestService } from 'vs/platform/request/electron-main/requestService'; +import { RequestMainService } from 'vs/platform/request/electron-main/requestMainService'; import * as fs from 'fs'; import { CodeApplication } from 'vs/code/electron-main/app'; import { localize } from 'vs/nls'; @@ -116,7 +116,7 @@ class CodeMain { await instantiationService.invokeFunction(async accessor => { const environmentService = accessor.get(IEnvironmentService); const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleService); + const lifecycleService = accessor.get(ILifecycleMainService); const configurationService = accessor.get(IConfigurationService); const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true); @@ -143,9 +143,9 @@ class CodeMain { services.set(ILogService, logService); services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource)); - services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); + services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService)); services.set(IStateService, new SyncDescriptor(StateService)); - services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IRequestService, new SyncDescriptor(RequestMainService)); services.set(IThemeMainService, new SyncDescriptor(ThemeMainService)); services.set(ISignService, new SyncDescriptor(SignService)); @@ -189,7 +189,7 @@ class CodeMain { return instanceEnvironment; } - private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleService, instantiationService: IInstantiationService, retry: boolean): Promise { + private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise { // Try to setup a server for running. If that succeeds it means // we are the first instance to startup. Otherwise it is likely @@ -374,7 +374,7 @@ class CodeMain { private quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleService); + const lifecycleService = accessor.get(ILifecycleMainService); let exitCode = 0; diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 169af009af8..29ef3a38ddc 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -10,7 +10,7 @@ import { BrowserWindow, ipcMain } from 'electron'; import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -24,7 +24,7 @@ export class SharedProcess implements ISharedProcess { private readonly machineId: string, private userEnv: NodeJS.ProcessEnv, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @IThemeMainService private readonly themeMainService: IThemeMainService ) { } diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d00c5e99aab..d5ba7ef2ae2 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -15,7 +15,7 @@ import { IStateService } from 'vs/platform/state/common/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; -import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; @@ -188,7 +188,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -1364,7 +1364,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { window.win.on('closed', () => this.onWindowClosed(window!)); // Lifecycle - (this.lifecycleService as LifecycleService).registerWindow(window); + (this.lifecycleService as LifecycleMainService).registerWindow(window); } // Existing window diff --git a/src/vs/platform/history/common/history.ts b/src/vs/platform/history/common/history.ts index e43836ec7c6..e2c725ab6cb 100644 --- a/src/vs/platform/history/common/history.ts +++ b/src/vs/platform/history/common/history.ts @@ -39,4 +39,3 @@ export function isRecentFolder(curr: IRecent): curr is IRecentFolder { export function isRecentFile(curr: IRecent): curr is IRecentFile { return curr.hasOwnProperty('fileUri'); } - diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 69815a03a6e..b67c268b997 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -23,7 +23,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/common/historyStorage'; import { exists } from 'vs/base/node/pfs'; -import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IHistoryMainService = createDecorator('historyMainService'); @@ -68,7 +68,7 @@ export class HistoryMainService implements IHistoryMainService { @ILogService private readonly logService: ILogService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleService lifecycleService: ILifecycleService + @ILifecycleMainService lifecycleService: ILifecycleMainService ) { this.macOSRecentDocumentsUpdater = new ThrottledDelayer(800); diff --git a/src/vs/platform/launch/common/launch.ts b/src/vs/platform/launch/common/launch.ts index 0c0e1db2134..6fbf52d5612 100644 --- a/src/vs/platform/launch/common/launch.ts +++ b/src/vs/platform/launch/common/launch.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + import { UriComponents } from 'vs/base/common/uri'; export interface IWindowInfo { @@ -18,4 +19,4 @@ export interface IMainProcessInfo { windows: IWindowInfo[]; screenReader: boolean; gpuFeatureStatus: any; -} \ No newline at end of file +} diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts similarity index 96% rename from src/vs/platform/lifecycle/electron-main/lifecycleMain.ts rename to src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index 72f2d7c124f..dc31d3afab2 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -14,7 +14,7 @@ import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; import { Barrier } from 'vs/base/common/async'; -export const ILifecycleService = createDecorator('lifecycleService'); +export const ILifecycleMainService = createDecorator('lifecycleMainService'); export const enum UnloadReason { CLOSE = 1, @@ -38,7 +38,7 @@ export interface ShutdownEvent { join(promise: Promise): void; } -export interface ILifecycleService { +export interface ILifecycleMainService { _serviceBrand: undefined; @@ -129,7 +129,7 @@ export const enum LifecycleMainPhase { AfterWindowOpen = 3 } -export class LifecycleService extends Disposable implements ILifecycleService { +export class LifecycleMainService extends Disposable implements ILifecycleMainService { _serviceBrand: undefined; @@ -178,10 +178,10 @@ export class LifecycleService extends Disposable implements ILifecycleService { } private handleRestarted(): void { - this._wasRestarted = !!this.stateService.getItem(LifecycleService.QUIT_FROM_RESTART_MARKER); + this._wasRestarted = !!this.stateService.getItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER); if (this._wasRestarted) { - this.stateService.removeItem(LifecycleService.QUIT_FROM_RESTART_MARKER); // remove the marker right after if found + this.stateService.removeItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER); // remove the marker right after if found } } @@ -468,7 +468,7 @@ export class LifecycleService extends Disposable implements ILifecycleService { // Remember the reason for quit was to restart if (fromUpdate) { - this.stateService.setItem(LifecycleService.QUIT_FROM_RESTART_MARKER, true); + this.stateService.setItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER, true); } this.pendingQuitPromise = new Promise(resolve => { @@ -507,7 +507,7 @@ export class LifecycleService extends Disposable implements ILifecycleService { if (!quitVetoed) { // Remember the reason for quit was to restart - this.stateService.setItem(LifecycleService.QUIT_FROM_RESTART_MARKER, true); + this.stateService.setItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER, true); // Windows: we are about to restart and as such we need to restore the original // current working directory we had on startup to get the exact same startup diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 85d1b197e54..25139ec68e5 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -20,7 +20,7 @@ import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMa import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar'; import { URI } from 'vs/base/common/uri'; import { IStateService } from 'vs/platform/state/common/state'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; const telemetryFrom = 'menu'; @@ -68,7 +68,7 @@ export class Menubar { @ITelemetryService private readonly telemetryService: ITelemetryService, @IHistoryMainService private readonly historyMainService: IHistoryMainService, @IStateService private readonly stateService: IStateService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @ILogService private readonly logService: ILogService ) { this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); diff --git a/src/vs/platform/menubar/electron-main/menubarService.ts b/src/vs/platform/menubar/electron-main/menubarMainService.ts similarity index 94% rename from src/vs/platform/menubar/electron-main/menubarService.ts rename to src/vs/platform/menubar/electron-main/menubarMainService.ts index 8763b9d2330..cb4c63bfa85 100644 --- a/src/vs/platform/menubar/electron-main/menubarService.ts +++ b/src/vs/platform/menubar/electron-main/menubarMainService.ts @@ -8,7 +8,8 @@ import { Menubar } from 'vs/platform/menubar/electron-main/menubar'; import { ILogService } from 'vs/platform/log/common/log'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -export class MenubarService implements IMenubarService { +export class MenubarMainService implements IMenubarService { + _serviceBrand: undefined; private _menubar: Menubar; @@ -30,4 +31,4 @@ export class MenubarService implements IMenubarService { return Promise.resolve(undefined); } -} \ No newline at end of file +} diff --git a/src/vs/platform/request/electron-main/requestService.ts b/src/vs/platform/request/electron-main/requestMainService.ts similarity index 94% rename from src/vs/platform/request/electron-main/requestService.ts rename to src/vs/platform/request/electron-main/requestMainService.ts index de9eacfd447..7f8b7141212 100644 --- a/src/vs/platform/request/electron-main/requestService.ts +++ b/src/vs/platform/request/electron-main/requestMainService.ts @@ -13,7 +13,7 @@ function getRawRequest(options: IRequestOptions): IRawRequestFunction { return net.request as any as IRawRequestFunction; } -export class RequestService extends NodeRequestService { +export class RequestMainService extends NodeRequestService { request(options: IRequestOptions, token: CancellationToken): Promise { return super.request(assign({}, options || {}, { getRawRequest }), token); diff --git a/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts index d44f8bed3dd..e9b43cea979 100644 --- a/src/vs/platform/theme/electron-main/themeMainService.ts +++ b/src/vs/platform/theme/electron-main/themeMainService.ts @@ -41,7 +41,7 @@ export class ThemeMainService implements IThemeMainService { this.stateService.setItem(THEME_BG_STORAGE_KEY, data.background); } - public getBackgroundColor(): string { + getBackgroundColor(): string { if (isWindows && systemPreferences.isInvertedColorScheme()) { return DEFAULT_BG_HC_BLACK; } @@ -64,4 +64,4 @@ export class ThemeMainService implements IThemeMainService { return background; } -} \ No newline at end of file +} diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index 4f8d6ef3521..8847db647a7 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -6,7 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; import { IConfigurationService, getMigratedSettingValue } from 'vs/platform/configuration/common/configuration'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import product from 'vs/platform/product/common/product'; import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -44,7 +44,7 @@ export abstract class AbstractUpdateService implements IUpdateService { } constructor( - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @IConfigurationService protected configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IRequestService protected requestService: IRequestService, diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index 4ea14a0cb82..cf016a44280 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -8,7 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { memoize } from 'vs/base/common/decorators'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { State, IUpdate, StateType, UpdateType } from 'vs/platform/update/common/update'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -28,7 +28,7 @@ export class DarwinUpdateService extends AbstractUpdateService { @memoize private get onRawUpdateDownloaded(): Event { return Event.fromNodeEventEmitter(electron.autoUpdater, 'update-downloaded', (_, releaseNotes, version, date) => ({ releaseNotes, version, productVersion: version, date })); } constructor( - @ILifecycleService lifecycleService: ILifecycleService, + @ILifecycleMainService lifecycleService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 5de08fb051d..7adb7e00bf8 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -5,7 +5,7 @@ import product from 'vs/platform/product/common/product'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { State, IUpdate, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -20,7 +20,7 @@ export class LinuxUpdateService extends AbstractUpdateService { _serviceBrand: undefined; constructor( - @ILifecycleService lifecycleService: ILifecycleService, + @ILifecycleMainService lifecycleService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, diff --git a/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts index 3861dc0b392..36db202ff33 100644 --- a/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -5,7 +5,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; @@ -35,7 +35,7 @@ abstract class AbstractUpdateService2 implements IUpdateService { } constructor( - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @IEnvironmentService environmentService: IEnvironmentService, @ILogService protected logService: ILogService, ) { @@ -139,7 +139,7 @@ export class SnapUpdateService extends AbstractUpdateService2 { constructor( private snap: string, private snapRevision: string, - @ILifecycleService lifecycleService: ILifecycleService, + @ILifecycleMainService lifecycleService: ILifecycleMainService, @IEnvironmentService environmentService: IEnvironmentService, @ILogService logService: ILogService, @ITelemetryService private readonly telemetryService: ITelemetryService diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 72efd33c9be..7395de466da 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -8,7 +8,7 @@ import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { memoize } from 'vs/base/common/decorators'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import product from 'vs/platform/product/common/product'; import { State, IUpdate, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -60,7 +60,7 @@ export class Win32UpdateService extends AbstractUpdateService { } constructor( - @ILifecycleService lifecycleService: ILifecycleService, + @ILifecycleMainService lifecycleService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index c1bc389a681..c6ee7cfc593 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -11,7 +11,7 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/ import { shell, crashReporter, app, Menu } from 'electron'; import { Event } from 'vs/base/common/event'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; -import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IWindowsMainService, ISharedProcess, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; import { IHistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; @@ -45,7 +45,7 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IURLService urlService: IURLService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, + @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, @IHistoryMainService private readonly historyService: IHistoryMainService, @ILogService private readonly logService: ILogService ) { From 9e3d285def2dd99623226e1479309d47522b97eb Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Sep 2019 15:48:00 +0200 Subject: [PATCH 30/82] breakpoints: interaction on inline breakpoint decorations --- .../browser/breakpointEditorContribution.ts | 62 ++++++++++++++----- .../contrib/debug/browser/breakpointWidget.ts | 11 ++-- .../contrib/debug/browser/breakpointsView.ts | 4 +- .../contrib/debug/browser/debugActions.ts | 6 +- .../debug/browser/debugEditorActions.ts | 2 +- .../workbench/contrib/debug/common/debug.ts | 2 +- 6 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 53be1139b22..8b613a2058a 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -19,7 +19,6 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions'; import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ContextSubMenu } from 'vs/base/browser/contextmenu'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget'; @@ -28,6 +27,7 @@ import { MarkdownString } from 'vs/base/common/htmlContent'; import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView'; import { generateUuid } from 'vs/base/common/uuid'; import { memoize } from 'vs/base/common/decorators'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; const $ = dom.$; @@ -100,7 +100,6 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { @IContextMenuService private readonly contextMenuService: IContextMenuService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, - @IKeybindingService private readonly keybindingService: IKeybindingService, @IDialogService private readonly dialogService: IDialogService, ) { this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); @@ -208,17 +207,17 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); } - private getContextMenuActions(breakpoints: ReadonlyArray, uri: uri, lineNumber: number): Array { + private getContextMenuActions(breakpoints: ReadonlyArray, uri: uri, lineNumber: number, column?: number): Array { const actions: Array = []; if (breakpoints.length === 1) { const breakpointType = breakpoints[0].logMessage ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint"); - actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService)); + actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService)); actions.push(new Action( 'workbench.debug.action.editBreakpointAction', nls.localize('editBreakpoint', "Edit {0}...", breakpointType), undefined, true, - () => Promise.resolve(this.showBreakpointWidget(breakpoints[0].lineNumber)) + () => Promise.resolve(this.showBreakpointWidget(breakpoints[0].lineNumber, breakpoints[0].column)) )); actions.push(new Action( @@ -243,7 +242,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"), undefined, true, - () => Promise.resolve(this.showBreakpointWidget(bp.lineNumber)) + () => Promise.resolve(this.showBreakpointWidget(bp.lineNumber, bp.column)) ) ))); @@ -261,14 +260,14 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { nls.localize('addBreakpoint', "Add Breakpoint"), undefined, true, - () => this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorContextMenu`) + () => this.debugService.addBreakpoints(uri, [{ lineNumber, column }], `debugEditorContextMenu`) )); actions.push(new Action( 'addConditionalBreakpoint', nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."), undefined, true, - () => Promise.resolve(this.showBreakpointWidget(lineNumber)) + () => Promise.resolve(this.showBreakpointWidget(lineNumber, column)) )); actions.push(new Action( 'addLogPoint', @@ -330,12 +329,20 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { bpd.inlineWidget.dispose(); } }); - this.breakpointDecorations = decorationIds.map((decorationId, index) => ({ - decorationId, - breakpointId: breakpoints[index].getId(), - range: desiredDecorations[index].range, - inlineWidget: breakpoints[index].column ? new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredDecorations[index].options.glyphMarginClassName) : undefined - })); + this.breakpointDecorations = decorationIds.map((decorationId, index) => { + let inlineWidget: InlineBreakpointWidget | undefined = undefined; + const breakpoint = breakpoints[index]; + if (breakpoint.column) { + inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column)); + } + + return { + decorationId, + breakpointId: breakpoint.getId(), + range: desiredDecorations[index].range, + inlineWidget + }; + }); } finally { this.ignoreDecorationsChangedEvent = false; } @@ -389,13 +396,13 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } // breakpoint widget - showBreakpointWidget(lineNumber: number, context?: BreakpointWidgetContext): void { + showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void { if (this.breakpointWidget) { this.breakpointWidget.dispose(); } - this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, context); - this.breakpointWidget.show({ lineNumber, column: 1 }, 2); + this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, column, context); + this.breakpointWidget.show({ lineNumber, column: 1 }); this.breakpointWidgetVisible.set(true); } @@ -431,6 +438,10 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { private readonly editor: IActiveCodeEditor, private readonly decorationId: string, cssClass: string | null | undefined, + private readonly breakpoint: IBreakpoint | undefined, + private readonly debugService: IDebugService, + private readonly contextMenuService: IContextMenuService, + private readonly getContextMenuActions: () => ReadonlyArray ) { this.range = this.editor.getModel().getDecorationRange(decorationId); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => { @@ -452,6 +463,23 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { if (cssClass) { this.domNode.classList.add(cssClass); } + this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CLICK, async e => { + if (this.breakpoint) { + await this.debugService.removeBreakpoints(this.breakpoint.getId()); + } else { + await this.debugService.addBreakpoints(this.editor.getModel().uri, [{ lineNumber: this.range!.startLineNumber, column: this.range!.startColumn }], 'debugEditorInlineWidget'); + } + })); + this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CONTEXT_MENU, async e => { + const event = new StandardMouseEvent(e); + const anchor = { x: event.posx, y: event.posy }; + + this.contextMenuService.showContextMenu({ + getAnchor: () => anchor, + getActions: () => this.getContextMenuActions(), + getActionsContext: () => this.breakpoint + }); + })); } @memoize diff --git a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index 52dda729604..85f2ac93bf1 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -37,7 +37,7 @@ import { IRange, Range } from 'vs/editor/common/core/range'; import { onUnexpectedError } from 'vs/base/common/errors'; const $ = dom.$; -const IPrivateBreakpointWidgetService = createDecorator('privateBreakopintWidgetService'); +const IPrivateBreakpointWidgetService = createDecorator('privateBreakpointWidgetService'); export interface IPrivateBreakpointWidgetService { _serviceBrand: undefined; close(success: boolean): void; @@ -55,7 +55,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi private logMessageInput = ''; private breakpoint: IBreakpoint | undefined; - constructor(editor: ICodeEditor, private lineNumber: number, private context: Context, + constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, private context: Context, @IContextViewService private readonly contextViewService: IContextViewService, @IDebugService private readonly debugService: IDebugService, @IThemeService private readonly themeService: IThemeService, @@ -70,7 +70,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi const model = this.editor.getModel(); if (model) { const uri = model.uri; - const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, uri }); + const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, column: this.column, uri }); this.breakpoint = breakpoints.length ? breakpoints[0] : undefined; } @@ -130,12 +130,12 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi } } - show(rangeOrPos: IRange | IPosition, heightInLines: number) { + show(rangeOrPos: IRange | IPosition): void { const lineNum = this.input.getModel().getLineCount(); super.show(rangeOrPos, lineNum + 1); } - fitHeightToContent() { + fitHeightToContent(): void { const lineNum = this.input.getModel().getLineCount(); this._relayout(lineNum + 1); } @@ -293,6 +293,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi if (model) { this.debugService.addBreakpoints(model.uri, [{ lineNumber: this.lineNumber, + column: this.column, enabled: true, condition, hitCondition, diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 9db0d99399e..1eafaff8e61 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -167,7 +167,7 @@ export class BreakpointsView extends ViewletPanel { if (editor) { const codeEditor = editor.getControl(); if (isCodeEditor(codeEditor)) { - codeEditor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber); + codeEditor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column); } } }); @@ -180,7 +180,7 @@ export class BreakpointsView extends ViewletPanel { actions.push(new Separator()); } - actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService)); + actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService)); if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) { actions.push(new RemoveAllBreakpointsAction(RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL, this.debugService, this.keybindingService)); diff --git a/src/vs/workbench/contrib/debug/browser/debugActions.ts b/src/vs/workbench/contrib/debug/browser/debugActions.ts index 5d71d9aa40f..cc4091769a1 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActions.ts @@ -181,12 +181,12 @@ export class SelectAndStartAction extends AbstractDebugAction { } } -export class RemoveBreakpointAction extends AbstractDebugAction { +export class RemoveBreakpointAction extends Action { static readonly ID = 'workbench.debug.viewlet.action.removeBreakpoint'; static LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint"); - constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action remove', debugService, keybindingService); + constructor(id: string, label: string, @IDebugService private readonly debugService: IDebugService) { + super(id, label, 'debug-action remove'); } public run(breakpoint: IBreakpoint): Promise { diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 7b40caea504..784694a387a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -75,7 +75,7 @@ class ConditionalBreakpointAction extends EditorAction { const position = editor.getPosition(); if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) { - editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber); + editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, undefined); } } } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 748f0b389b7..a531f430188 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -855,7 +855,7 @@ export interface IDebugEditorContribution extends IEditorContribution { } export interface IBreakpointEditorContribution extends IEditorContribution { - showBreakpointWidget(lineNumber: number, context?: BreakpointWidgetContext): void; + showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void; closeBreakpointWidget(): void; } From 50a0bd9eaaaaf7474f8c348865fd9d21e7d717f7 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Sep 2019 16:10:24 +0200 Subject: [PATCH 31/82] debug session: add breakpointLocations --- .../contrib/debug/browser/debugSession.ts | 34 +++++++++++++------ .../contrib/debug/browser/rawDebugSession.ts | 7 ++++ .../workbench/contrib/debug/common/debug.ts | 3 +- .../contrib/debug/test/common/mockDebug.ts | 7 +++- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 908b3ef89db..92c18c46873 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -10,7 +10,7 @@ import * as platform from 'vs/base/common/platform'; import severity from 'vs/base/common/severity'; import { Event, Emitter } from 'vs/base/common/event'; import { CompletionItem, completionKindFromString } from 'vs/editor/common/modes'; -import { Position } from 'vs/editor/common/core/position'; +import { Position, IPosition } from 'vs/editor/common/core/position'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; @@ -34,6 +34,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IOpenerService } from 'vs/platform/opener/common/opener'; import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; +import { distinct } from 'vs/base/common/arrays'; export class DebugSession implements IDebugSession { @@ -284,15 +285,7 @@ export class DebugSession implements IDebugSession { return Promise.resolve(undefined); } - const source = this.getSourceForUri(modelUri); - let rawSource: DebugProtocol.Source; - if (source) { - rawSource = source.raw; - } else { - const data = Source.getEncodedDebugData(modelUri); - rawSource = { name: data.name, path: data.path, sourceReference: data.sourceReference }; - } - + const rawSource = this.getRawSource(modelUri); if (breakpointsToSend.length && !rawSource.adapterData) { rawSource.adapterData = breakpointsToSend[0].adapterData; } @@ -376,6 +369,17 @@ export class DebugSession implements IDebugSession { return Promise.reject(new Error('no debug adapter')); } + async breakpointsLocations(uri: URI, lineNumber: number): Promise { + if (this.raw) { + const source = this.getRawSource(uri); + const response = await this.raw.breakpointLocations({ source, line: lineNumber }); + const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 })); + + return distinct(positions, p => p.toString()); + } + return Promise.reject(new Error('no debug adapter')); + } + customRequest(request: string, args: any): Promise { if (this.raw) { return this.raw.custom(request, args); @@ -914,6 +918,16 @@ export class DebugSession implements IDebugSession { return source; } + private getRawSource(uri: URI): DebugProtocol.Source { + const source = this.getSourceForUri(uri); + if (source) { + return source.raw; + } else { + const data = Source.getEncodedDebugData(uri); + return { name: data.name, path: data.path, sourceReference: data.sourceReference }; + } + } + private getNewCancellationToken(threadId: number): CancellationToken { const tokenSource = new CancellationTokenSource(); const tokens = this.cancellationMap.get(threadId) || []; diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 2e8ce0cf55e..53a10ed04c5 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -381,6 +381,13 @@ export class RawDebugSession implements IDisposable { return this.send('setExceptionBreakpoints', args); } + breakpointLocations(args: DebugProtocol.BreakpointLocationsArguments): Promise { + if (this.capabilities.supportsBreakpointLocationsRequest) { + return this.send('breakpointLocations', args); + } + return Promise.reject(new Error('breakpointLocations is not supported')); + } + configurationDone(): Promise { if (this.capabilities.supportsConfigurationDoneRequest) { return this.send('configurationDone', null); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index a531f430188..8d4055a1569 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel as EditorIModel } from 'vs/editor/common/model'; import { IEditor, ITextEditor } from 'vs/workbench/common/editor'; -import { Position } from 'vs/editor/common/core/position'; +import { Position, IPosition } from 'vs/editor/common/core/position'; import { CompletionItem } from 'vs/editor/common/modes'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { Range, IRange } from 'vs/editor/common/core/range'; @@ -208,6 +208,7 @@ export interface IDebugSession extends ITreeElement { dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }>; sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise; sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise; + breakpointsLocations(uri: uri, lineNumber: number): Promise; stackTrace(threadId: number, startFrame: number, levels: number): Promise; exceptionInfo(threadId: number): Promise; diff --git a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index 0abec14fb21..155f23002cf 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -6,7 +6,7 @@ import { URI as uri } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { Position } from 'vs/editor/common/core/position'; +import { Position, IPosition } from 'vs/editor/common/core/position'; import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { CompletionItem } from 'vs/editor/common/modes'; @@ -132,6 +132,11 @@ export class MockDebugService implements IDebugService { } export class MockSession implements IDebugSession { + + breakpointsLocations(uri: uri, lineNumber: number): Promise { + throw new Error('Method not implemented.'); + } + dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> { throw new Error('Method not implemented.'); } From 5cc29271b523b9c643cd0447b6a82baa1c2f390b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 16:24:51 +0200 Subject: [PATCH 32/82] Introduce id and user data sync store registry --- .../userDataSync/common/userDataSync.ts | 1 + .../api/browser/mainThreadUserData.ts | 3 +- .../workbench/api/common/extHost.api.impl.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 2 +- .../workbench/api/common/extHostUserData.ts | 4 +- .../userDataSync/common/userDataSyncStores.ts | 90 +++++++++++++++++++ 6 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index a311d5185da..4e47e25b391 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -58,6 +58,7 @@ export class UserDataSyncStoreError extends Error { } export interface IUserDataSyncStore { + readonly id: string; readonly name: string; read(key: string): Promise; write(key: string, content: string, ref: string | null): Promise; diff --git a/src/vs/workbench/api/browser/mainThreadUserData.ts b/src/vs/workbench/api/browser/mainThreadUserData.ts index 6893e0ce18c..69d2cdefadc 100644 --- a/src/vs/workbench/api/browser/mainThreadUserData.ts +++ b/src/vs/workbench/api/browser/mainThreadUserData.ts @@ -22,9 +22,10 @@ export class MainThreadUserData extends Disposable implements MainThreadUserData this._register(toDisposable(() => this.userDataSyncStoreService.deregisterUserDataSyncStore())); } - $registerUserDataProvider(name: string): void { + $registerUserDataProvider(id: string, name: string): void { const proxy = this.proxy; this.userDataSyncStoreService.registerUserDataSyncStore({ + id, name, read(key: string): Promise { return proxy.$read(key); diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 5cb276d27b2..8eeb8078ea4 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -546,9 +546,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I createInputBox(): vscode.InputBox { return extHostQuickOpen.createInputBox(extension.identifier); }, - registerUserDataSyncProvider: (identity: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable => { + registerUserDataSyncProvider: (name: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable => { checkProposedApiEnabled(extension); - return extHostUserData.registerUserDataProvider(identity, userDataProvider); + return extHostUserData.registerUserDataProvider(extension.identifier.value, name, userDataProvider); } }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index e3e56c063c6..979ab88a2df 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -147,7 +147,7 @@ export interface MainThreadConfigurationShape extends IDisposable { } export interface MainThreadUserDataShape extends IDisposable { - $registerUserDataProvider(name: string): void; + $registerUserDataProvider(id: string, name: string): void; $deregisterUserDataProvider(): void; } diff --git a/src/vs/workbench/api/common/extHostUserData.ts b/src/vs/workbench/api/common/extHostUserData.ts index 182b989359a..02984f3d88d 100644 --- a/src/vs/workbench/api/common/extHostUserData.ts +++ b/src/vs/workbench/api/common/extHostUserData.ts @@ -20,14 +20,14 @@ export class ExtHostUserData implements ExtHostUserDataShape { ) { } - registerUserDataProvider(name: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable { + registerUserDataProvider(id: string, name: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable { if (this.userDataProvider) { this.logService.warn(`A user data provider '${this.name}' already exists hence ignoring the remote user data provider '${name}'.`); return Disposable.None; } this.userDataProvider = userDataProvider; this.name = name; - this.proxy.$registerUserDataProvider(name); + this.proxy.$registerUserDataProvider(id, name); return toDisposable(() => this.proxy.$deregisterUserDataProvider()); } diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts new file mode 100644 index 00000000000..8734df3eb08 --- /dev/null +++ b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts @@ -0,0 +1,90 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { values } from 'vs/base/common/map'; +import { Registry } from 'vs/platform/registry/common/platform'; + + +export namespace Extensions { + export const UserDataSyncStoresRegistry = 'workbench.registry.userData.syncStores'; +} + +export interface IUserDataSyncStoresRegistry { + /** + * An event that is triggerred when a user data sync store is registered. + */ + readonly onDidRegister: Event; + + /** + * An event that is triggerred when a user data sync store is deregistered. + */ + readonly onDidDeregister: Event; + + /** + * All registered user data sync stores + */ + readonly all: IUserDataSyncStore[]; + + /** + * Registers a user data sync store + * + * @param userDataSyncStore to register + */ + registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void; + + /** + * Deregisters the user data sync store with given id + */ + deregisterUserDataSyncStore(id: string): void; + + /** + * Returns the user data sync store with given id. + * + * @returns the user data sync store with given id. + */ + get(id: string): IUserDataSyncStore | undefined; +} + +class UserDataSyncStoresRegistryImpl extends Disposable implements IUserDataSyncStoresRegistry { + + private readonly _onDidRegister = this._register(new Emitter()); + readonly onDidRegister: Event = this._onDidRegister.event; + + private readonly _onDidDeregister = this._register(new Emitter()); + readonly onDidDeregister: Event = this._onDidDeregister.event; + + private userDataSyncStores: Map = new Map(); + + get all(): IUserDataSyncStore[] { + return values(this.userDataSyncStores); + } + + registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void { + const existing = this.userDataSyncStores.get(userDataSyncStore.id); + if (existing) { + return; + } + + this.userDataSyncStores.set(userDataSyncStore.id, userDataSyncStore); + this._onDidRegister.fire(userDataSyncStore); + } + + deregisterUserDataSyncStore(id: string): void { + const existing = this.userDataSyncStores.get(id); + if (existing) { + this.userDataSyncStores.delete(id); + this._onDidDeregister.fire(id); + } + } + + get(id: string): IUserDataSyncStore | undefined { + return this.userDataSyncStores.get(id); + } +} + +Registry.add(Extensions.UserDataSyncStoresRegistry, new UserDataSyncStoresRegistryImpl()); From b44a8ca309adbd3858da4c2bc50af01f7f9d56aa Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 16:56:44 +0200 Subject: [PATCH 33/82] move user data sync store to workbench --- .../api/browser/mainThreadUserData.ts | 19 ++++++++++++------- .../workbench/api/common/extHost.protocol.ts | 2 +- .../workbench/api/common/extHostUserData.ts | 2 +- .../userDataSync/common/userDataSyncStores.ts | 8 +++++++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadUserData.ts b/src/vs/workbench/api/browser/mainThreadUserData.ts index 69d2cdefadc..509f8566752 100644 --- a/src/vs/workbench/api/browser/mainThreadUserData.ts +++ b/src/vs/workbench/api/browser/mainThreadUserData.ts @@ -3,10 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { MainContext, ExtHostContext, IExtHostContext, MainThreadUserDataShape, ExtHostUserDataShape } from '../common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IUserDataSyncStoresRegistry, Extensions } from 'vs/workbench/services/userDataSync/common/userDataSyncStores'; @extHostNamedCustomer(MainContext.MainThreadUserData) export class MainThreadUserData extends Disposable implements MainThreadUserDataShape { @@ -15,16 +17,14 @@ export class MainThreadUserData extends Disposable implements MainThreadUserData constructor( extHostContext: IExtHostContext, - @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService ) { super(); this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostUserData); - this._register(toDisposable(() => this.userDataSyncStoreService.deregisterUserDataSyncStore())); } $registerUserDataProvider(id: string, name: string): void { const proxy = this.proxy; - this.userDataSyncStoreService.registerUserDataSyncStore({ + Registry.as(Extensions.UserDataSyncStoresRegistry).registerUserDataSyncStore({ id, name, read(key: string): Promise { @@ -36,8 +36,13 @@ export class MainThreadUserData extends Disposable implements MainThreadUserData }); } - $deregisterUserDataProvider(): void { - this.userDataSyncStoreService.deregisterUserDataSyncStore(); + $deregisterUserDataProvider(id: string): void { + Registry.as(Extensions.UserDataSyncStoresRegistry).deregisterUserDataSyncStore(id); + } + + dispose(): void { + const registry = Registry.as(Extensions.UserDataSyncStoresRegistry); + registry.all.forEach(store => registry.deregisterUserDataSyncStore(store.id)); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 979ab88a2df..55bcebff44e 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -148,7 +148,7 @@ export interface MainThreadConfigurationShape extends IDisposable { export interface MainThreadUserDataShape extends IDisposable { $registerUserDataProvider(id: string, name: string): void; - $deregisterUserDataProvider(): void; + $deregisterUserDataProvider(id: string): void; } export interface MainThreadDiagnosticsShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostUserData.ts b/src/vs/workbench/api/common/extHostUserData.ts index 02984f3d88d..de5e565f7cb 100644 --- a/src/vs/workbench/api/common/extHostUserData.ts +++ b/src/vs/workbench/api/common/extHostUserData.ts @@ -28,7 +28,7 @@ export class ExtHostUserData implements ExtHostUserDataShape { this.userDataProvider = userDataProvider; this.name = name; this.proxy.$registerUserDataProvider(id, name); - return toDisposable(() => this.proxy.$deregisterUserDataProvider()); + return toDisposable(() => this.proxy.$deregisterUserDataProvider(id)); } $read(key: string): Promise { diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts index 8734df3eb08..b7bf3c91ce5 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts @@ -4,11 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { IUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { Registry } from 'vs/platform/registry/common/platform'; +export interface IUserDataSyncStore { + readonly id: string; + readonly name: string; + read(key: string): Promise; + write(key: string, content: string, ref: string | null): Promise; +} export namespace Extensions { export const UserDataSyncStoresRegistry = 'workbench.registry.userData.syncStores'; From a2a9ec0eb6a971f27518f052131fcd7f366d9b91 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 08:00:04 -0700 Subject: [PATCH 34/82] Rename iconDefault => iconForeground --- src/vs/platform/theme/common/colorRegistry.ts | 2 +- .../browser/parts/notifications/notificationsActions.ts | 4 ++-- src/vs/workbench/browser/style.ts | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 0c6eef628ac..b6ec6f9e6f9 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -187,7 +187,7 @@ export const activeContrastBorder = registerColor('contrastActiveBorder', { ligh export const selectionBackground = registerColor('selection.background', { light: null, dark: null, hc: null }, nls.localize('selectionBackground', "The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor.")); -export const iconDefault = registerColor('icon.default', { light: '#424242', dark: '#C5C5C5', hc: '#FFFFFF' }, nls.localize('iconDefault', "The default color for icons in the workbench.")); +export const iconForeground = registerColor('icon.foreground', { light: '#424242', dark: '#C5C5C5', hc: '#FFFFFF' }, nls.localize('iconForeground', "The default color for icons in the workbench.")); // ------ text colors diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index 16f7f408a3e..712cb046a3f 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -43,7 +43,7 @@ export class ClearAllNotificationsAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'clear-all-notifications-action'); + super(id, label, 'codicon-clear-all'); } run(notification: INotificationViewItem): Promise { @@ -63,7 +63,7 @@ export class HideNotificationsCenterAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'hide-all-notifications-action'); + super(id, label, 'codicon-chevron-down'); } run(notification: INotificationViewItem): Promise { diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index b7c6fc80afa..deaaf4953ed 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -6,15 +6,15 @@ import 'vs/css!./media/style'; import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; -import { iconDefault, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; +import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { // Icon defaults - const iconDefaultColor = theme.getColor(iconDefault); - if (iconDefaultColor) { - collector.addRule(`.monaco-workbench .codicon { color: ${iconDefaultColor}; }`); + const iconForegroundColor = theme.getColor(iconForeground); + if (iconForegroundColor) { + collector.addRule(`.monaco-workbench .codicon { color: ${iconForegroundColor}; }`); } // Foreground From 64b9f9b00af98b02b8ef459ba601e2c595f36095 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 08:01:39 -0700 Subject: [PATCH 35/82] Revert notification icon change --- .../browser/parts/notifications/notificationsActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index 712cb046a3f..16f7f408a3e 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -43,7 +43,7 @@ export class ClearAllNotificationsAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'codicon-clear-all'); + super(id, label, 'clear-all-notifications-action'); } run(notification: INotificationViewItem): Promise { @@ -63,7 +63,7 @@ export class HideNotificationsCenterAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'codicon-chevron-down'); + super(id, label, 'hide-all-notifications-action'); } run(notification: INotificationViewItem): Promise { From e83d9d3acf99de46d74a2ec3c1e17c3ccaa87506 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 17 Sep 2019 17:14:08 +0200 Subject: [PATCH 36/82] breakpoints: render candidates as decorations --- .../browser/breakpointEditorContribution.ts | 66 ++++++++++++++++--- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 8b613a2058a..4515fd4dfdd 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -28,6 +28,7 @@ import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/bro import { generateUuid } from 'vs/base/common/uuid'; import { memoize } from 'vs/base/common/decorators'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { distinct } from 'vs/base/common/arrays'; const $ = dom.$; @@ -63,6 +64,28 @@ function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArr return result; } +async function createCandidateDecorations(model: ITextModel, lineNumbers: number[], debugService: IDebugService): Promise<{ range: Range; options: IModelDecorationOptions; }[]> { + const result: { range: Range; options: IModelDecorationOptions; }[] = []; + const session = debugService.getViewModel().focusedSession; + if (session && session.capabilities.supportsBreakpointLocationsRequest) { + lineNumbers.forEach(async lineNumber => { + const positions = await session.breakpointsLocations(model.uri, lineNumber); + positions.forEach(p => { + result.push({ + range: new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1), + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + beforeContentClassName: `debug-breakpoint-placeholder` + } + }); + }); + }); + } + + return result; +} + + function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService): IModelDecorationOptions { const { className, message } = getBreakpointMessageAndClassName(debugService, breakpoint); let glyphMarginHoverMessage: MarkdownString | undefined; @@ -93,6 +116,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { private ignoreDecorationsChangedEvent = false; private ignoreFirstBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; + private candidateDecoraions: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = []; constructor( private readonly editor: ICodeEditor, @@ -193,16 +217,16 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.ensureBreakpointHintDecoration(-1); })); - this.toDispose.push(this.editor.onDidChangeModel(() => { + this.toDispose.push(this.editor.onDidChangeModel(async () => { this.closeBreakpointWidget(); - this.setDecorations(); + await this.setDecorations(); })); - this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => { + this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => { if (this.ignoreFirstBreakpointsChangeEvent) { this.ignoreFirstBreakpointsChangeEvent = false; return; } - this.setDecorations(); + await this.setDecorations(); })); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); } @@ -311,7 +335,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration); } - private setDecorations(): void { + private async setDecorations(): Promise { if (!this.editor.hasModel()) { return; } @@ -319,11 +343,13 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { const activeCodeEditor = this.editor; const model = activeCodeEditor.getModel(); const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri }); - const desiredDecorations = createBreakpointDecorations(model, breakpoints, this.debugService); + const desiredBreakpointDecorations = createBreakpointDecorations(model, breakpoints, this.debugService); try { this.ignoreDecorationsChangedEvent = true; - const decorationIds = activeCodeEditor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredDecorations); + + // Set breakpoint decorations + const decorationIds = activeCodeEditor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredBreakpointDecorations); this.breakpointDecorations.forEach(bpd => { if (bpd.inlineWidget) { bpd.inlineWidget.dispose(); @@ -333,19 +359,41 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { let inlineWidget: InlineBreakpointWidget | undefined = undefined; const breakpoint = breakpoints[index]; if (breakpoint.column) { - inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column)); + inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredBreakpointDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column)); } return { decorationId, breakpointId: breakpoint.getId(), - range: desiredDecorations[index].range, + range: desiredBreakpointDecorations[index].range, inlineWidget }; }); + } finally { this.ignoreDecorationsChangedEvent = false; } + + // Set breakpoint candidate decorations + const lineNumbers = distinct(this.breakpointDecorations.map(bpd => bpd.range.startLineNumber)); + let desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), lineNumbers, this.debugService); + desiredCandidateDecorations = desiredCandidateDecorations.filter(dbd => { + const breakpointDecorationAlreadyAtCandidateLocation = this.breakpointDecorations.filter(bd => bd.range.equalsRange(dbd.range)).length >= 0; + return !breakpointDecorationAlreadyAtCandidateLocation; + }); + const candidateDecorationids = this.editor.deltaDecorations(this.candidateDecoraions.map(c => c.decorationId), desiredCandidateDecorations); + this.candidateDecoraions.forEach(candidate => { + candidate.inlineWidget.dispose(); + }); + this.candidateDecoraions = candidateDecorationids.map((decorationId, index) => { + const candidate = desiredCandidateDecorations[index]; + const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, 'debug-breakpoint-disabled', undefined, this.debugService, this.contextMenuService, () => this.getContextMenuActions([], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn)); + + return { + decorationId, + inlineWidget + }; + }); } private async onModelDecorationsChanged(): Promise { From c9258e86a61a4d57496f3e6e7fcbe3cd683e48f6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 17:27:10 +0200 Subject: [PATCH 37/82] move credentials service to platform --- .../services => platform}/credentials/common/credentials.ts | 0 src/vs/workbench/api/browser/mainThreadKeytar.ts | 2 +- .../services/credentials/browser/credentialsService.ts | 2 +- .../workbench/services/credentials/node/credentialsService.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/vs/{workbench/services => platform}/credentials/common/credentials.ts (100%) diff --git a/src/vs/workbench/services/credentials/common/credentials.ts b/src/vs/platform/credentials/common/credentials.ts similarity index 100% rename from src/vs/workbench/services/credentials/common/credentials.ts rename to src/vs/platform/credentials/common/credentials.ts diff --git a/src/vs/workbench/api/browser/mainThreadKeytar.ts b/src/vs/workbench/api/browser/mainThreadKeytar.ts index ddcf676a10c..5312a9aad19 100644 --- a/src/vs/workbench/api/browser/mainThreadKeytar.ts +++ b/src/vs/workbench/api/browser/mainThreadKeytar.ts @@ -5,7 +5,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { MainContext, MainThreadKeytarShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; -import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; @extHostNamedCustomer(MainContext.MainThreadKeytar) export class MainThreadKeytar implements MainThreadKeytarShape { diff --git a/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts index e005f8bc302..20946f64ae1 100644 --- a/src/vs/workbench/services/credentials/browser/credentialsService.ts +++ b/src/vs/workbench/services/credentials/browser/credentialsService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; diff --git a/src/vs/workbench/services/credentials/node/credentialsService.ts b/src/vs/workbench/services/credentials/node/credentialsService.ts index 970a5f82034..8c876d5b759 100644 --- a/src/vs/workbench/services/credentials/node/credentialsService.ts +++ b/src/vs/workbench/services/credentials/node/credentialsService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { IdleValue } from 'vs/base/common/async'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; From 6fe6269c41bf555073cc2a0024709f6e76eb6dca Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 17 Sep 2019 17:27:15 +0200 Subject: [PATCH 38/82] Keep better track of custom executions for reruns and depends Fixes #80964 --- src/vs/workbench/api/common/extHostTask.ts | 36 ++++++++++++++-------- src/vs/workbench/api/node/extHostTask.ts | 4 +-- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index a2119063d3d..7667465f6bd 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -374,8 +374,9 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { protected _handlers: Map; protected _taskExecutions: Map; protected _providedCustomExecutions2: Map; + private _notProvidedCustomExecutions: Set; // Used for custom executions tasks that are created and run through executeTask. protected _activeCustomExecutions2: Map; - + private _lastStartedTask: string | undefined; protected readonly _onDidExecuteTask: Emitter = new Emitter(); protected readonly _onDidTerminateTask: Emitter = new Emitter(); @@ -399,6 +400,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._handlers = new Map(); this._taskExecutions = new Map(); this._providedCustomExecutions2 = new Map(); + this._notProvidedCustomExecutions = new Set(); this._activeCustomExecutions2 = new Map(); } @@ -462,6 +464,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._activeCustomExecutions2.set(execution.id, execution2); this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback()); } + this._lastStartedTask = execution.id; this._onDidExecuteTask.fire({ execution: await this.getTaskExecution(execution) @@ -571,7 +574,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { } if (CustomExecution2DTO.is(resolvedTaskDTO.execution)) { - await this.addCustomExecution2(resolvedTaskDTO, resolvedTask); + await this.addCustomExecution2(resolvedTaskDTO, resolvedTask, true); } return await this.resolveTaskInternal(resolvedTaskDTO); @@ -585,8 +588,11 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { return this._handleCounter++; } - protected async addCustomExecution2(taskDTO: tasks.TaskDTO, task: vscode.Task2): Promise { + protected async addCustomExecution2(taskDTO: tasks.TaskDTO, task: vscode.Task2, isProvided: boolean): Promise { const taskId = await this._proxy.$createTaskId(taskDTO); + if (!isProvided && !this._providedCustomExecutions2.has(taskId)) { + this._notProvidedCustomExecutions.add(taskId); + } this._providedCustomExecutions2.set(taskId, (task).execution2); } @@ -618,16 +624,22 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._activeCustomExecutions2.delete(execution.id); } - const lastCustomExecution = this._providedCustomExecutions2.get(execution.id); // Technically we don't really need to do this, however, if an extension // is executing a task through "executeTask" over and over again - // with different properties in the task definition, then this list + // with different properties in the task definition, then the map of executions // could grow indefinitely, something we don't want. - this._providedCustomExecutions2.clear(); - // We do still need to hang on to the last custom execution so that the - // Rerun Task command doesn't choke when it tries to rerun a custom execution - if (lastCustomExecution) { - this._providedCustomExecutions2.set(execution.id, lastCustomExecution); + if (this._notProvidedCustomExecutions.has(execution.id) && (this._lastStartedTask !== execution.id)) { + this._providedCustomExecutions2.delete(execution.id); + this._notProvidedCustomExecutions.delete(execution.id); + } + let iterator = this._notProvidedCustomExecutions.values(); + let iteratorResult = iterator.next(); + while (!iteratorResult.done) { + if (!this._activeCustomExecutions2.has(iteratorResult.value) && (this._lastStartedTask !== iteratorResult.value)) { + this._providedCustomExecutions2.delete(iteratorResult.value); + this._notProvidedCustomExecutions.delete(iteratorResult.value); + } + iteratorResult = iterator.next(); } } @@ -663,7 +675,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // in the provided custom execution map that is cleaned up after the // task is executed. if (CustomExecution2DTO.is(dto.execution)) { - await this.addCustomExecution2(dto, task); + await this.addCustomExecution2(dto, task, false); } else { throw new Error('Not implemented'); } @@ -685,7 +697,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data. - taskIdPromises.push(this.addCustomExecution2(taskDTO, task)); + taskIdPromises.push(this.addCustomExecution2(taskDTO, task, true)); } else { console.warn('Only custom execution tasks supported.'); } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index f1379251ab1..71d8b818b72 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -57,7 +57,7 @@ export class ExtHostTask extends ExtHostTaskBase { // in the provided custom execution map that is cleaned up after the // task is executed. if (CustomExecution2DTO.is(dto.execution)) { - await this.addCustomExecution2(dto, task); + await this.addCustomExecution2(dto, task, false); } return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task)); @@ -80,7 +80,7 @@ export class ExtHostTask extends ExtHostTaskBase { // The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data. - taskIdPromises.push(this.addCustomExecution2(taskDTO, task)); + taskIdPromises.push(this.addCustomExecution2(taskDTO, task, true)); } } } From 874d2fcd3e79244169fa88133657d7a3bb7ba548 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 17:34:23 +0200 Subject: [PATCH 39/82] sketch user data sync store service with log in --- .../platform/product/common/productService.ts | 1 + .../userDataSync/common/userDataSync.ts | 46 ++----------------- .../common/userDataSyncService.ts | 2 +- .../common/userDataSyncStoreService.ts | 45 ++++++++---------- src/vs/workbench/api/common/extHostTypes.ts | 3 +- .../userData/browser/userData.contribution.ts | 9 ++-- .../userDataSync/common/userDataSyncStores.ts | 34 +++++++++++++- 7 files changed, 62 insertions(+), 78 deletions(-) diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index f99f0c6be8d..88c6decf397 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -103,6 +103,7 @@ export interface IProductConfiguration { readonly msftInternalDomains?: string[]; readonly linkProtectionTrustedDomains?: readonly string[]; + readonly settingsSyncStoreUrl?: string; } export interface IExeBasedExtensionTip { diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 4e47e25b391..f54e3f4e62f 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -17,38 +17,6 @@ export enum UserDataSyncStoreErrorCode { Unknown = 'Unknown' } -export function markAsUserDataSyncStoreError(error: Error, code: UserDataSyncStoreErrorCode): Error { - error.name = code ? `${code} (UserDataSyncStoreError)` : `UserDataSyncStoreError`; - - return error; -} - -export function toUserDataSyncStoreErrorCode(error: Error | undefined | null): UserDataSyncStoreErrorCode { - - // Guard against abuse - if (!error) { - return UserDataSyncStoreErrorCode.Unknown; - } - - // FileSystemProviderError comes with the code - if (error instanceof UserDataSyncStoreError) { - return error.code; - } - - // Any other error, check for name match by assuming that the error - // went through the markAsUserDataSyncStoreError() method - const match = /^(.+) \(UserDataSyncStoreError\)$/.exec(error.name); - if (!match) { - return UserDataSyncStoreErrorCode.Unknown; - } - - switch (match[1]) { - case UserDataSyncStoreErrorCode.Rejected: return UserDataSyncStoreErrorCode.Rejected; - } - - return UserDataSyncStoreErrorCode.Unknown; -} - export class UserDataSyncStoreError extends Error { constructor(message: string, public readonly code: UserDataSyncStoreErrorCode) { @@ -57,23 +25,17 @@ export class UserDataSyncStoreError extends Error { } -export interface IUserDataSyncStore { - readonly id: string; - readonly name: string; - read(key: string): Promise; - write(key: string, content: string, ref: string | null): Promise; -} - export const IUserDataSyncStoreService = createDecorator('IUserDataSyncStoreService'); export interface IUserDataSyncStoreService { _serviceBrand: undefined; - readonly onDidChangeEnablement: Event; readonly enabled: boolean; - registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void; - deregisterUserDataSyncStore(): void; + readonly loggedIn: boolean; + readonly onDidChangeLoggedIn: Event; + login(): Promise; + logout(): Promise; read(key: string): Promise; write(key: string, content: string, ref: string | null): Promise; diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 814ea6d5d0c..471a2e644d7 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -32,7 +32,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this.instantiationService.createInstance(SettingsSynchroniser) ]; this.updateStatus(); - this._register(Event.any(this.userDataSyncStoreService.onDidChangeEnablement, ...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus())); + this._register(Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus())); this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal)); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 912746c25ac..e5da8ba57ca 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -4,54 +4,45 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, } from 'vs/base/common/lifecycle'; +import { IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IProductService } from 'vs/platform/product/common/productService'; import { Emitter, Event } from 'vs/base/common/event'; -import { IUserDataSyncStore, IUserData, UserDataSyncStoreError, toUserDataSyncStoreErrorCode, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; -import { ILogService } from 'vs/platform/log/common/log'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { _serviceBrand: any; - private userDataSyncStore: IUserDataSyncStore | null = null; + get enabled(): boolean { return !!this.productService.settingsSyncStoreUrl; } - get enabled(): boolean { return !!this.userDataSyncStore; } - private readonly _onDidChangeEnablement: Emitter = this._register(new Emitter()); - readonly onDidChangeEnablement: Event = this._onDidChangeEnablement.event; + private _loggedIn: boolean = false; + get loggedIn(): boolean { return this._loggedIn; } + private readonly _onDidChangeLoggedIn: Emitter = this._register(new Emitter()); + readonly onDidChangeLoggedIn: Event = this._onDidChangeLoggedIn.event; constructor( - @ILogService private logService: ILogService + @IProductService private readonly productService: IProductService, ) { super(); } - registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void { - if (this.userDataSyncStore) { - this.logService.warn(`A user data sync store '${this.userDataSyncStore.name}' already registered. Hence ignoring the newly registered '${userDataSyncStore.name}' store.`); - return; - } - this.userDataSyncStore = userDataSyncStore; - this._onDidChangeEnablement.fire(true); + async login(): Promise { } - deregisterUserDataSyncStore(): void { - this.userDataSyncStore = null; - this._onDidChangeEnablement.fire(false); + async logout(): Promise { } - read(key: string): Promise { - if (!this.userDataSyncStore) { - throw new Error('No user sync store exists.'); + async read(key: string): Promise { + if (!this.enabled) { + return Promise.reject(new Error('No settings sync store url configured.')); } - return this.userDataSyncStore.read(key) - .then(null, error => Promise.reject(new UserDataSyncStoreError(error.message, toUserDataSyncStoreErrorCode(error)))); + return null; } - write(key: string, content: string, ref: string | null): Promise { - if (!this.userDataSyncStore) { - throw new Error('No user sync store exists.'); + async write(key: string, content: string, ref: string | null): Promise { + if (!this.enabled) { + return Promise.reject(new Error('No settings sync store url configured.')); } - return this.userDataSyncStore.write(key, content, ref) - .then(null, error => Promise.reject(new UserDataSyncStoreError(error.message, toUserDataSyncStoreErrorCode(error)))); + return ''; } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 5ca6f6535be..6462f5b3b9e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -14,7 +14,8 @@ import { generateUuid } from 'vs/base/common/uuid'; import * as vscode from 'vscode'; import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files'; import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { UserDataSyncStoreErrorCode, markAsUserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncStoreErrorCode } from 'vs/platform/userDataSync/common/userDataSync'; +import { markAsUserDataSyncStoreError } from 'vs/workbench/services/userDataSync/common/userDataSyncStores'; function es5ClassCompat(target: Function): any { ///@ts-ignore diff --git a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts index d1c64c8f11a..ed95a7e2571 100644 --- a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts +++ b/src/vs/workbench/contrib/userData/browser/userData.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IUserDataSyncService, SyncStatus, USER_DATA_PREVIEW_SCHEME, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, USER_DATA_PREVIEW_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; import { localize } from 'vs/nls'; import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -52,14 +52,11 @@ class UserDataSyncContribution extends Disposable implements IWorkbenchContribut @IFileService fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, - @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, ) { super(); this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); this.sync(true); - this._register(Event.any( - Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue('userConfiguration.enableSync')), - this.userDataSyncStoreService.onDidChangeEnablement) + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue('userConfiguration.enableSync')) (() => this.sync(true))); // Sync immediately if there is a local change. @@ -67,7 +64,7 @@ class UserDataSyncContribution extends Disposable implements IWorkbenchContribut } private async sync(loop: boolean): Promise { - if (this.configurationService.getValue('userConfiguration.enableSync') && this.userDataSyncStoreService.enabled) { + if (this.configurationService.getValue('userConfiguration.enableSync')) { try { await this.userDataSyncService.sync(); } catch (e) { diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts index b7bf3c91ce5..cd83212d09b 100644 --- a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts +++ b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts @@ -4,11 +4,43 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { Registry } from 'vs/platform/registry/common/platform'; +export function markAsUserDataSyncStoreError(error: Error, code: UserDataSyncStoreErrorCode): Error { + error.name = code ? `${code} (UserDataSyncStoreError)` : `UserDataSyncStoreError`; + + return error; +} + +export function toUserDataSyncStoreErrorCode(error: Error | undefined | null): UserDataSyncStoreErrorCode { + + // Guard against abuse + if (!error) { + return UserDataSyncStoreErrorCode.Unknown; + } + + // FileSystemProviderError comes with the code + if (error instanceof UserDataSyncStoreError) { + return error.code; + } + + // Any other error, check for name match by assuming that the error + // went through the markAsUserDataSyncStoreError() method + const match = /^(.+) \(UserDataSyncStoreError\)$/.exec(error.name); + if (!match) { + return UserDataSyncStoreErrorCode.Unknown; + } + + switch (match[1]) { + case UserDataSyncStoreErrorCode.Rejected: return UserDataSyncStoreErrorCode.Rejected; + } + + return UserDataSyncStoreErrorCode.Unknown; +} + export interface IUserDataSyncStore { readonly id: string; readonly name: string; From 7ecb5821cdc3035a54280265dee4ccc8ef1cdfd4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 17:47:02 +0200 Subject: [PATCH 40/82] debt - remove IWindowService#log in favor of a logger that can log to the main side --- .../issue/issueReporterMain.ts | 6 +-- .../sharedProcess/sharedProcessMain.ts | 8 +-- src/vs/code/electron-main/app.ts | 8 +-- src/vs/platform/log/common/log.ts | 51 ++++++++++++++++++- src/vs/platform/log/common/logIpc.ts | 31 +++++++++-- src/vs/platform/windows/common/windows.ts | 1 - src/vs/platform/windows/common/windowsIpc.ts | 1 - .../electron-browser/windowsService.ts | 4 -- .../windows/electron-main/windowsService.ts | 18 ------- .../api/browser/mainThreadConsole.ts | 9 ++-- .../workbench/browser/web.simpleservices.ts | 4 -- .../remote/common/remote.contribution.ts | 8 +-- .../electron-browser/remote.contribution.ts | 4 +- .../electron-browser/desktop.main.ts | 27 +++++++--- .../extensions/common/remoteConsoleUtil.ts | 32 ++++++++++++ .../electron-browser/extensionHost.ts | 8 +-- .../workbench/test/workbenchTestServices.ts | 4 -- 17 files changed, 155 insertions(+), 69 deletions(-) create mode 100644 src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index a0f146faa19..6d0693d7657 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -32,7 +32,7 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/electron-browser/issue/issueReporterModel'; import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/node/issue'; import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil'; @@ -300,8 +300,8 @@ export class IssueReporter extends Disposable { this.environmentService = new EnvironmentService(configuration, configuration.execPath); const logService = new SpdLogService(`issuereporter${configuration.windowId}`, this.environmentService.logsPath, getLogLevel(this.environmentService)); - const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); - this.logService = new FollowerLogService(logLevelClient, logService); + const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger')); + this.logService = new FollowerLogService(loggerClient, logService); const sharedProcess = (serviceCollection.get(IWindowsService)).whenSharedProcessReady() .then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${configuration.windowId}`)); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 56f7ed460f3..6343cddc3a8 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -30,7 +30,7 @@ import { IWindowsService } from 'vs/platform/windows/common/windows'; import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc'; @@ -96,8 +96,8 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const environmentService = new EnvironmentService(initData.args, process.execPath); const mainRouter = new StaticRouter(ctx => ctx === 'main'); - const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', mainRouter)); - const logService = new FollowerLogService(logLevelClient, new SpdLogService('sharedprocess', environmentService.logsPath, initData.logLevel)); + const loggerClient = new LoggerChannelClient(server.getChannel('logger', mainRouter)); + const logService = new FollowerLogService(loggerClient, new SpdLogService('sharedprocess', environmentService.logsPath, initData.logLevel)); disposables.add(logService); logService.info('main', JSON.stringify(configuration)); @@ -135,7 +135,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const services = new ServiceCollection(); const environmentService = accessor.get(IEnvironmentService); const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService; - const telemetryLogService = new FollowerLogService(logLevelClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel)); + const telemetryLogService = new FollowerLogService(loggerClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel)); telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.'); telemetryLogService.info('==========================================================='); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 4e2f8842a9e..f0eeddedf86 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -47,7 +47,7 @@ import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateServ import { IIssueService } from 'vs/platform/issue/node/issue'; import { IssueChannel } from 'vs/platform/issue/electron-main/issueIpc'; import { IssueMainService } from 'vs/platform/issue/electron-main/issueMainService'; -import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; +import { LoggerChannel } from 'vs/platform/log/common/logIpc'; import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/errors'; import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener'; import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; @@ -567,9 +567,9 @@ export class CodeApplication extends Disposable { const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService)); electronIpcServer.registerChannel('storage', storageChannel); - const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService)); - electronIpcServer.registerChannel('loglevel', logLevelChannel); - sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); + const loggerChannel = new LoggerChannel(accessor.get(ILogService)); + electronIpcServer.registerChannel('logger', loggerChannel); + sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel)); // ExtensionHost Debug broadcast service electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 5e6b7300c49..0009b304e53 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -8,6 +8,7 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { isWindows } from 'vs/base/common/platform'; import { Event, Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; export const ILogService = createServiceDecorator('logService'); @@ -183,6 +184,54 @@ export class ConsoleLogService extends AbstractLogService implements ILogService dispose(): void { } } +export class ConsoleLogInMainService extends AbstractLogService implements ILogService { + + _serviceBrand: undefined; + + constructor(private readonly client: LoggerChannelClient, logLevel: LogLevel = DEFAULT_LOG_LEVEL) { + super(); + this.setLevel(logLevel); + } + + trace(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Trace) { + this.client.consoleLog('trace', [message, ...args]); + } + } + + debug(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Debug) { + this.client.consoleLog('debug', [message, ...args]); + } + } + + info(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Info) { + this.client.consoleLog('info', [message, ...args]); + } + } + + warn(message: string | Error, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Warning) { + this.client.consoleLog('warn', [message, ...args]); + } + } + + error(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Error) { + this.client.consoleLog('error', [message, ...args]); + } + } + + critical(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Critical) { + this.client.consoleLog('critical', [message, ...args]); + } + } + + dispose(): void { } +} + export class MultiplexLogService extends AbstractLogService implements ILogService { _serviceBrand: undefined; @@ -326,4 +375,4 @@ export function getLogLevel(environmentService: IEnvironmentService): LogLevel { } } return DEFAULT_LOG_LEVEL; -} \ No newline at end of file +} diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index 5f631b8b9d1..260922cedcb 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -7,7 +7,7 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { LogLevel, ILogService, DelegatedLogService } from 'vs/platform/log/common/log'; import { Event } from 'vs/base/common/event'; -export class LogLevelSetterChannel implements IServerChannel { +export class LoggerChannel implements IServerChannel { onDidChangeLogLevel: Event; @@ -26,13 +26,32 @@ export class LogLevelSetterChannel implements IServerChannel { call(_: unknown, command: string, arg?: any): Promise { switch (command) { case 'setLevel': this.service.setLevel(arg); return Promise.resolve(); + case 'consoleLog': this.consoleLog(arg[0], arg[1]); return Promise.resolve(); } throw new Error(`Call not found: ${command}`); } + + private consoleLog(severity: string, args: string[]): void { + let consoleFn = console.log; + + switch (severity) { + case 'error': + consoleFn = console.error; + break; + case 'warn': + consoleFn = console.warn; + break; + case 'info': + consoleFn = console.info; + break; + } + + consoleFn.call(console, ...args); + } } -export class LogLevelSetterChannelClient { +export class LoggerChannelClient { constructor(private channel: IChannel) { } @@ -43,12 +62,16 @@ export class LogLevelSetterChannelClient { setLevel(level: LogLevel): void { this.channel.call('setLevel', level); } + + consoleLog(severity: string, args: string[]): void { + this.channel.call('consoleLog', [severity, args]); + } } export class FollowerLogService extends DelegatedLogService implements ILogService { _serviceBrand: undefined; - constructor(private master: LogLevelSetterChannelClient, logService: ILogService) { + constructor(private master: LoggerChannelClient, logService: ILogService) { super(logService); this._register(master.onDidChangeLogLevel(level => logService.setLevel(level))); } @@ -56,4 +79,4 @@ export class FollowerLogService extends DelegatedLogService implements ILogServi setLevel(level: LogLevel): void { this.master.setLevel(level); } -} \ No newline at end of file +} diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 7f697c0d445..97f4c9b7687 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -156,7 +156,6 @@ export interface IWindowsService { openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>; getWindowCount(): Promise; - log(severity: string, args: string[]): Promise; showItemInFolder(path: URI): Promise; getActiveWindowId(): Promise; diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 5e3c0944d94..091f49e137f 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -109,7 +109,6 @@ export class WindowsChannel implements IServerChannel { case 'whenSharedProcessReady': return this.service.whenSharedProcessReady(); case 'toggleSharedProcess': return this.service.toggleSharedProcess(); case 'quit': return this.service.quit(); - case 'log': return this.service.log(arg[0], arg[1]); case 'showItemInFolder': return this.service.showItemInFolder(URI.revive(arg)); case 'getActiveWindowId': return this.service.getActiveWindowId(); case 'openExternal': return this.service.openExternal(arg); diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index d6089d90776..283259ac8d6 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -226,10 +226,6 @@ export class WindowsService implements IWindowsService { return this.channel.call('getWindowCount'); } - log(severity: string, args: string[]): Promise { - return this.channel.call('log', [severity, args]); - } - showItemInFolder(path: URI): Promise { return this.channel.call('showItemInFolder', path); } diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index c6ee7cfc593..740891b52f9 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -336,24 +336,6 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH return this.windowsMainService.getWindows().length; } - async log(severity: string, args: string[]): Promise { - let consoleFn = console.log; - - switch (severity) { - case 'error': - consoleFn = console.error; - break; - case 'warn': - consoleFn = console.warn; - break; - case 'info': - consoleFn = console.info; - break; - } - - consoleFn.call(console, ...args); - } - async showItemInFolder(resource: URI): Promise { this.logService.trace('windowsService#showItemInFolder'); diff --git a/src/vs/workbench/api/browser/mainThreadConsole.ts b/src/vs/workbench/api/browser/mainThreadConsole.ts index 1d7a7723404..4a244875f42 100644 --- a/src/vs/workbench/api/browser/mainThreadConsole.ts +++ b/src/vs/workbench/api/browser/mainThreadConsole.ts @@ -6,9 +6,10 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { MainContext, MainThreadConsoleShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console'; +import { IRemoteConsoleLog, log } from 'vs/base/common/console'; +import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { ILogService } from 'vs/platform/log/common/log'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; @extHostNamedCustomer(MainContext.MainThreadConsole) @@ -20,7 +21,7 @@ export class MainThreadConsole implements MainThreadConsoleShape { constructor( extHostContext: IExtHostContext, @IEnvironmentService private readonly _environmentService: IEnvironmentService, - @IWindowsService private readonly _windowsService: IWindowsService, + @ILogService private readonly _logService: ILogService, @IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService, ) { const devOpts = parseExtensionDevOptions(this._environmentService); @@ -40,7 +41,7 @@ export class MainThreadConsole implements MainThreadConsoleShape { // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(entry.severity, parse(entry).args); + logRemoteEntry(this._logService, entry); } // Broadcast to other windows if we are in development mode diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 86e496ceedd..87a1fee80e8 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -508,10 +508,6 @@ export class SimpleWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - log(_severity: string, _args: string[]): Promise { - return Promise.resolve(); - } - showItemInFolder(_path: URI): Promise { return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 8ec38b3795e..1f4297c039f 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -11,7 +11,7 @@ import { OperatingSystem, isWeb } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; import { ILogService } from 'vs/platform/log/common/log'; -import { LogLevelSetterChannelClient } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output'; import { localize } from 'vs/nls'; import { joinPath } from 'vs/base/common/resources'; @@ -79,9 +79,9 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib super(); const connection = remoteAgentService.getConnection(); if (connection) { - const logLevelClient = new LogLevelSetterChannelClient(connection.getChannel('loglevel')); - logLevelClient.setLevel(logService.getLevel()); - this._register(logService.onDidChangeLogLevel(level => logLevelClient.setLevel(level))); + const loggerClient = new LoggerChannelClient(connection.getChannel('logger')); + loggerClient.setLevel(logService.getLevel()); + this._register(logService.onDidChangeLogLevel(level => loggerClient.setLevel(level))); } } } diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 37cae45ace2..e45a5faa59e 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -26,7 +26,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc'; import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; -import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; +import { LoggerChannel } from 'vs/platform/log/common/logIpc'; import { ipcRenderer as ipc } from 'electron'; import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -229,7 +229,7 @@ class RemoteChannelsContribution implements IWorkbenchContribution { if (connection) { connection.registerChannel('dialog', new DialogChannel(dialogService)); connection.registerChannel('download', new DownloadServiceChannel(downloadService)); - connection.registerChannel('loglevel', new LogLevelSetterChannel(logService)); + connection.registerChannel('logger', new LoggerChannel(logService)); } } } diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index ebf89cda089..076d03a5b1e 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -23,9 +23,9 @@ import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { webFrame } from 'electron'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ConsoleLogService, MultiplexLogService, ILogService } from 'vs/platform/log/common/log'; +import { ConsoleLogService, MultiplexLogService, ILogService, ConsoleLogInMainService } from 'vs/platform/log/common/log'; import { StorageService } from 'vs/platform/storage/node/storageService'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { Schemas } from 'vs/base/common/network'; import { sanitizeFilePath } from 'vs/base/common/extpath'; import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; @@ -345,12 +345,25 @@ class CodeRendererMain extends Disposable { } private createLogService(mainProcessService: IMainProcessService, environmentService: IWorkbenchEnvironmentService): ILogService { - const spdlogService = new SpdLogService(`renderer${this.environmentService.configuration.windowId}`, environmentService.logsPath, this.environmentService.configuration.logLevel); - const consoleLogService = new ConsoleLogService(this.environmentService.configuration.logLevel); - const logService = new MultiplexLogService([consoleLogService, spdlogService]); - const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); + const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger')); - return new FollowerLogService(logLevelClient, logService); + // Extension development test CLI: forward everything to main side + const loggers: ILogService[] = []; + if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { + loggers.push( + new ConsoleLogInMainService(loggerClient, this.environmentService.configuration.logLevel) + ); + } + + // Normal logger: spdylog and console + else { + loggers.push( + new ConsoleLogService(this.environmentService.configuration.logLevel), + new SpdLogService(`renderer${this.environmentService.configuration.windowId}`, environmentService.logsPath, this.environmentService.configuration.logLevel) + ); + } + + return new FollowerLogService(loggerClient, new MultiplexLogService(loggers)); } } diff --git a/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts b/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts new file mode 100644 index 00000000000..58ca081f88f --- /dev/null +++ b/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRemoteConsoleLog, parse } from 'vs/base/common/console'; +import { ILogService } from 'vs/platform/log/common/log'; + +export function logRemoteEntry(logService: ILogService, entry: IRemoteConsoleLog): void { + const args = parse(entry).args; + const firstArg = args.shift(); + if (typeof firstArg !== 'string') { + return; + } + + if (!entry.severity) { + entry.severity = 'info'; + } + + switch (entry.severity) { + case 'log': + case 'info': + logService.info(firstArg, ...args); + break; + case 'warn': + logService.warn(firstArg, ...args); + break; + case 'error': + logService.error(firstArg, ...args); + break; + } +} diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 5d5e96479a2..4ceaca310a8 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -14,7 +14,8 @@ import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; -import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console'; +import { IRemoteConsoleLog, log } from 'vs/base/common/console'; +import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; @@ -26,7 +27,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; @@ -67,7 +68,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { private readonly _extensionHostLogsLocation: URI, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @INotificationService private readonly _notificationService: INotificationService, - @IWindowsService private readonly _windowsService: IWindowsService, @IWindowService private readonly _windowService: IWindowService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @@ -435,7 +435,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(entry.severity, parse(entry).args); + logRemoteEntry(this._logService, entry); } // Broadcast to other windows if we are in development mode diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 6c4add507aa..ad9ae1c822d 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -1494,10 +1494,6 @@ export class TestWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - log(_severity: string, _args: string[]): Promise { - return Promise.resolve(); - } - showItemInFolder(_path: URI): Promise { return Promise.resolve(); } From 99a7194d4e77699bb13cb04c003234786c8cb5c2 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 09:02:29 -0700 Subject: [PATCH 41/82] Remove svg reference --- src/vs/base/browser/ui/codiconLabel/codicon/codicon.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 689f29ba4c6..417afa0de5d 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,8 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?e042d2dda15ef7b36b910e3edf539f26") format("truetype"), -url("./codicon.svg?e042d2dda15ef7b36b910e3edf539f26#codicon") format("svg"); + src: url("./codicon.ttf?e042d2dda15ef7b36b910e3edf539f26") format("truetype"); } .codicon[class*='codicon-'] { From 74bcfa3aa3e9c1800b6d40391781276a8c15ca70 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 18:04:49 +0200 Subject: [PATCH 42/82] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 673662926a8..1fc6e8141ae 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.39.0", - "distro": "e892717dc1ae3cea3824697bc2c28d64f8476f93", + "distro": "e1ddf4bc0450761d824c22ed1b7d24888f51bac9", "author": { "name": "Microsoft Corporation" }, From 0fa53a6e66fb6d0c372dde3d1a6fcfab475c20dc Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 09:05:42 -0700 Subject: [PATCH 43/82] Update refs to include codicon --- build/gulpfile.editor.js | 2 ++ build/gulpfile.hygiene.js | 1 + build/gulpfile.vscode.js | 1 + 3 files changed, 4 insertions(+) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 7bbf246a8dc..44f38953adb 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -45,6 +45,7 @@ var editorResources = [ '!out-build/vs/base/browser/ui/splitview/**/*', '!out-build/vs/base/browser/ui/toolbar/**/*', '!out-build/vs/base/browser/ui/octiconLabel/**/*', + '!out-build/vs/base/browser/ui/codiconLabel/**/*', '!out-build/vs/workbench/**', '!**/test/**' ]; @@ -91,6 +92,7 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { ], redirects: { 'vs/base/browser/ui/octiconLabel/octiconLabel': 'vs/base/browser/ui/octiconLabel/octiconLabel.mock', + 'vs/base/browser/ui/codiconLabel/codiconLabel': 'vs/base/browser/ui/codiconLabel/codiconLabel.mock', }, shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers importIgnorePattern: /(^vs\/css!)|(promise-polyfill\/polyfill)/, diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 5c60d5db221..30c98f95d06 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -72,6 +72,7 @@ const indentationFilter = [ // except multiple specific folders '!**/octicons/**', + '!**/codicon/**', '!**/fixtures/**', '!**/lib/**', '!extensions/**/out/**', diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 3e9e2276bfe..9a63fcec936 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -68,6 +68,7 @@ const vscodeResources = [ 'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', + 'out-build/vs/base/browser/ui/codiconLabel/codicon/**', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', From 945d678d361270dd3ebfc68ad5efffa245ed52ea Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 17 Sep 2019 18:06:50 +0200 Subject: [PATCH 44/82] uv_pipe_open error when starting code-insiders from WSL microsoft/vscode-remote-release#1420 --- resources/win32/bin/code.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index f925851fb95..43aaa25a96e 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -27,15 +27,15 @@ if grep -qi Microsoft /proc/version; then WSL_EXT_ID="ms-vscode-remote.remote-wsl" if [ $WSL_BUILD -ge 41955 -a $WSL_BUILD -lt 41959 ]; then - # WSL2 in workaround for https://github.com/microsoft/WSL/issues/4337 + # WSL2 workaround for https://github.com/microsoft/WSL/issues/4337 CWD="$(pwd)" cd "$VSCODE_PATH" - cmd.exe /C ".\\bin\\$APP_NAME.cmd --locate-extension $WSL_EXT_ID >remote-wsl-loc.txt" - WSL_EXT_WLOC="$(cat ./remote-wsl-loc.txt)" - rm remote-wsl-loc.txt + cmd.exe /C ".\\bin\\$APP_NAME.cmd --locate-extension $WSL_EXT_ID >%TEMP%\\remote-wsl-loc.txt" + WSL_EXT_WLOC=$(cmd.exe /C type %TEMP%\\remote-wsl-loc.txt) cd "$CWD" else - WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID) + ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID >/tmp/remote-wsl-loc.txt + WSL_EXT_WLOC=$(cat /tmp/remote-wsl-loc.txt) fi if [ -n "$WSL_EXT_WLOC" ]; then # replace \r\n with \n in WSL_EXT_WLOC From 66a25a0ec1a7c3e599b246eb9538bc3b84839967 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 18:13:47 +0200 Subject: [PATCH 45/82] electron-main renames :lipstick: --- src/vs/code/electron-main/app.ts | 24 ++++++++--------- src/vs/code/electron-main/main.ts | 16 ++++++------ src/vs/code/electron-main/sharedProcess.ts | 4 +-- src/vs/code/electron-main/windows.ts | 26 +++++++++---------- .../platform/driver/electron-main/driver.ts | 14 +++++----- .../electron-main/historyMainService.ts | 5 ++-- .../issue/electron-main/issueMainService.ts | 14 +++++----- .../platform/menubar/electron-main/menubar.ts | 4 +-- .../electron-main/abstractUpdateService.ts | 4 +-- .../electron-main/updateService.darwin.ts | 4 +-- .../electron-main/updateService.linux.ts | 4 +-- .../electron-main/updateService.snap.ts | 10 +++---- .../electron-main/updateService.win32.ts | 4 +-- .../url/electron-main/electronUrlListener.ts | 6 ++--- .../windows/electron-main/windowsService.ts | 16 ++++++------ 15 files changed, 78 insertions(+), 77 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f0eeddedf86..72b1fdc43fb 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -92,7 +92,7 @@ export class CodeApplication extends Disposable { @IInstantiationService private readonly instantiationService: IInstantiationService, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStateService private readonly stateService: IStateService ) { @@ -109,7 +109,7 @@ export class CodeApplication extends Disposable { process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); // Dispose on shutdown - this.lifecycleService.onWillShutdown(() => this.dispose()); + this.lifecycleMainService.onWillShutdown(() => this.dispose()); // Contextmenu via IPC support registerContextMenuListener(); @@ -255,7 +255,7 @@ export class CodeApplication extends Disposable { this.logService.trace('IPC#vscode:exit', code); this.dispose(); - this.lifecycleService.kill(code); + this.lifecycleMainService.kill(code); }); ipc.on('vscode:fetchShellEnv', async (event: Electron.IpcMainEvent) => { @@ -282,7 +282,7 @@ export class CodeApplication extends Disposable { // Some listeners after window opened (async () => { - await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen); + await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen); // After waking up from sleep (after window opened) powerMonitor.on('resume', () => { @@ -361,7 +361,7 @@ export class CodeApplication extends Disposable { // Spawn shared process after the first window has opened and 3s have passed const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); - this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { + this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { this._register(new RunOnceScheduler(async () => { const userEnv = await getShellEnvironment(this.logService, this.environmentService); @@ -461,7 +461,7 @@ export class CodeApplication extends Disposable { const storageMainService = new StorageMainService(this.logService, this.environmentService); services.set(IStorageMainService, storageMainService); - this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close())); + this.lifecycleMainService.onWillShutdown(e => e.join(storageMainService.close())); const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); services.set(IBackupMainService, backupMainService); @@ -529,8 +529,8 @@ export class CodeApplication extends Disposable { private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise>): ICodeWindow[] { // Register more Main IPC services - const launchService = accessor.get(ILaunchMainService); - const launchChannel = new LaunchChannel(launchService); + const launchMainService = accessor.get(ILaunchMainService); + const launchChannel = new LaunchChannel(launchMainService); this.mainIpcServer.registerChannel('launch', launchChannel); // Register more Electron IPC services @@ -546,8 +546,8 @@ export class CodeApplication extends Disposable { const electronChannel = new ElectronChannel(electronService); electronIpcServer.registerChannel('electron', electronChannel); - const workspacesService = accessor.get(IWorkspacesMainService); - const workspacesChannel = new WorkspacesChannel(workspacesService); + const workspacesMainService = accessor.get(IWorkspacesMainService); + const workspacesChannel = new WorkspacesChannel(workspacesMainService); electronIpcServer.registerChannel('workspaces', workspacesChannel); const windowsService = accessor.get(IWindowsService); @@ -575,7 +575,7 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); // Signal phase: ready (services set) - this.lifecycleService.phase = LifecycleMainPhase.Ready; + this.lifecycleMainService.phase = LifecycleMainPhase.Ready; // Propagate to clients const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); @@ -685,7 +685,7 @@ export class CodeApplication extends Disposable { private afterWindowOpen(): void { // Signal phase: after window open - this.lifecycleService.phase = LifecycleMainPhase.AfterWindowOpen; + this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen; // Remote Authorities this.handleRemoteAuthorities(); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index f2d5cf7b88d..534cfddbe4c 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -116,13 +116,13 @@ class CodeMain { await instantiationService.invokeFunction(async accessor => { const environmentService = accessor.get(IEnvironmentService); const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleMainService); + const lifecycleMainService = accessor.get(ILifecycleMainService); const configurationService = accessor.get(IConfigurationService); - const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true); + const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, true); bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel()); - once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose()); + once(lifecycleMainService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose()); return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); }); @@ -189,7 +189,7 @@ class CodeMain { return instanceEnvironment; } - private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise { + private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, retry: boolean): Promise { // Try to setup a server for running. If that succeeds it means // we are the first instance to startup. Otherwise it is likely @@ -197,7 +197,7 @@ class CodeMain { let server: Server; try { server = await serve(environmentService.mainIPCHandle); - once(lifecycleService.onWillShutdown)(() => server.dispose()); + once(lifecycleMainService.onWillShutdown)(() => server.dispose()); } catch (error) { // Handle unexpected errors (the only expected error is EADDRINUSE that @@ -245,7 +245,7 @@ class CodeMain { throw error; } - return this.doStartup(logService, environmentService, lifecycleService, instantiationService, false); + return this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, false); } // Tests from CLI require to be the only instance currently @@ -374,7 +374,7 @@ class CodeMain { private quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleMainService); + const lifecycleMainService = accessor.get(ILifecycleMainService); let exitCode = 0; @@ -394,7 +394,7 @@ class CodeMain { } } - lifecycleService.kill(exitCode); + lifecycleMainService.kill(exitCode); } } diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 29ef3a38ddc..b59ecadb78f 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -24,7 +24,7 @@ export class SharedProcess implements ISharedProcess { private readonly machineId: string, private userEnv: NodeJS.ProcessEnv, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @IThemeMainService private readonly themeMainService: IThemeMainService ) { } @@ -68,7 +68,7 @@ export class SharedProcess implements ISharedProcess { const disposables = new DisposableStore(); - this.lifecycleService.onWillShutdown(() => { + this.lifecycleMainService.onWillShutdown(() => { disposables.dispose(); // Shut the shared process down when we are quitting diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d5ba7ef2ae2..3bb019cd961 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -188,7 +188,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -207,8 +207,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.dialogs = new Dialogs(stateService, this); this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); - this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); - this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); + this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); + this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); } private installWindowsMutex(): void { @@ -217,7 +217,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { try { const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; const mutex = new WindowsMutex(win32MutexName); - once(this.lifecycleService.onWillShutdown)(() => mutex.release()); + once(this.lifecycleMainService.onWillShutdown)(() => mutex.release()); } catch (e) { this.logService.error(e); } @@ -251,8 +251,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Handle various lifecycle events around windows - this.lifecycleService.onBeforeWindowClose(window => this.onBeforeWindowClose(window)); - this.lifecycleService.onBeforeShutdown(() => this.onBeforeShutdown()); + this.lifecycleMainService.onBeforeWindowClose(window => this.onBeforeWindowClose(window)); + this.lifecycleMainService.onBeforeShutdown(() => this.onBeforeShutdown()); this.onWindowsCountChanged(e => { if (e.newCount - e.oldCount > 0) { // clear last closed window state when a new window opens. this helps on macOS where @@ -340,7 +340,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // See note on #onBeforeShutdown() for details how these events are flowing private onBeforeWindowClose(win: ICodeWindow): void { - if (this.lifecycleService.quitRequested) { + if (this.lifecycleMainService.quitRequested) { return; // during quit, many windows close in parallel so let it be handled in the before-quit handler } @@ -985,7 +985,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private getRestoreWindowsSetting(): RestoreWindowsSetting { let restoreWindows: RestoreWindowsSetting; - if (this.lifecycleService.wasRestarted) { + if (this.lifecycleMainService.wasRestarted) { restoreWindows = 'all'; // always reopen all windows when an update was applied } else { const windowConfig = this.configurationService.getValue('window'); @@ -1328,7 +1328,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Window state is from a previous session: only allow fullscreen when we got updated or user wants to restore else { - allowFullscreen = this.lifecycleService.wasRestarted || (windowConfig && windowConfig.restoreFullscreen); + allowFullscreen = this.lifecycleMainService.wasRestarted || (windowConfig && windowConfig.restoreFullscreen); } if (state.mode === WindowMode.Fullscreen && !allowFullscreen) { @@ -1364,7 +1364,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { window.win.on('closed', () => this.onWindowClosed(window!)); // Lifecycle - (this.lifecycleService as LifecycleMainService).registerWindow(window); + (this.lifecycleMainService as LifecycleMainService).registerWindow(window); } // Existing window @@ -1387,7 +1387,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // first and only load the new configuration if that was // not vetoed if (window.isReady) { - this.lifecycleService.unload(window, UnloadReason.LOAD).then(veto => { + this.lifecycleMainService.unload(window, UnloadReason.LOAD).then(veto => { if (!veto) { this.doOpenInBrowserWindow(window!, configuration, options); } @@ -1554,7 +1554,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { async reload(win: ICodeWindow, cli?: ParsedArgs): Promise { // Only reload when the window has not vetoed this - const veto = await this.lifecycleService.unload(win, UnloadReason.RELOAD); + const veto = await this.lifecycleMainService.unload(win, UnloadReason.RELOAD); if (!veto) { win.reload(undefined, cli); } @@ -1866,7 +1866,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Otherwise: normal quit else { setTimeout(() => { - this.lifecycleService.quit(); + this.lifecycleMainService.quit(); }, 10 /* delay to unwind callback stack (IPC) */); } } diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 49404125de3..8966f02836c 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -34,7 +34,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { constructor( private windowServer: IPCServer, private options: IDriverOptions, - @IWindowsMainService private readonly windowsService: IWindowsMainService + @IWindowsMainService private readonly windowsMainService: IWindowsMainService ) { } async registerWindowDriver(windowId: number): Promise { @@ -49,7 +49,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { } async getWindowIds(): Promise { - return this.windowsService.getWindows() + return this.windowsMainService.getWindows() .map(w => w.id) .filter(id => this.registeredWindowIds.has(id) && !this.reloadingWindowIds.has(id)); } @@ -57,7 +57,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { async capturePage(windowId: number): Promise { await this.whenUnfrozen(windowId); - const window = this.windowsService.getWindowById(windowId); + const window = this.windowsMainService.getWindowById(windowId); if (!window) { throw new Error('Invalid window'); } @@ -69,16 +69,16 @@ export class Driver implements IDriver, IWindowDriverRegistry { async reloadWindow(windowId: number): Promise { await this.whenUnfrozen(windowId); - const window = this.windowsService.getWindowById(windowId); + const window = this.windowsMainService.getWindowById(windowId); if (!window) { throw new Error('Invalid window'); } this.reloadingWindowIds.add(windowId); - this.windowsService.reload(window); + this.windowsMainService.reload(window); } async exitApplication(): Promise { - return this.windowsService.quit(); + return this.windowsMainService.quit(); } async dispatchKeybinding(windowId: number, keybinding: string): Promise { @@ -96,7 +96,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { throw new Error('ScanCodeBindings not supported'); } - const window = this.windowsService.getWindowById(windowId); + const window = this.windowsMainService.getWindowById(windowId); if (!window) { throw new Error('Invalid window'); } diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index b67c268b997..a76d56fcc21 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -29,6 +29,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const IHistoryMainService = createDecorator('historyMainService'); export interface IHistoryMainService { + _serviceBrand: undefined; onRecentlyOpenedChange: CommonEvent; @@ -68,11 +69,11 @@ export class HistoryMainService implements IHistoryMainService { @ILogService private readonly logService: ILogService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService lifecycleService: ILifecycleMainService + @ILifecycleMainService lifecycleMainService: ILifecycleMainService ) { this.macOSRecentDocumentsUpdater = new ThrottledDelayer(800); - lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); + lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); } private handleWindowsJumpList(): void { diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index 2278e311a04..55d332040c5 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -31,7 +31,7 @@ export class IssueMainService implements IIssueService { private machineId: string, private userEnv: IProcessEnvironment, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILaunchMainService private readonly launchService: ILaunchMainService, + @ILaunchMainService private readonly launchMainService: ILaunchMainService, @ILogService private readonly logService: ILogService, @IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService, @IWindowsService private readonly windowsService: IWindowsService @@ -41,7 +41,7 @@ export class IssueMainService implements IIssueService { private registerListeners(): void { ipcMain.on('vscode:issueSystemInfoRequest', async (event: Electron.IpcMainEvent) => { - Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]) + Promise.all([this.launchMainService.getMainProcessInfo(), this.launchMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]) .then(result => { const [info, remoteData] = result; this.diagnosticsService.getSystemInfo(info, remoteData).then(msg => { @@ -54,9 +54,9 @@ export class IssueMainService implements IIssueService { const processes = []; try { - const mainPid = await this.launchService.getMainProcessId(); + const mainPid = await this.launchMainService.getMainProcessId(); processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(mainPid) }); - (await this.launchService.getRemoteDiagnostics({ includeProcesses: true })) + (await this.launchMainService.getRemoteDiagnostics({ includeProcesses: true })) .forEach(data => { if (isRemoteDiagnosticError(data)) { processes.push({ @@ -157,7 +157,7 @@ export class IssueMainService implements IIssueService { }); ipcMain.on('windowsInfoRequest', (event: Electron.IpcMainEvent) => { - this.launchService.getMainProcessInfo().then(info => { + this.launchMainService.getMainProcessInfo().then(info => { event.sender.send('vscode:windowsInfoResponse', info.windows); }); }); @@ -268,7 +268,7 @@ export class IssueMainService implements IIssueService { } public async getSystemStatus(): Promise { - return Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]) + return Promise.all([this.launchMainService.getMainProcessInfo(), this.launchMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]) .then(result => { const [info, remoteData] = result; return this.diagnosticsService.getDiagnostics(info, remoteData); @@ -345,7 +345,7 @@ export class IssueMainService implements IIssueService { private getPerformanceInfo(): Promise { return new Promise(async (resolve, reject) => { - Promise.all([this.launchService.getMainProcessInfo(), this.launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })]) + Promise.all([this.launchMainService.getMainProcessInfo(), this.launchMainService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })]) .then(result => { const [info, remoteData] = result; this.diagnosticsService.getPerformanceInfo(info, remoteData) diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 25139ec68e5..70caae25b47 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -68,7 +68,7 @@ export class Menubar { @ITelemetryService private readonly telemetryService: ITelemetryService, @IHistoryMainService private readonly historyMainService: IHistoryMainService, @IStateService private readonly stateService: IStateService, - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService ) { this.menuUpdater = new RunOnceScheduler(() => this.doUpdateMenu(), 0); @@ -160,7 +160,7 @@ export class Menubar { private registerListeners(): void { // Keep flag when app quits - this.lifecycleService.onWillShutdown(() => this.willShutdown = true); + this.lifecycleMainService.onWillShutdown(() => this.willShutdown = true); // // Listen to some events from window service to update menu this.windowsMainService.onWindowsCountChanged(e => this.onWindowsCountChanged(e)); diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index 8847db647a7..276c468a51a 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -44,7 +44,7 @@ export abstract class AbstractUpdateService implements IUpdateService { } constructor( - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IConfigurationService protected configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IRequestService protected requestService: IRequestService, @@ -152,7 +152,7 @@ export abstract class AbstractUpdateService implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); - this.lifecycleService.quit(true /* from update */).then(vetod => { + this.lifecycleMainService.quit(true /* from update */).then(vetod => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; diff --git a/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts index cf016a44280..cd73a5cd95a 100644 --- a/src/vs/platform/update/electron-main/updateService.darwin.ts +++ b/src/vs/platform/update/electron-main/updateService.darwin.ts @@ -28,14 +28,14 @@ export class DarwinUpdateService extends AbstractUpdateService { @memoize private get onRawUpdateDownloaded(): Event { return Event.fromNodeEventEmitter(electron.autoUpdater, 'update-downloaded', (_, releaseNotes, version, date) => ({ releaseNotes, version, productVersion: version, date })); } constructor( - @ILifecycleMainService lifecycleService: ILifecycleMainService, + @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentService, requestService, logService); this.onRawError(this.onError, this, this.disposables); this.onRawUpdateAvailable(this.onUpdateAvailable, this, this.disposables); this.onRawUpdateDownloaded(this.onUpdateDownloaded, this, this.disposables); diff --git a/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts index 7adb7e00bf8..8b59c871d09 100644 --- a/src/vs/platform/update/electron-main/updateService.linux.ts +++ b/src/vs/platform/update/electron-main/updateService.linux.ts @@ -20,14 +20,14 @@ export class LinuxUpdateService extends AbstractUpdateService { _serviceBrand: undefined; constructor( - @ILifecycleMainService lifecycleService: ILifecycleMainService, + @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, @IRequestService requestService: IRequestService, @ILogService logService: ILogService ) { - super(lifecycleService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentService, requestService, logService); } protected buildUpdateFeedUrl(quality: string): string { diff --git a/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts index 36db202ff33..75d7c1e187e 100644 --- a/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -35,7 +35,7 @@ abstract class AbstractUpdateService2 implements IUpdateService { } constructor( - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IEnvironmentService environmentService: IEnvironmentService, @ILogService protected logService: ILogService, ) { @@ -106,7 +106,7 @@ abstract class AbstractUpdateService2 implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); - this.lifecycleService.quit(true /* from update */).then(vetod => { + this.lifecycleMainService.quit(true /* from update */).then(vetod => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; @@ -139,12 +139,12 @@ export class SnapUpdateService extends AbstractUpdateService2 { constructor( private snap: string, private snapRevision: string, - @ILifecycleMainService lifecycleService: ILifecycleMainService, + @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IEnvironmentService environmentService: IEnvironmentService, @ILogService logService: ILogService, @ITelemetryService private readonly telemetryService: ITelemetryService ) { - super(lifecycleService, environmentService, logService); + super(lifecycleMainService, environmentService, logService); const watcher = watch(path.dirname(this.snap)); const onChange = Event.fromNodeEventEmitter(watcher, 'change', (_, fileName: string) => fileName); @@ -152,7 +152,7 @@ export class SnapUpdateService extends AbstractUpdateService2 { const onDebouncedCurrentChange = Event.debounce(onCurrentChange, (_, e) => e, 2000); const listener = onDebouncedCurrentChange(this.checkForUpdates, this); - lifecycleService.onWillShutdown(() => { + lifecycleMainService.onWillShutdown(() => { listener.dispose(); watcher.close(); }); diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 7395de466da..c053fda3904 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -60,7 +60,7 @@ export class Win32UpdateService extends AbstractUpdateService { } constructor( - @ILifecycleMainService lifecycleService: ILifecycleMainService, + @ILifecycleMainService lifecycleMainService: ILifecycleMainService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IEnvironmentService environmentService: IEnvironmentService, @@ -68,7 +68,7 @@ export class Win32UpdateService extends AbstractUpdateService { @ILogService logService: ILogService, @IFileService private readonly fileService: IFileService ) { - super(lifecycleService, configurationService, environmentService, requestService, logService); + super(lifecycleMainService, configurationService, environmentService, requestService, logService); if (getUpdateType() === UpdateType.Setup) { /* __GDPR__ diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index 6edd504f66c..f8db65d4e1e 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -28,7 +28,7 @@ export class ElectronURLListener { constructor( initial: string | string[], @IURLService private readonly urlService: IURLService, - @IWindowsMainService windowsService: IWindowsMainService + @IWindowsMainService windowsMainService: IWindowsMainService ) { const globalBuffer = ((global).getOpenUrls() || []) as string[]; const rawBuffer = [ @@ -58,14 +58,14 @@ export class ElectronURLListener { const onOpenUrl = Event.filter(Event.map(onOpenElectronUrl, uriFromRawUrl), uri => !!uri); onOpenUrl(this.urlService.open, this.urlService, this.disposables); - const isWindowReady = windowsService.getWindows() + const isWindowReady = windowsMainService.getWindows() .filter(w => w.isReady) .length > 0; if (isWindowReady) { flush(); } else { - Event.once(windowsService.onWindowReady)(flush); + Event.once(windowsMainService.onWindowReady)(flush); } } diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 740891b52f9..4d219fc827b 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -38,15 +38,15 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)) ); - readonly onRecentlyOpenedChange: Event = this.historyService.onRecentlyOpenedChange; + readonly onRecentlyOpenedChange: Event = this.historyMainService.onRecentlyOpenedChange; constructor( private sharedProcess: ISharedProcess, @IWindowsMainService private readonly windowsMainService: IWindowsMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IURLService urlService: IURLService, - @ILifecycleMainService private readonly lifecycleService: ILifecycleMainService, - @IHistoryMainService private readonly historyService: IHistoryMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, + @IHistoryMainService private readonly historyMainService: IHistoryMainService, @ILogService private readonly logService: ILogService ) { super(); @@ -157,25 +157,25 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH async addRecentlyOpened(recents: IRecent[]): Promise { this.logService.trace('windowsService#addRecentlyOpened'); - this.historyService.addRecentlyOpened(recents); + this.historyMainService.addRecentlyOpened(recents); } async removeFromRecentlyOpened(paths: URI[]): Promise { this.logService.trace('windowsService#removeFromRecentlyOpened'); - this.historyService.removeFromRecentlyOpened(paths); + this.historyMainService.removeFromRecentlyOpened(paths); } async clearRecentlyOpened(): Promise { this.logService.trace('windowsService#clearRecentlyOpened'); - this.historyService.clearRecentlyOpened(); + this.historyMainService.clearRecentlyOpened(); } async getRecentlyOpened(windowId: number): Promise { this.logService.trace('windowsService#getRecentlyOpened', windowId); - return this.withWindow(windowId, codeWindow => this.historyService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpenOrCreate), () => this.historyService.getRecentlyOpened())!; + return this.withWindow(windowId, codeWindow => this.historyMainService.getRecentlyOpened(codeWindow.config.workspace, codeWindow.config.folderUri, codeWindow.config.filesToOpenOrCreate), () => this.historyMainService.getRecentlyOpened())!; } async newWindowTab(): Promise { @@ -370,7 +370,7 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH async relaunch(options: { addArgs?: string[], removeArgs?: string[] }): Promise { this.logService.trace('windowsService#relaunch'); - this.lifecycleService.relaunch(options); + this.lifecycleMainService.relaunch(options); } async whenSharedProcessReady(): Promise { From a62c6ee148f724e64b280359040c6c274bec150d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 Sep 2019 18:34:57 +0200 Subject: [PATCH 46/82] debt - add openExtensionDevelopmentHostWindow into IExtensionHostDebugService --- .../debug/common/extensionHostDebug.ts | 16 +++--- .../debug/common/extensionHostDebugIpc.ts | 10 +++- .../workbench/browser/web.simpleservices.ts | 43 --------------- .../contrib/debug/browser/debugSession.ts | 7 +-- .../browser/extensionHostDebugService.ts | 52 ++++++++++++++++++- .../contrib/debug/browser/rawDebugSession.ts | 6 +-- .../extensionHostDebugService.ts | 13 ++++- 7 files changed, 87 insertions(+), 60 deletions(-) diff --git a/src/vs/platform/debug/common/extensionHostDebug.ts b/src/vs/platform/debug/common/extensionHostDebug.ts index 3386e62b25d..3ccb12051b7 100644 --- a/src/vs/platform/debug/common/extensionHostDebug.ts +++ b/src/vs/platform/debug/common/extensionHostDebug.ts @@ -6,6 +6,8 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { IRemoteConsoleLog } from 'vs/base/common/console'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; +import { IProcessEnvironment } from 'vs/base/common/platform'; export const IExtensionHostDebugService = createDecorator('extensionHostDebugService'); @@ -37,17 +39,19 @@ export interface IExtensionHostDebugService { _serviceBrand: undefined; reload(sessionId: string): void; - onReload: Event; + readonly onReload: Event; close(sessionId: string): void; - onClose: Event; + readonly onClose: Event; attachSession(sessionId: string, port: number, subId?: string): void; - onAttachSession: Event; + readonly onAttachSession: Event; logToSession(sessionId: string, log: IRemoteConsoleLog): void; - onLogToSession: Event; + readonly onLogToSession: Event; terminateSession(sessionId: string, subId?: string): void; - onTerminateSession: Event; -} \ No newline at end of file + readonly onTerminateSession: Event; + + openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; +} diff --git a/src/vs/platform/debug/common/extensionHostDebugIpc.ts b/src/vs/platform/debug/common/extensionHostDebugIpc.ts index 3511be94950..555d90bfde0 100644 --- a/src/vs/platform/debug/common/extensionHostDebugIpc.ts +++ b/src/vs/platform/debug/common/extensionHostDebugIpc.ts @@ -8,6 +8,8 @@ import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSes import { Event, Emitter } from 'vs/base/common/event'; import { IRemoteConsoleLog } from 'vs/base/common/console'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; +import { IProcessEnvironment } from 'vs/base/common/platform'; export class ExtensionHostDebugBroadcastChannel implements IServerChannel { @@ -99,4 +101,10 @@ export class ExtensionHostDebugChannelClient extends Disposable implements IExte get onTerminateSession(): Event { return this.channel.listen('terminate'); } -} \ No newline at end of file + + openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { + // TODO@Isidor + //return this.channel.call('openExtensionDevelopmentHostWindow', [args, env]); + return Promise.resolve(); + } +} diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 87a1fee80e8..fdc94ca35b0 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -454,49 +454,6 @@ export class SimpleWindowsService implements IWindowsService { } openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { - - // we pass the "ParsedArgs" as query parameters of the URL - - let newAddress = `${document.location.origin}/?`; - let gotFolder = false; - - const addQueryParameter = (key: string, value: string) => { - const lastChar = newAddress.charAt(newAddress.length - 1); - if (lastChar !== '?' && lastChar !== '&') { - newAddress += '&'; - } - newAddress += `${key}=${encodeURIComponent(value)}`; - }; - - const f = args['folder-uri']; - if (f) { - const u = URI.parse(f[0]); - gotFolder = true; - addQueryParameter('folder', u.path); - } - if (!gotFolder) { - // request empty window - addQueryParameter('ew', 'true'); - } - - const ep = args['extensionDevelopmentPath']; - if (ep) { - let u = ep[0]; - addQueryParameter('edp', u); - } - - const di = args['debugId']; - if (di) { - addQueryParameter('di', di); - } - - const ibe = args['inspect-brk-extensions']; - if (ibe) { - addQueryParameter('ibe', ibe); - } - - window.open(newAddress); - return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 92c18c46873..0f53246d206 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -22,7 +22,8 @@ import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspac import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; import { generateUuid } from 'vs/base/common/uuid'; -import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { Range } from 'vs/editor/common/core/range'; @@ -74,7 +75,7 @@ export class DebugSession implements IDebugSession { @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @INotificationService private readonly notificationService: INotificationService, @IProductService private readonly productService: IProductService, - @IWindowsService private readonly windowsService: IWindowsService, + @IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService, @IOpenerService private readonly openerService: IOpenerService ) { this.id = generateUuid(); @@ -186,7 +187,7 @@ export class DebugSession implements IDebugSession { return dbgr.createDebugAdapter(this).then(debugAdapter => { - this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService, this.openerService); + this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService); return this.raw.start().then(() => { diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index 49b8815ca93..af19c1bbe2e 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -5,7 +5,7 @@ import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; @@ -13,8 +13,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; -class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient { +class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService { constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, @@ -45,6 +47,52 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient { } })); } + + openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { + // we pass the "ParsedArgs" as query parameters of the URL + + let newAddress = `${document.location.origin}/?`; + let gotFolder = false; + + const addQueryParameter = (key: string, value: string) => { + const lastChar = newAddress.charAt(newAddress.length - 1); + if (lastChar !== '?' && lastChar !== '&') { + newAddress += '&'; + } + newAddress += `${key}=${encodeURIComponent(value)}`; + }; + + const f = args['folder-uri']; + if (f) { + const u = URI.parse(f[0]); + gotFolder = true; + addQueryParameter('folder', u.path); + } + if (!gotFolder) { + // request empty window + addQueryParameter('ew', 'true'); + } + + const ep = args['extensionDevelopmentPath']; + if (ep) { + let u = ep[0]; + addQueryParameter('edp', u); + } + + const di = args['debugId']; + if (di) { + addQueryParameter('di', di); + } + + const ibe = args['inspect-brk-extensions']; + if (ibe) { + addQueryParameter('ibe', ibe); + } + + window.open(newAddress); + + return Promise.resolve(); + } } registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService); diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 53a10ed04c5..45ffb5776a8 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -13,7 +13,7 @@ import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { URI } from 'vs/base/common/uri'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { env as processEnv } from 'vs/base/common/process'; @@ -79,7 +79,7 @@ export class RawDebugSession implements IDisposable { dbgr: IDebugger, private readonly telemetryService: ITelemetryService, public readonly customTelemetryService: ITelemetryService | undefined, - private readonly windowsService: IWindowsService, + private readonly extensionHostDebugService: IExtensionHostDebugService, private readonly openerService: IOpenerService ) { @@ -632,7 +632,7 @@ export class RawDebugSession implements IDisposable { Object.keys(env).filter(k => env[k] === null).forEach(key => delete env[key]); } - return this.windowsService.openExtensionDevelopmentHostWindow(args, env); + return this.extensionHostDebugService.openExtensionDevelopmentHostWindow(args, env); } private send(command: string, args: any, token?: CancellationToken, timeout?: number): Promise { diff --git a/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts index e292a9ecd31..dad63fd4fb0 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/extensionHostDebugService.ts @@ -7,13 +7,22 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient { constructor( - @IMainProcessService readonly windowService: IMainProcessService, + @IMainProcessService readonly mainProcessService: IMainProcessService, + @IWindowsService private readonly windowsService: IWindowsService ) { - super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); + super(mainProcessService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); + } + + openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { + // TODO@Isidor use debug IPC channel + return this.windowsService.openExtensionDevelopmentHostWindow(args, env); } } From b920133a68555c0a2ea3e446c2c4bd2e48a015f4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 19:09:35 +0200 Subject: [PATCH 47/82] read and write user data using sync store endpoint --- .../common/userDataSyncStoreService.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index e5da8ba57ca..5bd7b3a859a 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -7,6 +7,10 @@ import { Disposable, } from 'vs/base/common/lifecycle'; import { IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { IProductService } from 'vs/platform/product/common/productService'; import { Emitter, Event } from 'vs/base/common/event'; +import { IRequestService, asJson, asText } from 'vs/platform/request/common/request'; +import { URI } from 'vs/base/common/uri'; +import { joinPath } from 'vs/base/common/resources'; +import { CancellationToken } from 'vs/base/common/cancellation'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -21,6 +25,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn constructor( @IProductService private readonly productService: IProductService, + @IRequestService private readonly requestService: IRequestService, ) { super(); } @@ -35,14 +40,23 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn if (!this.enabled) { return Promise.reject(new Error('No settings sync store url configured.')); } - return null; + const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); + const context = await this.requestService.request({ type: 'GET', url }, CancellationToken.None); + return asJson(context); } async write(key: string, content: string, ref: string | null): Promise { if (!this.enabled) { return Promise.reject(new Error('No settings sync store url configured.')); } - return ''; + const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); + const data = JSON.stringify({ content, ref }); + const context = await this.requestService.request({ type: 'POST', url, data }, CancellationToken.None); + const newRef = await asText(context); + if (!newRef) { + throw new Error('Server did not return the ref'); + } + return newRef; } } From 86baf839044cd6a886716eb0924bee6d23592f50 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 10:52:21 -0700 Subject: [PATCH 48/82] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1fc6e8141ae..a03e9dd1f40 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.39.0", - "distro": "e1ddf4bc0450761d824c22ed1b7d24888f51bac9", + "distro": "8ec29a9878d2ca77f73efc02f382f177d200fbb9", "author": { "name": "Microsoft Corporation" }, From 927f8d87a8191a49d9d838d95655aacf0c499ba0 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 17 Sep 2019 23:37:53 +0200 Subject: [PATCH 49/82] Move user data sync to shared process --- .../sharedProcess/sharedProcessMain.ts | 21 ++++- .../environment/common/environment.ts | 1 + .../environment/node/environmentService.ts | 3 + .../userDataSync/common/settingsSync.ts | 25 +++--- .../userDataSync/common/settingsSyncIpc.ts | 37 ++++++++ .../userDataSync/common/userDataSync.ts | 13 ++- .../userDataSync/common/userDataSyncIpc.ts | 29 +++++++ .../common/userDataSyncService.ts | 84 +++++++++++++------ .../browser/media/sync-push-dark.svg | 0 .../browser/media/sync-push-light.svg | 0 .../browser/userDataSync.contribution.ts} | 56 ++----------- .../userDataSync.contribution.ts | 24 ++++++ .../environment/browser/environmentService.ts | 2 + .../common/settingsMergeService.ts | 0 .../electron-browser/userDataSyncService.ts | 49 +++++++++++ src/vs/workbench/workbench.common.main.ts | 11 +-- src/vs/workbench/workbench.desktop.main.ts | 4 + src/vs/workbench/workbench.web.main.ts | 5 ++ 18 files changed, 264 insertions(+), 100 deletions(-) create mode 100644 src/vs/platform/userDataSync/common/settingsSyncIpc.ts create mode 100644 src/vs/platform/userDataSync/common/userDataSyncIpc.ts rename src/vs/workbench/contrib/{userData => userDataSync}/browser/media/sync-push-dark.svg (100%) rename src/vs/workbench/contrib/{userData => userDataSync}/browser/media/sync-push-light.svg (100%) rename src/vs/workbench/contrib/{userData/browser/userData.contribution.ts => userDataSync/browser/userDataSync.contribution.ts} (81%) create mode 100644 src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts rename src/vs/workbench/services/{userData => userDataSync}/common/settingsMergeService.ts (100%) create mode 100644 src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 56f7ed460f3..68b3606086f 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -26,7 +26,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows'; import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -51,6 +51,11 @@ import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; +import { IUserDataSyncService, IUserDataSyncStoreService, ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncService, UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService'; +import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; +import { SettingsMergeChannelClient } from 'vs/platform/userDataSync/common/settingsSyncIpc'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -117,6 +122,11 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const windowsService = new WindowsService(mainProcessService); services.set(IWindowsService, windowsService); + const activeWindowManager = new ActiveWindowManager(windowsService); + const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); + const settingsMergeChannel = server.getChannel('settingsMerge', activeWindowRouter); + services.set(ISettingsMergeService, new SettingsMergeChannelClient(settingsMergeChannel)); + // Files const fileService = new FileService(logService); services.set(IFileService, fileService); @@ -163,6 +173,8 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); + services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService)); + services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); const instantiationService2 = instantiationService.createChild(services); @@ -180,6 +192,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService); server.registerChannel('diagnostics', diagnosticsChannel); + const userDataSyncService = accessor.get(IUserDataSyncService); + const userDataSyncChannel = new UserDataSyncChannel(userDataSyncService); + server.registerChannel('userDataSync', userDataSyncChannel); + // clean up deprecated extensions (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(); // update localizations cache @@ -189,7 +205,8 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat instantiationService2.createInstance(NodeCachedDataCleaner), instantiationService2.createInstance(LanguagePackCachedDataCleaner), instantiationService2.createInstance(StorageDataCleaner), - instantiationService2.createInstance(LogsDataCleaner) + instantiationService2.createInstance(LogsDataCleaner), + instantiationService2.createInstance(UserDataAutoSync) )); disposables.add(extensionManagementService as ExtensionManagementService); }); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 31cca78bd31..fdd4e9997a0 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -114,6 +114,7 @@ export interface IEnvironmentService { // user roaming data userRoamingDataHome: URI; settingsResource: URI; + settingsSyncPreviewResource: URI; keybindingsResource: URI; keyboardLayoutResource: URI; localeResource: URI; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 36f275fbaf5..0df72e178ad 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -116,6 +116,9 @@ export class EnvironmentService implements IEnvironmentService { @memoize get settingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'settings.json'); } + @memoize + get settingsSyncPreviewResource(): URI { return resources.joinPath(this.userRoamingDataHome, '.settings.json'); } + @memoize get machineSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'Machine')); } diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index 9ebf057bd4f..fb001ed8ef0 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -6,7 +6,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_CONFLICTS_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; import { localize } from 'vs/nls'; @@ -14,7 +14,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; import { CancelablePromise, createCancelablePromise, ThrottledDelayer } from 'vs/base/common/async'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { URI } from 'vs/base/common/uri'; interface ISyncPreviewResult { readonly fileContent: IFileContent | null; @@ -40,8 +39,6 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { private _onDidChangeLocal: Emitter = this._register(new Emitter()); readonly onDidChangeLocal: Event = this._onDidChangeLocal.event; - readonly conflicts: URI = SETTINGS_CONFLICTS_RESOURCE; - constructor( @IFileService private readonly fileService: IFileService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -77,7 +74,11 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } } - async sync(): Promise { + async sync(_continue?: boolean): Promise { + + if (_continue) { + return this.continueSync(); + } if (this.status !== SyncStatus.Idle) { return false; @@ -110,7 +111,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } } - async continueSync(): Promise { + private async continueSync(): Promise { if (this.status !== SyncStatus.HasConflicts) { return false; } @@ -123,8 +124,8 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { return; } - if (await this.fileService.exists(this.conflicts)) { - const settingsPreivew = await this.fileService.readFile(this.conflicts); + if (await this.fileService.exists(this.environmentService.settingsSyncPreviewResource)) { + const settingsPreivew = await this.fileService.readFile(this.environmentService.settingsSyncPreviewResource); const content = settingsPreivew.value.toString(); if (this.hasErrors(content)) { return Promise.reject(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again.")); @@ -143,7 +144,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } // Delete the preview - await this.fileService.del(this.conflicts); + await this.fileService.del(this.environmentService.settingsSyncPreviewResource); } this.syncPreviewResultPromise = null; @@ -175,7 +176,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { if (fileContent && !remoteUserData) { this.logService.trace('Settings Sync: Remote contents does not exist. So sync with settings file.'); hasRemoteChanged = true; - await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(fileContent.value.toString())); + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(fileContent.value.toString())); return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } @@ -183,7 +184,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { if (remoteUserData && !fileContent) { this.logService.trace('Settings Sync: Settings file does not exist. So sync with remote contents'); hasLocalChanged = true; - await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(remoteUserData.content)); + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(remoteUserData.content)); return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } @@ -202,7 +203,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { if (hasLocalChanged || hasRemoteChanged) { // Sync only if there are changes hasConflicts = this.hasErrors(mergeContent); - await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(mergeContent)); + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(mergeContent)); return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } } diff --git a/src/vs/platform/userDataSync/common/settingsSyncIpc.ts b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts new file mode 100644 index 00000000000..a8e4cac6ac5 --- /dev/null +++ b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync'; + +export class SettingsMergeChannel implements IServerChannel { + + constructor(private readonly service: ISettingsMergeService) { } + + listen(_: unknown, event: string): Event { + throw new Error(`Event not found: ${event}`); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'merge': return this.service.merge(args[0], args[1], args[2]); + } + throw new Error('Invalid call'); + } +} + +export class SettingsMergeChannelClient implements ISettingsMergeService { + + _serviceBrand: undefined; + + constructor(private readonly channel: IChannel) { + } + + merge(localContent: string, remoteContent: string, baseContent: string | null): Promise { + return this.channel.call('merge', [localContent, remoteContent, baseContent]); + } + +} diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index f54e3f4e62f..a6bf31b22ac 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -5,7 +5,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; -import { URI } from 'vs/base/common/uri'; export interface IUserData { ref: string; @@ -41,6 +40,10 @@ export interface IUserDataSyncStoreService { write(key: string, content: string, ref: string | null): Promise; } +export enum SyncSource { + Settings = 1, + Extensions +} export enum SyncStatus { Uninitialized = 'uninitialized', @@ -49,24 +52,20 @@ export enum SyncStatus { HasConflicts = 'hasConflicts', } -export const USER_DATA_PREVIEW_SCHEME = 'vscode-userdata-preview'; -export const SETTINGS_CONFLICTS_RESOURCE = URI.file('Settings-Preview').with({ scheme: USER_DATA_PREVIEW_SCHEME }); - export interface ISynchroniser { - readonly conflicts: URI | null; readonly status: SyncStatus; readonly onDidChangeStatus: Event; readonly onDidChangeLocal: Event; - sync(): Promise; - continueSync(): Promise; + sync(_continue?: boolean): Promise; } export const IUserDataSyncService = createDecorator('IUserDataSyncService'); export interface IUserDataSyncService extends ISynchroniser { _serviceBrand: any; + readonly conflictsSource: SyncSource | null; } export const ISettingsMergeService = createDecorator('ISettingsMergeService'); diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts new file mode 100644 index 00000000000..20b40039141 --- /dev/null +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Event } from 'vs/base/common/event'; +import { IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; + +export class UserDataSyncChannel implements IServerChannel { + + constructor(private readonly service: IUserDataSyncService) { } + + listen(_: unknown, event: string): Event { + switch (event) { + case 'onDidChangeStatus': return this.service.onDidChangeStatus; + case 'onDidChangeLocal': return this.service.onDidChangeLocal; + } + throw new Error(`Event not found: ${event}`); + } + + call(context: any, command: string, args?: any): Promise { + switch (command) { + case 'sync': return this.service.sync(args[0]); + case 'getConflictsSource': return Promise.resolve(this.service.conflictsSource); + } + throw new Error('Invalid call'); + } +} diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 471a2e644d7..17988d1184a 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, ISynchroniser, IUserDataSyncStoreService, SyncSource } from 'vs/platform/userDataSync/common/userDataSync'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync'; import { Emitter, Event } from 'vs/base/common/event'; -import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { timeout } from 'vs/base/common/async'; export class UserDataSyncService extends Disposable implements IUserDataSyncService { @@ -18,11 +19,14 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private _status: SyncStatus = SyncStatus.Uninitialized; get status(): SyncStatus { return this._status; } - private _onDidChangStatus: Emitter = this._register(new Emitter()); - readonly onDidChangeStatus: Event = this._onDidChangStatus.event; + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; readonly onDidChangeLocal: Event; + private _conflictsSource: SyncSource | null = null; + get conflictsSource(): SyncSource | null { return this._conflictsSource; } + constructor( @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -36,43 +40,27 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal)); } - get conflicts(): URI | null { - const synchroniser = this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts)[0]; - return synchroniser ? synchroniser.conflicts : null; - } - - async sync(): Promise { + async sync(_continue?: boolean): Promise { if (!this.userDataSyncStoreService.enabled) { throw new Error('Not enabled'); } for (const synchroniser of this.synchronisers) { - if (!await synchroniser.sync()) { + if (!await synchroniser.sync(_continue)) { return false; } } return true; } - async continueSync(): Promise { - if (!this.userDataSyncStoreService.enabled) { - throw new Error('Not enabled'); - } - for (const synchroniser of this.synchronisers) { - if (await synchroniser.continueSync()) { - return true; - } - } - return false; - } - private updateStatus(): void { + this._conflictsSource = this.computeConflictsSource(); this.setStatus(this.computeStatus()); } private setStatus(status: SyncStatus): void { if (this._status !== status) { this._status = status; - this._onDidChangStatus.fire(status); + this._onDidChangeStatus.fire(status); } } @@ -89,4 +77,52 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ return SyncStatus.Idle; } + private computeConflictsSource(): SyncSource | null { + const source = this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts)[0]; + if (source) { + if (source instanceof SettingsSynchroniser) { + return SyncSource.Settings; + } + } + return null; + } + +} + +export class UserDataAutoSync extends Disposable { + + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService, + @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, + @IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService, + ) { + super(); + if (userDataSyncStoreService.enabled) { + this.sync(true); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync'))(() => this.sync(true))); + + // Sync immediately if there is a local change. + this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false))); + } + } + + private async sync(loop: boolean): Promise { + if (this.isSyncEnabled()) { + try { + await this.userDataSyncService.sync(); + } catch (e) { + // Ignore errors + } + if (loop) { + await timeout(1000 * 5); // Loop sync for every 5s. + this.sync(loop); + } + } + } + + private isSyncEnabled(): boolean { + const { user: userLocal } = this.configurationService.inspect('userConfiguration.enableSync'); + return userLocal === undefined || userLocal; + } + } diff --git a/src/vs/workbench/contrib/userData/browser/media/sync-push-dark.svg b/src/vs/workbench/contrib/userDataSync/browser/media/sync-push-dark.svg similarity index 100% rename from src/vs/workbench/contrib/userData/browser/media/sync-push-dark.svg rename to src/vs/workbench/contrib/userDataSync/browser/media/sync-push-dark.svg diff --git a/src/vs/workbench/contrib/userData/browser/media/sync-push-light.svg b/src/vs/workbench/contrib/userDataSync/browser/media/sync-push-light.svg similarity index 100% rename from src/vs/workbench/contrib/userData/browser/media/sync-push-light.svg rename to src/vs/workbench/contrib/userDataSync/browser/media/sync-push-light.svg diff --git a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts similarity index 81% rename from src/vs/workbench/contrib/userData/browser/userData.contribution.ts rename to src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index ed95a7e2571..4edc5aa34e4 100644 --- a/src/vs/workbench/contrib/userData/browser/userData.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IUserDataSyncService, SyncStatus, USER_DATA_PREVIEW_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncService, SyncStatus, SyncSource } from 'vs/platform/userDataSync/common/userDataSync'; import { localize } from 'vs/nls'; import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -16,7 +16,6 @@ import { MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/acti import { RawContextKey, IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity'; import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; -import { timeout } from 'vs/base/common/async'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { URI } from 'vs/base/common/uri'; import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; @@ -25,8 +24,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IFileService } from 'vs/platform/files/common/files'; -import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { isEqual } from 'vs/base/common/resources'; const CONTEXT_SYNC_STATE = new RawContextKey('syncStatus', SyncStatus.Uninitialized); @@ -46,39 +45,6 @@ Registry.as(ConfigurationExtensions.Configuration) } }); -class UserDataSyncContribution extends Disposable implements IWorkbenchContribution { - - constructor( - @IFileService fileService: IFileService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, - ) { - super(); - this._register(fileService.registerProvider(USER_DATA_PREVIEW_SCHEME, new InMemoryFileSystemProvider())); - this.sync(true); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('userConfiguration.enableSync') && this.configurationService.getValue('userConfiguration.enableSync')) - (() => this.sync(true))); - - // Sync immediately if there is a local change. - this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false))); - } - - private async sync(loop: boolean): Promise { - if (this.configurationService.getValue('userConfiguration.enableSync')) { - try { - await this.userDataSyncService.sync(); - } catch (e) { - // Ignore errors - } - if (loop) { - await timeout(1000 * 5); // Loop sync for every 5s. - this.sync(loop); - } - } - } - -} - const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-light.svg`)); const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-dark.svg`)); class SyncActionsContribution extends Disposable implements IWorkbenchContribution { @@ -96,6 +62,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi @IEditorService private readonly editorService: IEditorService, @ITextFileService private readonly textFileService: ITextFileService, @IHistoryService private readonly historyService: IHistoryService, + @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(); this.syncEnablementContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); @@ -142,17 +109,14 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi private async continueSync(): Promise { // Get the preview editor - const editorInput = this.editorService.editors.filter(input => { - const resource = input.getResource(); - return resource && resource.scheme === USER_DATA_PREVIEW_SCHEME; - })[0]; + const editorInput = this.editorService.editors.filter(input => isEqual(input.getResource(), this.workbenchEnvironmentService.settingsSyncPreviewResource))[0]; // Save the preview if (editorInput && editorInput.isDirty()) { await this.textFileService.save(editorInput.getResource()!); } try { // Continue Sync - await this.userDataSyncService.continueSync(); + await this.userDataSyncService.sync(true); } catch (error) { this.notificationService.error(error); return; @@ -164,10 +128,9 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi } private async handleConflicts(): Promise { - const resource = this.userDataSyncService.conflicts; - if (resource) { + if (this.userDataSyncService.conflictsSource === SyncSource.Settings ) { const resourceInput = { - resource, + resource: this.workbenchEnvironmentService.settingsSyncPreviewResource, options: { preserveFocus: false, pinned: false, @@ -237,11 +200,10 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi }, group: 'navigation', order: 1, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Scheme.isEqualTo(USER_DATA_PREVIEW_SCHEME)), + when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts), ResourceContextKey.Resource.isEqualTo(this.workbenchEnvironmentService.settingsSyncPreviewResource.toString())), }); } } const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(SyncActionsContribution, LifecyclePhase.Starting); -workbenchRegistry.registerWorkbenchContribution(UserDataSyncContribution, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts new file mode 100644 index 00000000000..2b8fb68f933 --- /dev/null +++ b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { SettingsMergeChannel } from 'vs/platform/userDataSync/common/settingsSyncIpc'; + +class UserDataSyncServicesContribution implements IWorkbenchContribution { + + constructor( + @ISettingsMergeService settingsMergeService: ISettingsMergeService, + @ISharedProcessService sharedProcessService: ISharedProcessService, + ) { + sharedProcessService.registerChannel('settingsMerge', new SettingsMergeChannel(settingsMergeService)); + } +} + +const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(UserDataSyncServicesContribution, LifecyclePhase.Starting); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index a68e9cef955..6ccc6ffcbbf 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -84,6 +84,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment this.configuration.machineId = generateUuid(); this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData }); this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json'); + this.settingsSyncPreviewResource = joinPath(this.userRoamingDataHome, '.settings.json'); this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json'); this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json'); @@ -141,6 +142,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment appSettingsHome: URI; userRoamingDataHome: URI; settingsResource: URI; + settingsSyncPreviewResource: URI; keybindingsResource: URI; keyboardLayoutResource: URI; localeResource: URI; diff --git a/src/vs/workbench/services/userData/common/settingsMergeService.ts b/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts similarity index 100% rename from src/vs/workbench/services/userData/common/settingsMergeService.ts rename to src/vs/workbench/services/userDataSync/common/settingsMergeService.ts diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts new file mode 100644 index 00000000000..7a1fe399ff1 --- /dev/null +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SyncStatus, SyncSource, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class UserDataSyncService extends Disposable implements IUserDataSyncService { + + _serviceBrand: undefined; + + private readonly channel: IChannel; + + private _status: SyncStatus = SyncStatus.Uninitialized; + get status(): SyncStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } + + private _conflictsSource: SyncSource | null = null; + get conflictsSource(): SyncSource | null { return this._conflictsSource; } + + constructor( + @ISharedProcessService sharedProcessService: ISharedProcessService + ) { + super(); + this.channel = sharedProcessService.getChannel('userDataSync'); + this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); + } + + sync(_continue?: boolean): Promise { + return this.channel.call('sync', [_continue]); + } + + private async updateStatus(status: SyncStatus): Promise { + this._conflictsSource = await this.channel.call('getConflictsSource'); + this._status = status; + this._onDidChangeStatus.fire(status); + } + +} + +registerSingleton(IUserDataSyncService, UserDataSyncService); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 73fc63f220c..4526dbac1b2 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -79,7 +79,7 @@ import 'vs/workbench/services/label/common/labelService'; import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; -import 'vs/workbench/services/userData/common/settingsMergeService'; +import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/workspace/browser/workspaceEditingService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -106,9 +106,6 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; -import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; -import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(IContextViewService, ContextViewService, true); @@ -122,8 +119,6 @@ registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationSe registerSingleton(IMenuService, MenuService, true); registerSingleton(IDownloadService, DownloadService, true); registerSingleton(IOpenerService, OpenerService, true); -registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); -registerSingleton(IUserDataSyncService, UserDataSyncService); //#endregion @@ -259,7 +254,7 @@ import 'vs/workbench/contrib/experiments/browser/experiments.contribution'; // Send a Smile import 'vs/workbench/contrib/feedback/browser/feedback.contribution'; -// User Data -import 'vs/workbench/contrib/userData/browser/userData.contribution'; +// User Data Sync +import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution'; //#endregion diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index f22592cb8fe..e864ab64498 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -49,6 +49,7 @@ import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/credentials/node/credentialsService'; import 'vs/workbench/services/url/electron-browser/urlService'; import 'vs/workbench/services/workspace/electron-browser/workspacesService'; +import 'vs/workbench/services/userDataSync/electron-browser/userDataSyncService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -137,4 +138,7 @@ import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; // Tasks import 'vs/workbench/contrib/tasks/electron-browser/taskService'; +// User Data Sync +import 'vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution'; + //#endregion diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index dc8eb1bb5e6..65078676b4e 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -61,6 +61,9 @@ import { BackupFileService } from 'vs/workbench/services/backup/common/backupFil import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; +import { IUserDataSyncStoreService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService'; registerSingleton(IRequestService, RequestService, true); registerSingleton(IExtensionManagementService, ExtensionManagementService); @@ -70,6 +73,8 @@ registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); registerSingleton(ILifecycleService, BrowserLifecycleService); registerSingleton(IContextMenuService, ContextMenuService); registerSingleton(ITunnelService, NoOpTunnelService, true); +registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService); +registerSingleton(IUserDataSyncService, UserDataSyncService); //#endregion From 073a6efc8042bb495c29258ae2db73297ca8ee2c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 00:03:42 +0200 Subject: [PATCH 50/82] Store last sync data in file --- .../userDataSync/common/settingsSync.ts | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index fb001ed8ef0..8a6ab26adfb 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -5,7 +5,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; import { VSBuffer } from 'vs/base/common/buffer'; import { parse, ParseError } from 'vs/base/common/json'; @@ -14,6 +13,8 @@ import { Emitter, Event } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; import { CancelablePromise, createCancelablePromise, ThrottledDelayer } from 'vs/base/common/async'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { URI } from 'vs/base/common/uri'; +import { joinPath } from 'vs/base/common/resources'; interface ISyncPreviewResult { readonly fileContent: IFileContent | null; @@ -25,7 +26,6 @@ interface ISyncPreviewResult { export class SettingsSynchroniser extends Disposable implements ISynchroniser { - private static LAST_SYNC_SETTINGS_STORAGE_KEY: string = 'LAST_SYNC_SETTINGS_CONTENTS'; private static EXTERNAL_USER_DATA_SETTINGS_KEY: string = 'settings'; private syncPreviewResultPromise: CancelablePromise | null = null; @@ -39,22 +39,24 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { private _onDidChangeLocal: Emitter = this._register(new Emitter()); readonly onDidChangeLocal: Event = this._onDidChangeLocal.event; + private readonly lastSyncSettingsResource: URI; + constructor( @IFileService private readonly fileService: IFileService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IStorageService private readonly storageService: IStorageService, @IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService, @ISettingsMergeService private readonly settingsMergeService: ISettingsMergeService, @ILogService private readonly logService: ILogService, ) { super(); + this.lastSyncSettingsResource = joinPath(this.environmentService.appSettingsHome, '.lastSyncSettings.json'); this.throttledDelayer = this._register(new ThrottledDelayer(500)); this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.settingsResource))(() => this.throttledDelayer.trigger(() => this.onDidChangeSettings()))); } private async onDidChangeSettings(): Promise { const localFileContent = await this.getLocalFileContent(); - const lastSyncData = this.getLastSyncUserData(); + const lastSyncData = await this.getLastSyncUserData(); if (localFileContent && lastSyncData) { if (localFileContent.value.toString() !== lastSyncData.content) { this._onDidChangeLocal.fire(); @@ -140,7 +142,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { await this.writeToLocal(content, fileContent); } if (remoteUserData) { - this.updateLastSyncValue(remoteUserData); + await this.updateLastSyncValue(remoteUserData); } // Delete the preview @@ -191,7 +193,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { if (fileContent && remoteUserData) { const localContent: string = fileContent.value.toString(); const remoteContent: string = remoteUserData.content; - const lastSyncData = this.getLastSyncUserData(); + const lastSyncData = await this.getLastSyncUserData(); if (!lastSyncData // First time sync || lastSyncData.content !== localContent // Local has moved forwarded || lastSyncData.content !== remoteContent // Remote has moved forwarded @@ -213,22 +215,20 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } - private getLastSyncUserData(): IUserData | null { - const lastSyncStorageContents = this.storageService.get(SettingsSynchroniser.LAST_SYNC_SETTINGS_STORAGE_KEY, StorageScope.GLOBAL, undefined); - if (lastSyncStorageContents) { - return JSON.parse(lastSyncStorageContents); + private async getLastSyncUserData(): Promise { + try { + const content = await this.fileService.readFile(this.lastSyncSettingsResource); + return JSON.parse(content.value.toString()); + } catch (error) { + return null; } - return null; } private async getLocalFileContent(): Promise { try { return await this.fileService.readFile(this.environmentService.settingsResource); } catch (error) { - if (error instanceof FileSystemProviderError && error.code !== FileSystemProviderErrorCode.FileNotFound) { - return null; - } - throw error; + return null; } } @@ -246,12 +246,8 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } } - private updateLastSyncValue(remoteUserData: IUserData): void { - const lastSyncUserData = this.getLastSyncUserData(); - if (lastSyncUserData && lastSyncUserData.ref === remoteUserData.ref) { - return; - } - this.storageService.store(SettingsSynchroniser.LAST_SYNC_SETTINGS_STORAGE_KEY, JSON.stringify(remoteUserData), StorageScope.GLOBAL); + private async updateLastSyncValue(remoteUserData: IUserData): Promise { + await this.fileService.writeFile(this.lastSyncSettingsResource, VSBuffer.fromString(JSON.stringify(remoteUserData))); } } From 8937b39776e1ac0186160cb93c42cddc2c05c743 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 00:03:49 +0200 Subject: [PATCH 51/82] Pass content type header --- .../platform/userDataSync/common/userDataSyncStoreService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 5bd7b3a859a..7f1e4261921 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -11,6 +11,7 @@ import { IRequestService, asJson, asText } from 'vs/platform/request/common/requ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { IStringDictionary } from 'vs/base/common/collections'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -51,7 +52,8 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn } const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); const data = JSON.stringify({ content, ref }); - const context = await this.requestService.request({ type: 'POST', url, data }, CancellationToken.None); + const headers: IStringDictionary = { 'Content-Type': 'application/json' }; + const context = await this.requestService.request({ type: 'POST', url, data, headers }, CancellationToken.None); const newRef = await asText(context); if (!newRef) { throw new Error('Server did not return the ref'); From 6b2da9bc5574dc5c4d26b5bc3f4b25498405ff7b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 00:26:25 +0200 Subject: [PATCH 52/82] Use userRoamingDataHome --- src/vs/platform/userDataSync/common/settingsSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index 8a6ab26adfb..e6ec0ab0145 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -49,7 +49,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { @ILogService private readonly logService: ILogService, ) { super(); - this.lastSyncSettingsResource = joinPath(this.environmentService.appSettingsHome, '.lastSyncSettings.json'); + this.lastSyncSettingsResource = joinPath(this.environmentService.userRoamingDataHome, '.lastSyncSettings.json'); this.throttledDelayer = this._register(new ThrottledDelayer(500)); this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.settingsResource))(() => this.throttledDelayer.trigger(() => this.onDidChangeSettings()))); } From f4766766b47fb942d8b2099b99a4aeb498631d02 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 00:26:48 +0200 Subject: [PATCH 53/82] Auto sync in web --- .../browser/userDataSync.contribution.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index 4edc5aa34e4..f864d7e0176 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -26,6 +26,9 @@ import { Event } from 'vs/base/common/event'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { isEqual } from 'vs/base/common/resources'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { isWeb } from 'vs/base/common/platform'; +import { UserDataAutoSync } from 'vs/platform/userDataSync/common/userDataSyncService'; const CONTEXT_SYNC_STATE = new RawContextKey('syncStatus', SyncStatus.Uninitialized); @@ -45,6 +48,18 @@ Registry.as(ConfigurationExtensions.Configuration) } }); +class UserDataAutoSyncContribution extends Disposable implements IWorkbenchContribution { + + constructor( + @IInstantiationService instantiationService: IInstantiationService + ) { + super(); + if (isWeb) { + instantiationService.createInstance(UserDataAutoSync); + } + } +} + const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-light.svg`)); const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-dark.svg`)); class SyncActionsContribution extends Disposable implements IWorkbenchContribution { @@ -128,7 +143,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi } private async handleConflicts(): Promise { - if (this.userDataSyncService.conflictsSource === SyncSource.Settings ) { + if (this.userDataSyncService.conflictsSource === SyncSource.Settings) { const resourceInput = { resource: this.workbenchEnvironmentService.settingsSyncPreviewResource, options: { @@ -207,3 +222,4 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(SyncActionsContribution, LifecyclePhase.Starting); +workbenchRegistry.registerWorkbenchContribution(UserDataAutoSyncContribution, LifecyclePhase.Restored); From 5fc4fe2266dbb57a83fed24d1f9ff2552ee41202 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 17 Sep 2019 15:25:27 -0700 Subject: [PATCH 54/82] Add resolveExternalUri embedder contribution point --- .../editor/browser/services/openerService.ts | 14 ++++++++-- src/vs/platform/opener/common/opener.ts | 18 ++++++++++--- .../contrib/url/common/externalUriResolver.ts | 26 +++++++++++++++++++ .../contrib/url/common/url.contribution.ts | 7 ++++- src/vs/workbench/workbench.web.api.ts | 5 ++++ 5 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 src/vs/workbench/contrib/url/common/externalUriResolver.ts diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index c42f82fdb26..8a122c18fc5 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -13,7 +13,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IOpener, IOpenerService, IValidator } from 'vs/platform/opener/common/opener'; +import { IOpener, IOpenerService, IValidator, IExternalUriResolver } from 'vs/platform/opener/common/opener'; export class OpenerService extends Disposable implements IOpenerService { @@ -21,6 +21,7 @@ export class OpenerService extends Disposable implements IOpenerService { private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); + private readonly _resolvers = new LinkedList(); constructor( @ICodeEditorService private readonly _editorService: ICodeEditorService, @@ -39,6 +40,11 @@ export class OpenerService extends Disposable implements IOpenerService { return { dispose: remove }; } + registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable { + const remove = this._resolvers.push(resolver); + return { dispose: remove }; + } + async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise { // no scheme ?!? if (!resource.scheme) { @@ -118,7 +124,11 @@ export class OpenerService extends Disposable implements IOpenerService { } } - private _doOpenExternal(resource: URI): Promise { + private async _doOpenExternal(resource: URI): Promise { + for (const resolver of this._resolvers.toArray()) { + resource = await resolver.resolveExternalUri(resource); + } + dom.windowOpenNoOpener(encodeURI(resource.toString(true))); return Promise.resolve(true); diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 8563f3fa2af..0c9a243a952 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -5,7 +5,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; export const IOpenerService = createDecorator('openerService'); @@ -18,6 +18,10 @@ export interface IValidator { shouldOpen(resource: URI): Promise; } +export interface IExternalUriResolver { + resolveExternalUri(resource: URI): Promise; +} + export interface IOpenerService { _serviceBrand: undefined; @@ -29,10 +33,15 @@ export interface IOpenerService { /** * Register a participant that can validate if the URI resource be opened. - * validators are run before openers. + * Validators are run before openers. */ registerValidator(validator: IValidator): IDisposable; + /** + * Register a participant that can resolve an external URI resource to be opened. + */ + registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable; + /** * Opens a resource, like a webaddress, a document uri, or executes command. * @@ -45,7 +54,8 @@ export interface IOpenerService { export const NullOpenerService: IOpenerService = Object.freeze({ _serviceBrand: undefined, - registerOpener() { return { dispose() { } }; }, - registerValidator() { return { dispose() { } }; }, + registerOpener() { return Disposable.None; }, + registerValidator() { return Disposable.None; }, + registerExternalUriResolver() { return Disposable.None; }, open() { return Promise.resolve(false); }, }); diff --git a/src/vs/workbench/contrib/url/common/externalUriResolver.ts b/src/vs/workbench/contrib/url/common/externalUriResolver.ts new file mode 100644 index 00000000000..454d76644b6 --- /dev/null +++ b/src/vs/workbench/contrib/url/common/externalUriResolver.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +export class ExternalUriResolverContribution extends Disposable implements IWorkbenchContribution { + constructor( + @IOpenerService _openerService: IOpenerService, + @IWorkbenchEnvironmentService _workbenchEnvironmentService: IWorkbenchEnvironmentService, + ) { + super(); + + if (_workbenchEnvironmentService.options && _workbenchEnvironmentService.options.resolveExternalUri) { + this._register(_openerService.registerExternalUriResolver({ + resolveExternalUri: async (resource) => { + return _workbenchEnvironmentService.options!.resolveExternalUri!(resource); + } + })); + } + } +} diff --git a/src/vs/workbench/contrib/url/common/url.contribution.ts b/src/vs/workbench/contrib/url/common/url.contribution.ts index f51bd6d3f03..e299262de05 100644 --- a/src/vs/workbench/contrib/url/common/url.contribution.ts +++ b/src/vs/workbench/contrib/url/common/url.contribution.ts @@ -14,9 +14,10 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IURLService } from 'vs/platform/url/common/url'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { ExternalUriResolverContribution } from 'vs/workbench/contrib/url/common/externalUriResolver'; import { configureTrustedDomainSettingsCommand } from 'vs/workbench/contrib/url/common/trustedDomains'; -import { OpenerValidatorContributions } from 'vs/workbench/contrib/url/common/trustedDomainsValidator'; import { TrustedDomainsFileSystemProvider } from 'vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider'; +import { OpenerValidatorContributions } from 'vs/workbench/contrib/url/common/trustedDomainsValidator'; export class OpenUrlAction extends Action { static readonly ID = 'workbench.action.url.openUrl'; @@ -65,3 +66,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi TrustedDomainsFileSystemProvider, LifecyclePhase.Ready ); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( + ExternalUriResolverContribution, + LifecyclePhase.Ready +); diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index cd4351d6016..38bb092333d 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -90,6 +90,11 @@ interface IWorkbenchConstructionOptions { * Experimental: Support for update reporting. */ updateProvider?: IUpdateProvider; + + /** + * Experimental: Resolves an external uri before it is opened. + */ + readonly resolveExternalUri?: (uri: URI) => Promise; } /** From db358b5b02231ca794bdadd1bd1c45942664e514 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 17 Sep 2019 15:31:44 -0700 Subject: [PATCH 55/82] Fixing a mismatch in default config for webviews --- .../environment/browser/environmentService.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index a68e9cef955..346c6c6c81b 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -181,16 +181,17 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment get webviewExternalEndpoint(): string { // TODO: get fallback from product.json - return this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com'; - } - - get webviewResourceRoot(): string { - return `${this.webviewExternalEndpoint}/{{commit}}/vscode-resource{{resource}}` + return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}') .replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); } + get webviewResourceRoot(): string { + return `${this.webviewExternalEndpoint}/vscode-resource{{resource}}`; + } + get webviewCspSource(): string { - return this.options.webviewEndpoint || `https://*.vscode-webview-test.com`; + return this.webviewExternalEndpoint + .replace('{{uuid}}', '*'); } } From 88ff4a7bdd9ad85ac8a44fafecdd9a103a6f8f28 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 17 Sep 2019 15:35:38 -0700 Subject: [PATCH 56/82] Fix #80525 --- src/vs/workbench/contrib/search/browser/searchWidget.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 4a97413453c..254346cc052 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -364,11 +364,12 @@ export class SearchWidget extends Widget { } })); - let controls = document.createElement('div'); + const controls = document.createElement('div'); controls.className = 'controls'; controls.style.display = 'block'; controls.appendChild(this._preserveCase.domNode); replaceBox.appendChild(controls); + this.replaceInput.paddingRight = this._preserveCase.width(); this._register(attachInputBoxStyler(this.replaceInput, this.themeService)); this.onkeydown(this.replaceInput.inputElement, (keyboardEvent) => this.onReplaceInputKeyDown(keyboardEvent)); From c894376361b2b948baeeacc9120ab41aa1d49f6b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 01:11:57 +0200 Subject: [PATCH 57/82] fix settings merging --- .../userDataSync/common/settingsSync.ts | 14 +-- .../userDataSync/common/settingsSyncIpc.ts | 2 +- .../userDataSync/common/userDataSync.ts | 2 +- .../common/settingsMergeService.ts | 110 ++++++++---------- 4 files changed, 57 insertions(+), 71 deletions(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index e6ec0ab0145..f408d51a7c6 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -199,13 +199,13 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { || lastSyncData.content !== remoteContent // Remote has moved forwarded ) { this.logService.trace('Settings Sync: Merging remote contents with settings file.'); - const mergeContent = await this.settingsMergeService.merge(localContent, remoteContent, lastSyncData ? lastSyncData.content : null); - hasLocalChanged = mergeContent !== localContent; - hasRemoteChanged = mergeContent !== remoteContent; - if (hasLocalChanged || hasRemoteChanged) { - // Sync only if there are changes - hasConflicts = this.hasErrors(mergeContent); - await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(mergeContent)); + const result = await this.settingsMergeService.merge(localContent, remoteContent, lastSyncData ? lastSyncData.content : null); + // Sync only if there are changes + if (result.hasChanges) { + hasLocalChanged = result.mergeContent !== localContent; + hasRemoteChanged = result.mergeContent !== remoteContent; + hasConflicts = result.hasConflicts; + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(result.mergeContent)); return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } } diff --git a/src/vs/platform/userDataSync/common/settingsSyncIpc.ts b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts index a8e4cac6ac5..dfee58a6191 100644 --- a/src/vs/platform/userDataSync/common/settingsSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/settingsSyncIpc.ts @@ -30,7 +30,7 @@ export class SettingsMergeChannelClient implements ISettingsMergeService { constructor(private readonly channel: IChannel) { } - merge(localContent: string, remoteContent: string, baseContent: string | null): Promise { + merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { return this.channel.call('merge', [localContent, remoteContent, baseContent]); } diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index a6bf31b22ac..5801cea4ca3 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -74,6 +74,6 @@ export interface ISettingsMergeService { _serviceBrand: undefined; - merge(localContent: string, remoteContent: string, baseContent: string | null): Promise; + merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{mergeContent: string, hasChanges: boolean, hasConflicts: boolean}>; } diff --git a/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts b/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts index 835e1a7179b..cd11a6743df 100644 --- a/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts +++ b/src/vs/workbench/services/userDataSync/common/settingsMergeService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as objects from 'vs/base/common/objects'; -import { values } from 'vs/base/common/map'; import { parse, findNodeAtLocation, parseTree } from 'vs/base/common/json'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -26,75 +25,21 @@ class SettingsMergeService implements ISettingsMergeService { @IModeService private readonly modeService: IModeService ) { } - async merge(localContent: string, remoteContent: string, baseContent: string | null): Promise { + async merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> { const local = parse(localContent); const remote = parse(remoteContent); const base = baseContent ? parse(baseContent) : null; - const { changes, conflicts } = this.getChanges(local, remote, base); - if (!changes.length && !conflicts.length) { - return localContent; - } - - const settingsPreviewModel = this.modelService.createModel(localContent, this.modeService.create('jsonc')); - for (const change of changes) { - this.editSetting(settingsPreviewModel, change.key, change.value); - } - for (const key of conflicts) { - const tree = parseTree(settingsPreviewModel.getValue()); - const valueNode = findNodeAtLocation(tree, [key]); - const eol = settingsPreviewModel.getEOL(); - const remoteEdit = setProperty(`{${eol}\t${eol}}`, [key], remote[key], { tabSize: 4, insertSpaces: false, eol: eol })[0]; - const remoteContent = remoteEdit ? `${remoteEdit.content.substring(remoteEdit.offset + remoteEdit.length + 1)},${eol}` : ''; - if (valueNode) { - // Updated in Local and Remote with different value - const keyPosition = settingsPreviewModel.getPositionAt(valueNode.parent!.offset); - const valuePosition = settingsPreviewModel.getPositionAt(valueNode.offset + valueNode.length); - const editOperations = [ - EditOperation.insert(new Position(keyPosition.lineNumber - 1, settingsPreviewModel.getLineMaxColumn(keyPosition.lineNumber - 1)), `${eol}<<<<<<< local`), - EditOperation.insert(new Position(valuePosition.lineNumber, settingsPreviewModel.getLineMaxColumn(valuePosition.lineNumber)), `${eol}=======${eol}${remoteContent}>>>>>>> remote`) - ]; - settingsPreviewModel.pushEditOperations([new Selection(keyPosition.lineNumber, keyPosition.column, keyPosition.lineNumber, keyPosition.column)], editOperations, () => []); - } else { - // Removed in Local, but updated in Remote - const position = new Position(settingsPreviewModel.getLineCount() - 1, settingsPreviewModel.getLineMaxColumn(settingsPreviewModel.getLineCount() - 1)); - const editOperations = [ - EditOperation.insert(position, `${eol}<<<<<<< local${eol}=======${eol}${remoteContent}>>>>>>> remote`) - ]; - settingsPreviewModel.pushEditOperations([new Selection(position.lineNumber, position.column, position.lineNumber, position.column)], editOperations, () => []); - } - } - return settingsPreviewModel.getValue(); - } - - private editSetting(model: ITextModel, key: string, value: any | undefined): void { - const insertSpaces = false; - const tabSize = 4; - const eol = model.getEOL(); - const edit = setProperty(model.getValue(), [key], value, { tabSize, insertSpaces, eol })[0]; - if (edit) { - const startPosition = model.getPositionAt(edit.offset); - const endPosition = model.getPositionAt(edit.offset + edit.length); - const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column); - let currentText = model.getValueInRange(range); - if (edit.content !== currentText) { - const editOperation = currentText ? EditOperation.replace(range, edit.content) : EditOperation.insert(startPosition, edit.content); - model.pushEditOperations([new Selection(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column)], [editOperation], () => []); - } - } - } - - private getChanges(local: { [key: string]: any }, remote: { [key: string]: any }, base: { [key: string]: any } | null): { changes: { key: string; value: any | undefined; }[], conflicts: string[] } { const localToRemote = this.compare(local, remote); if (localToRemote.added.size === 0 && localToRemote.removed.size === 0 && localToRemote.updated.size === 0) { // No changes found between local and remote. - return { changes: [], conflicts: [] }; + return { mergeContent: localContent, hasChanges: false, hasConflicts: false }; } - const changes: { key: string, value: any | undefined }[] = []; const conflicts: Set = new Set(); const baseToLocal = base ? this.compare(base, local) : { added: Object.keys(local).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; const baseToRemote = base ? this.compare(base, remote) : { added: Object.keys(remote).reduce((r, k) => { r.add(k); return r; }, new Set()), removed: new Set(), updated: new Set() }; + const settingsPreviewModel = this.modelService.createModel(localContent, this.modeService.create('jsonc')); // Removed settings in Local for (const key of baseToLocal.removed.keys()) { @@ -113,7 +58,7 @@ class SettingsMergeService implements ISettingsMergeService { if (baseToLocal.updated.has(key)) { conflicts.add(key); } else { - changes.push({ key, value: undefined }); + this.editSetting(settingsPreviewModel, key, undefined); } } @@ -143,7 +88,7 @@ class SettingsMergeService implements ISettingsMergeService { conflicts.add(key); } } else { - changes.push({ key, value: remote[key] }); + this.editSetting(settingsPreviewModel, key, remote[key]); } } @@ -173,11 +118,52 @@ class SettingsMergeService implements ISettingsMergeService { conflicts.add(key); } } else { - changes.push({ key, value: remote[key] }); + this.editSetting(settingsPreviewModel, key, remote[key]); } } - return { changes, conflicts: values(conflicts) }; + for (const key of conflicts.keys()) { + const tree = parseTree(settingsPreviewModel.getValue()); + const valueNode = findNodeAtLocation(tree, [key]); + const eol = settingsPreviewModel.getEOL(); + const remoteEdit = setProperty(`{${eol}\t${eol}}`, [key], remote[key], { tabSize: 4, insertSpaces: false, eol: eol })[0]; + const remoteContent = remoteEdit ? `${remoteEdit.content.substring(remoteEdit.offset + remoteEdit.length + 1)},${eol}` : ''; + if (valueNode) { + // Updated in Local and Remote with different value + const keyPosition = settingsPreviewModel.getPositionAt(valueNode.parent!.offset); + const valuePosition = settingsPreviewModel.getPositionAt(valueNode.offset + valueNode.length); + const editOperations = [ + EditOperation.insert(new Position(keyPosition.lineNumber - 1, settingsPreviewModel.getLineMaxColumn(keyPosition.lineNumber - 1)), `${eol}<<<<<<< local`), + EditOperation.insert(new Position(valuePosition.lineNumber, settingsPreviewModel.getLineMaxColumn(valuePosition.lineNumber)), `${eol}=======${eol}${remoteContent}>>>>>>> remote`) + ]; + settingsPreviewModel.pushEditOperations([new Selection(keyPosition.lineNumber, keyPosition.column, keyPosition.lineNumber, keyPosition.column)], editOperations, () => []); + } else { + // Removed in Local, but updated in Remote + const position = new Position(settingsPreviewModel.getLineCount() - 1, settingsPreviewModel.getLineMaxColumn(settingsPreviewModel.getLineCount() - 1)); + const editOperations = [ + EditOperation.insert(position, `${eol}<<<<<<< local${eol}=======${eol}${remoteContent}>>>>>>> remote`) + ]; + settingsPreviewModel.pushEditOperations([new Selection(position.lineNumber, position.column, position.lineNumber, position.column)], editOperations, () => []); + } + } + return { mergeContent: settingsPreviewModel.getValue(), hasChanges: true, hasConflicts: conflicts.size > 0 }; + } + + private editSetting(model: ITextModel, key: string, value: any | undefined): void { + const insertSpaces = false; + const tabSize = 4; + const eol = model.getEOL(); + const edit = setProperty(model.getValue(), [key], value, { tabSize, insertSpaces, eol })[0]; + if (edit) { + const startPosition = model.getPositionAt(edit.offset); + const endPosition = model.getPositionAt(edit.offset + edit.length); + const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column); + let currentText = model.getValueInRange(range); + if (edit.content !== currentText) { + const editOperation = currentText ? EditOperation.replace(range, edit.content) : EditOperation.insert(startPosition, edit.content); + model.pushEditOperations([new Selection(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column)], [editOperation], () => []); + } + } } private compare(from: { [key: string]: any }, to: { [key: string]: any }): { added: Set, removed: Set, updated: Set } { From 76a09c003827ca23574f86471a42ffb763d184c5 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 01:15:40 +0200 Subject: [PATCH 58/82] fix icon paths --- .../contrib/userDataSync/browser/userDataSync.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index f864d7e0176..b3c153261d4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -60,8 +60,8 @@ class UserDataAutoSyncContribution extends Disposable implements IWorkbenchContr } } -const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-light.svg`)); -const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userData/browser/media/sync-push-dark.svg`)); +const SYNC_PUSH_LIGHT_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/sync-push-light.svg`)); +const SYNC_PUSH_DARK_ICON_URI = URI.parse(registerAndGetAmdImageURL(`vs/workbench/contrib/userDataSync/browser/media/sync-push-dark.svg`)); class SyncActionsContribution extends Disposable implements IWorkbenchContribution { private readonly syncEnablementContext: IContextKey; From cc481ab31b5827add5f99a770f2c860d0575df69 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Tue, 17 Sep 2019 23:23:11 -0700 Subject: [PATCH 59/82] Remove unused icon references --- .../parts/panel/media/chevron-left-dark.svg | 3 -- .../parts/panel/media/chevron-left-hc.svg | 3 -- .../parts/panel/media/chevron-left-light.svg | 3 -- .../parts/panel/media/chevron-right-dark.svg | 3 -- .../parts/panel/media/chevron-right-hc.svg | 3 -- .../parts/panel/media/chevron-right-light.svg | 3 -- .../browser/parts/panel/media/panelpart.css | 52 ------------------- 7 files changed, 70 deletions(-) delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-left-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-left-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-left-light.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-right-dark.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-right-hc.svg delete mode 100644 src/vs/workbench/browser/parts/panel/media/chevron-right-light.svg diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-left-dark.svg b/src/vs/workbench/browser/parts/panel/media/chevron-left-dark.svg deleted file mode 100644 index dbc37784a70..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-left-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-left-hc.svg b/src/vs/workbench/browser/parts/panel/media/chevron-left-hc.svg deleted file mode 100644 index 3767c200513..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-left-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-left-light.svg b/src/vs/workbench/browser/parts/panel/media/chevron-left-light.svg deleted file mode 100644 index 2bd4c96832f..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-left-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-right-dark.svg b/src/vs/workbench/browser/parts/panel/media/chevron-right-dark.svg deleted file mode 100644 index f518fc1632a..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-right-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-right-hc.svg b/src/vs/workbench/browser/parts/panel/media/chevron-right-hc.svg deleted file mode 100644 index 40ba72b7086..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-right-hc.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/chevron-right-light.svg b/src/vs/workbench/browser/parts/panel/media/chevron-right-light.svg deleted file mode 100644 index 0d746558a4f..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/chevron-right-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 0f4232c4e44..fcb9fc8edfa 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -123,55 +123,3 @@ min-width: 110px; margin-right: 10px; } - -/* Up */ -.monaco-workbench .maximize-panel-action { - background-image: url('chevron-up-light.svg'); -} - -.vs-dark .monaco-workbench .maximize-panel-action { - background-image: url('chevron-up-dark.svg'); -} - -.hc-black .monaco-workbench .maximize-panel-action { - background-image: url('chevron-up-hc.svg'); -} - -/* Down */ -.monaco-workbench .minimize-panel-action { - background-image: url('chevron-down-light.svg'); -} - -.vs-dark .monaco-workbench .minimize-panel-action { - background-image: url('chevron-down-dark.svg'); -} - -.hc-black .monaco-workbench .minimize-panel-action { - background-image: url('chevron-down-hc.svg'); -} - -/* Left */ -.monaco-workbench .panel.right .maximize-panel-action { - background-image: url('chevron-left-light.svg'); -} - -.vs-dark .monaco-workbench .panel.right .maximize-panel-action { - background-image: url('chevron-left-dark.svg'); -} - -.hc-black .monaco-workbench .panel.right .maximize-panel-action { - background-image: url('chevron-left-hc.svg'); -} - -/* Right */ -.monaco-workbench .panel.right .minimize-panel-action { - background-image: url('chevron-right-light.svg'); -} - -.vs-dark .monaco-workbench .panel.right .minimize-panel-action { - background-image: url('chevron-right-dark.svg'); -} - -.hc-black .monaco-workbench .panel.right .minimize-panel-action { - background-image: url('chevron-right-hc.svg'); -} From 88e8f36e2d0a436694ffb19a3455dd01463ad00d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 10:10:08 +0200 Subject: [PATCH 60/82] use if modified headers --- .../platform/userDataSync/common/userDataSync.ts | 2 +- .../common/userDataSyncStoreService.ts | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 5801cea4ca3..3204cc95aaa 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -36,7 +36,7 @@ export interface IUserDataSyncStoreService { login(): Promise; logout(): Promise; - read(key: string): Promise; + read(key: string, oldValue: IUserData | null): Promise; write(key: string, content: string, ref: string | null): Promise; } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 7f1e4261921..83103e414a7 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -11,7 +11,7 @@ import { IRequestService, asJson, asText } from 'vs/platform/request/common/requ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { IStringDictionary } from 'vs/base/common/collections'; +import { IHeaders } from 'vs/base/parts/request/common/request'; export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService { @@ -37,12 +37,16 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn async logout(): Promise { } - async read(key: string): Promise { + async read(key: string, oldValue: IUserData | null): Promise { if (!this.enabled) { return Promise.reject(new Error('No settings sync store url configured.')); } const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); - const context = await this.requestService.request({ type: 'GET', url }, CancellationToken.None); + const headers: IHeaders = {}; + if (oldValue) { + headers['If-None-Match'] = oldValue.ref; + } + const context = await this.requestService.request({ type: 'GET', url, headers }, CancellationToken.None); return asJson(context); } @@ -52,7 +56,10 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn } const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); const data = JSON.stringify({ content, ref }); - const headers: IStringDictionary = { 'Content-Type': 'application/json' }; + const headers: IHeaders = { 'Content-Type': 'application/json' }; + if (ref) { + headers['If-Match'] = ref; + } const context = await this.requestService.request({ type: 'POST', url, data, headers }, CancellationToken.None); const newRef = await asText(context); if (!newRef) { From 8940dc827dd5fa4674a97c0649a001aeaa68b49c Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Sep 2019 10:58:33 +0200 Subject: [PATCH 61/82] fix file dialogs --- .../contrib/files/browser/fileActions.contribution.ts | 8 ++++++++ .../remote/electron-browser/remote.contribution.ts | 10 +--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index ff484b1f19c..539455d8825 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -49,6 +49,14 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleAutoSaveAction, const workspacesCategory = nls.localize('workspaces', "Workspaces"); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); +const fileCategory = nls.localize('file', "File"); +if (isMacintosh) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); +} else { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); +} + // Commands CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand); CommandsRegistry.registerCommand('_files.newWindow', newWindowCommand); diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index e45a5faa59e..3ba4103fd34 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -12,7 +12,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; @@ -33,8 +33,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; @@ -377,11 +375,7 @@ Registry.as(ConfigurationExtensions.Configuration) } }); -const registry = Registry.as(ActionExtensions.WorkbenchActions); -const fileCategory = nls.localize('file', "File"); - if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OpenLocalFileFolderCommand.ID, weight: KeybindingWeight.WorkbenchContrib, @@ -391,8 +385,6 @@ if (isMacintosh) { handler: OpenLocalFileFolderCommand.handler() }); } else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OpenLocalFileCommand.ID, weight: KeybindingWeight.WorkbenchContrib, From 23d176011797b78ba9a1843fcf5623ae067a348d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 11:32:09 +0200 Subject: [PATCH 62/82] debt - first cut extract showIteminFolder --- .../electron-main/electronMainService.ts | 6 +- src/vs/platform/electron/node/electron.ts | 3 + src/vs/platform/windows/common/windows.ts | 1 - src/vs/platform/windows/common/windowsIpc.ts | 1 - .../electron-browser/windowsService.ts | 4 - .../windows/electron-main/windowsService.ts | 8 -- .../browser/parts/titlebar/titlebarPart.ts | 5 +- .../workbench/browser/web.simpleservices.ts | 4 - .../browser/extensions.contribution.ts | 11 +-- .../extensions/browser/extensionsActions.ts | 38 +-------- .../extensions.contribution.ts | 19 ++++- .../electron-browser/extensionsActions.ts | 47 +++++++++++ .../files/browser/fileActions.contribution.ts | 29 +------ .../contrib/files/browser/fileCommands.ts | 43 +--------- .../fileActions.contribution.ts | 83 +++++++++++++++++++ .../files/electron-browser/fileCommands.ts | 31 +++++++ .../contrib/logs/common/logs.contribution.ts | 6 +- .../contrib/logs/common/logsActions.ts | 20 ----- .../electron-browser/logs.contribution.ts | 14 ++++ .../logs/electron-browser/logsActions.ts | 28 +++++++ .../electron-browser/startupProfiler.ts | 6 +- src/vs/workbench/electron-browser/window.ts | 6 +- .../workbench/test/workbenchTestServices.ts | 4 - src/vs/workbench/workbench.desktop.main.ts | 6 ++ 24 files changed, 254 insertions(+), 169 deletions(-) create mode 100644 src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts create mode 100644 src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts create mode 100644 src/vs/workbench/contrib/files/electron-browser/fileCommands.ts create mode 100644 src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts create mode 100644 src/vs/workbench/contrib/logs/electron-browser/logsActions.ts diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index a8c92d2414b..bcdee9d4a02 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -5,7 +5,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -import { MessageBoxOptions, MessageBoxReturnValue } from 'electron'; +import { MessageBoxOptions, MessageBoxReturnValue, shell } from 'electron'; import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; @@ -30,6 +30,10 @@ export class ElectronMainService implements IElectronService { checkboxChecked: !!result.checkboxChecked }; } + + async showItemInFolder(path: string): Promise { + shell.showItemInFolder(path); + } } export class ElectronChannel implements IServerChannel { diff --git a/src/vs/platform/electron/node/electron.ts b/src/vs/platform/electron/node/electron.ts index 0f6c3a83091..5411269d98e 100644 --- a/src/vs/platform/electron/node/electron.ts +++ b/src/vs/platform/electron/node/electron.ts @@ -14,4 +14,7 @@ export interface IElectronService { // Dialogs showMessageBox(options: MessageBoxOptions): Promise; + + // OS + showItemInFolder(path: string): Promise; } diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 97f4c9b7687..a34ebe2978c 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -156,7 +156,6 @@ export interface IWindowsService { openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>; getWindowCount(): Promise; - showItemInFolder(path: URI): Promise; getActiveWindowId(): Promise; // This needs to be handled from browser process to prevent diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 091f49e137f..6534f2f56d3 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -109,7 +109,6 @@ export class WindowsChannel implements IServerChannel { case 'whenSharedProcessReady': return this.service.whenSharedProcessReady(); case 'toggleSharedProcess': return this.service.toggleSharedProcess(); case 'quit': return this.service.quit(); - case 'showItemInFolder': return this.service.showItemInFolder(URI.revive(arg)); case 'getActiveWindowId': return this.service.getActiveWindowId(); case 'openExternal': return this.service.openExternal(arg); case 'startCrashReporter': return this.service.startCrashReporter(arg); diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index 283259ac8d6..4e983130529 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -226,10 +226,6 @@ export class WindowsService implements IWindowsService { return this.channel.call('getWindowCount'); } - showItemInFolder(path: URI): Promise { - return this.channel.call('showItemInFolder', path); - } - getActiveWindowId(): Promise { return this.channel.call('getActiveWindowId'); } diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 4d219fc827b..6cdde7c3da8 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -336,14 +336,6 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH return this.windowsMainService.getWindows().length; } - async showItemInFolder(resource: URI): Promise { - this.logService.trace('windowsService#showItemInFolder'); - - if (resource.scheme === Schemas.file) { - shell.showItemInFolder(resource.fsPath); - } - } - async getActiveWindowId(): Promise { return this._activeWindowId; } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index a934e456352..f222733af9d 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -376,7 +376,6 @@ export class TitlebarPart extends Part implements ITitleService { if (!isMacintosh && !isWeb) { this.windowControls = append(this.element, $('div.window-controls-container')); - // Minimize const minimizeIconContainer = append(this.windowControls, $('div.window-icon-bg')); const minimizeIcon = append(minimizeIconContainer, $('div.window-icon')); @@ -612,7 +611,9 @@ class ShowItemInFolderAction extends Action { } run(): Promise { - return this.windowsService.showItemInFolder(URI.file(this.path)); + if (this.path && this.windowsService) { } + return Promise.resolve(); + // return this.windowsService.showItemInFolder(URI.file(this.path)); } } diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index fdc94ca35b0..a0fe7aa1915 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -465,10 +465,6 @@ export class SimpleWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - showItemInFolder(_path: URI): Promise { - return Promise.resolve(); - } - newWindowTab(): Promise { return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index b7bed063f07..db05deb3e72 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -20,7 +20,7 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/brow import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction, - EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction + EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; @@ -43,7 +43,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/browser/extensionsDependencyChecker'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { RemoteExtensionsInstaller } from 'vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller'; import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/browser/extensionTipsService'; @@ -344,7 +343,6 @@ const workbenchRegistry = Registry.as(Workbench class ExtensionsContributions implements IWorkbenchContribution { constructor( - @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService ) { @@ -362,14 +360,7 @@ class ExtensionsContributions implements IWorkbenchContribution { ) ); } - - if (workbenchEnvironmentService.extensionsPath) { - const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); - actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); - } - } - } workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index b9356f1b35e..a18bcf9b4ba 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -25,7 +25,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery'; import { IFileService, IFileContent } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; @@ -44,7 +44,6 @@ import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/w import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; @@ -2777,41 +2776,6 @@ export class EnableAllWorkpsaceAction extends Action { } } -export class OpenExtensionsFolderAction extends Action { - - static readonly ID = 'workbench.extensions.action.openExtensionsFolder'; - static LABEL = localize('openExtensionsFolder', "Open Extensions Folder"); - - constructor( - id: string, - label: string, - @IWindowsService private readonly windowsService: IWindowsService, - @IFileService private readonly fileService: IFileService, - @IEnvironmentService private readonly environmentService: IEnvironmentService - ) { - super(id, label, undefined, true); - } - - run(): Promise { - if (this.environmentService.extensionsPath) { - - const extensionsHome = URI.file(this.environmentService.extensionsPath); - - return Promise.resolve(this.fileService.resolve(extensionsHome)).then(file => { - let itemToShow: URI; - if (file.children && file.children.length > 0) { - itemToShow = file.children[0].resource; - } else { - itemToShow = extensionsHome; - } - - return this.windowsService.showItemInFolder(itemToShow); - }); - } - return Promise.resolve(); - } -} - export class InstallVSIXAction extends Action { static readonly ID = 'workbench.extensions.action.installVSIX'; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index d47550c32a9..19e5153bb53 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -8,7 +8,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -22,6 +22,9 @@ import { URI } from 'vs/base/common/uri'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; import { registerAndGetAmdImageURL } from 'vs/base/common/amd'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { OpenExtensionsFolderAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; // Singletons registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); @@ -57,6 +60,20 @@ const actionRegistry = Registry.as(WorkbenchActionExte actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowRuntimeExtensionsAction, ShowRuntimeExtensionsAction.ID, ShowRuntimeExtensionsAction.LABEL), 'Show Running Extensions', localize('developer', "Developer")); +class ExtensionsContributions implements IWorkbenchContribution { + + constructor( + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService + ) { + if (workbenchEnvironmentService.extensionsPath) { + const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL); + actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); + } + } +} + +workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting); + // Register Commands CommandsRegistry.registerCommand(DebugExtensionHostAction.ID, (accessor: ServicesAccessor) => { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts new file mode 100644 index 00000000000..b4185a6614f --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { Schemas } from 'vs/base/common/network'; + +export class OpenExtensionsFolderAction extends Action { + + static readonly ID = 'workbench.extensions.action.openExtensionsFolder'; + static LABEL = localize('openExtensionsFolder', "Open Extensions Folder"); + + constructor( + id: string, + label: string, + @IElectronService private readonly electronService: IElectronService, + @IFileService private readonly fileService: IFileService, + @IEnvironmentService private readonly environmentService: IEnvironmentService + ) { + super(id, label, undefined, true); + } + + async run(): Promise { + if (this.environmentService.extensionsPath) { + const extensionsHome = URI.file(this.environmentService.extensionsPath); + const file = await this.fileService.resolve(extensionsHome); + + let itemToShow: URI; + if (file.children && file.children.length > 0) { + itemToShow = file.children[0].resource; + } else { + itemToShow = extensionsHome; + } + + if (itemToShow.scheme === Schemas.file) { + return this.electronService.showItemInFolder(itemToShow.fsPath); + } + } + } +} + diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 539455d8825..47c9912e899 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -10,11 +10,11 @@ import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTI import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; -import { openWindowCommand, REVEAL_IN_OS_COMMAND_ID, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, REVEAL_IN_OS_LABEL, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands'; +import { openWindowCommand, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { isWindows, isMacintosh } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; @@ -170,11 +170,9 @@ const copyRelativePathCommand = { // Editor Title Context Menu appendEditorTitleContextMenuItem(COPY_PATH_COMMAND_ID, copyPathCommand.title, ResourceContextKey.IsFileSystemResource, '1_cutcopypaste'); appendEditorTitleContextMenuItem(COPY_RELATIVE_PATH_COMMAND_ID, copyRelativePathCommand.title, ResourceContextKey.IsFileSystemResource, '1_cutcopypaste'); -appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ResourceContextKey.Scheme.isEqualTo(Schemas.file)); -appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.isEqualTo(Schemas.userData))); appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource); -function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { +export function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { // Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { @@ -210,7 +208,7 @@ function appendSaveConflictEditorTitleAction(id: string, title: string, iconLoca // Menu registration - command palette -function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpr): void { +export function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpr): void { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id, @@ -230,7 +228,6 @@ appendToCommandPalette(SAVE_ALL_IN_GROUP_COMMAND_ID, { value: nls.localize('save appendToCommandPalette(SAVE_FILES_COMMAND_ID, { value: nls.localize('saveFiles', "Save All Files"), original: 'Save All Files' }, category); appendToCommandPalette(REVERT_FILE_COMMAND_ID, { value: nls.localize('revert', "Revert File"), original: 'Revert File' }, category); appendToCommandPalette(COMPARE_WITH_SAVED_COMMAND_ID, { value: nls.localize('compareActiveWithSaved', "Compare Active File with Saved"), original: 'Compare Active File with Saved' }, category); -appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category); appendToCommandPalette(SAVE_FILE_AS_COMMAND_ID, { value: SAVE_FILE_AS_LABEL, original: 'Save As...' }, category); appendToCommandPalette(CLOSE_EDITOR_COMMAND_ID, { value: nls.localize('closeEditor', "Close Editor"), original: 'Close Editor' }, { value: nls.localize('view', "View"), original: 'View' }); appendToCommandPalette(NEW_FILE_COMMAND_ID, { value: NEW_FILE_LABEL, original: 'New File' }, category, WorkspaceFolderCountContext.notEqualsTo('0')); @@ -250,17 +247,6 @@ MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { when: ResourceContextKey.IsFileSystemResource }); -const revealInOsCommand = { - id: REVEAL_IN_OS_COMMAND_ID, - title: isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder") -}; -MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { - group: 'navigation', - order: 20, - command: revealInOsCommand, - when: ResourceContextKey.IsFileSystemResource -}); - MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { group: '1_cutcopypaste', order: 10, @@ -428,13 +414,6 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { when: ContextKeyExpr.and(ExplorerFolderContext.toNegated(), ResourceContextKey.HasResource) }); -MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { - group: 'navigation', - order: 20, - command: revealInOsCommand, - when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) -}); - MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { group: '3_compare', order: 20, diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 2ee93fec213..98363ee5a05 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -25,9 +25,8 @@ import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; -import { isWindows, isMacintosh } from 'vs/base/common/platform'; +import { isWindows } from 'vs/base/common/platform'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { sequence } from 'vs/base/common/async'; import { getResourceForCommand, getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { getMultiSelectedEditorContexts } from 'vs/workbench/browser/parts/editor/editorCommands'; @@ -46,8 +45,6 @@ import { withUndefinedAsNull } from 'vs/base/common/types'; // Commands -export const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS'; -export const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder"); export const REVEAL_IN_EXPLORER_COMMAND_ID = 'revealInExplorer'; export const REVERT_FILE_COMMAND_ID = 'workbench.action.files.revert'; export const OPEN_TO_SIDE_COMMAND_ID = 'explorer.openToSide'; @@ -406,44 +403,6 @@ CommandsRegistry.registerCommand({ } }); -function revealResourcesInOS(resources: URI[], windowsService: IWindowsService, notificationService: INotificationService, workspaceContextService: IWorkspaceContextService): void { - if (resources.length) { - sequence(resources.map(r => () => windowsService.showItemInFolder(r.scheme === Schemas.userData ? r.with({ scheme: Schemas.file }) : r))); - } else if (workspaceContextService.getWorkspace().folders.length) { - windowsService.showItemInFolder(workspaceContextService.getWorkspace().folders[0].uri); - } else { - notificationService.info(nls.localize('openFileToReveal', "Open a file first to reveal")); - } -} - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: REVEAL_IN_OS_COMMAND_ID, - weight: KeybindingWeight.WorkbenchContrib, - when: EditorContextKeys.focus.toNegated(), - primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R, - win: { - primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_R - }, - handler: (accessor: ServicesAccessor, resource: URI | object) => { - const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService)); - revealResourcesInOS(resources, accessor.get(IWindowsService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService)); - } -}); - -KeybindingsRegistry.registerCommandAndKeybindingRule({ - weight: KeybindingWeight.WorkbenchContrib, - when: undefined, - primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R), - id: 'workbench.action.files.revealActiveFileInWindows', - handler: (accessor: ServicesAccessor) => { - const editorService = accessor.get(IEditorService); - const activeInput = editorService.activeEditor; - const resource = activeInput ? activeInput.getResource() : null; - const resources = resource ? [resource] : []; - revealResourcesInOS(resources, accessor.get(IWindowsService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService)); - } -}); - async function resourcesToClipboard(resources: URI[], relative: boolean, clipboardService: IClipboardService, notificationService: INotificationService, labelService: ILabelService): Promise { if (resources.length) { const lineDelimiter = isWindows ? '\r\n' : '\n'; diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts new file mode 100644 index 00000000000..20be6820e3f --- /dev/null +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { URI } from 'vs/base/common/uri'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { isWindows, isMacintosh } from 'vs/base/common/platform'; +import { Schemas } from 'vs/base/common/network'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; +import { IListService } from 'vs/platform/list/browser/listService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { revealResourcesInOS } from 'vs/workbench/contrib/files/electron-browser/fileCommands'; +import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { ResourceContextKey } from 'vs/workbench/common/resources'; +import { appendToCommandPalette, appendEditorTitleContextMenuItem } from 'vs/workbench/contrib/files/browser/fileActions.contribution'; + +const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS'; +const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder"); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: REVEAL_IN_OS_COMMAND_ID, + weight: KeybindingWeight.WorkbenchContrib, + when: EditorContextKeys.focus.toNegated(), + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R, + win: { + primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_R + }, + handler: (accessor: ServicesAccessor, resource: URI | object) => { + const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService)); + revealResourcesInOS(resources, accessor.get(IElectronService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService)); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + weight: KeybindingWeight.WorkbenchContrib, + when: undefined, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R), + id: 'workbench.action.files.revealActiveFileInWindows', + handler: (accessor: ServicesAccessor) => { + const editorService = accessor.get(IEditorService); + const activeInput = editorService.activeEditor; + const resource = activeInput ? activeInput.getResource() : null; + const resources = resource ? [resource] : []; + revealResourcesInOS(resources, accessor.get(IElectronService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService)); + } +}); + +appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ResourceContextKey.Scheme.isEqualTo(Schemas.file)); + +// Menu registration - open editors + +const revealInOsCommand = { + id: REVEAL_IN_OS_COMMAND_ID, + title: isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder") +}; +MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, { + group: 'navigation', + order: 20, + command: revealInOsCommand, + when: ResourceContextKey.IsFileSystemResource +}); + +// Menu registration - explorer + +MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { + group: 'navigation', + order: 20, + command: revealInOsCommand, + when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) +}); + +// Command Palette + +const category = { value: nls.localize('filesCategory', "File"), original: 'File' }; +appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category); diff --git a/src/vs/workbench/contrib/files/electron-browser/fileCommands.ts b/src/vs/workbench/contrib/files/electron-browser/fileCommands.ts new file mode 100644 index 00000000000..0a6e710462c --- /dev/null +++ b/src/vs/workbench/contrib/files/electron-browser/fileCommands.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { URI } from 'vs/base/common/uri'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { sequence } from 'vs/base/common/async'; +import { Schemas } from 'vs/base/common/network'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +// Commands + +export function revealResourcesInOS(resources: URI[], electronService: IElectronService, notificationService: INotificationService, workspaceContextService: IWorkspaceContextService): void { + if (resources.length) { + sequence(resources.map(r => async () => { + if (r.scheme === Schemas.file) { + electronService.showItemInFolder(r.fsPath); + } + })); + } else if (workspaceContextService.getWorkspace().folders.length) { + const uri = workspaceContextService.getWorkspace().folders[0].uri; + if (uri.scheme === Schemas.file) { + electronService.showItemInFolder(uri.fsPath); + } + } else { + notificationService.info(nls.localize('openFileToReveal', "Open a file first to reveal")); + } +} diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 3de9142da6b..ab29875c3c3 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -8,7 +8,7 @@ import { join } from 'vs/base/common/path'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { SetLogLevelAction, OpenLogsFolderAction, OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; +import { SetLogLevelAction, OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -64,10 +64,6 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { }; registerTelemetryChannel(this.logService.getLevel()); this.logService.onDidChangeLogLevel(registerTelemetryChannel); - - const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); - const devCategory = nls.localize('developer', "Developer"); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory); } private async registerLogChannel(id: string, label: string, file: URI): Promise { diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index 00a100d4c64..34e9eed4475 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -5,9 +5,6 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { join } from 'vs/base/common/path'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; @@ -16,23 +13,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -export class OpenLogsFolderAction extends Action { - - static ID = 'workbench.action.openLogsFolder'; - static LABEL = nls.localize('openLogsFolder', "Open Logs Folder"); - - constructor(id: string, label: string, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IWindowsService private readonly windowsService: IWindowsService, - ) { - super(id, label); - } - - run(): Promise { - return this.windowsService.showItemInFolder(URI.file(join(this.environmentService.logsPath, 'main.log'))); - } -} - export class SetLogLevelAction extends Action { static ID = 'workbench.action.setLogLevel'; diff --git a/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts new file mode 100644 index 00000000000..f6ceef58f71 --- /dev/null +++ b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { OpenLogsFolderAction } from 'vs/workbench/contrib/logs/electron-browser/logsActions'; + +const workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); +const devCategory = nls.localize('developer', "Developer"); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory); diff --git a/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts new file mode 100644 index 00000000000..547558b7deb --- /dev/null +++ b/src/vs/workbench/contrib/logs/electron-browser/logsActions.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; +import { join } from 'vs/base/common/path'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { URI } from 'vs/base/common/uri'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +export class OpenLogsFolderAction extends Action { + + static ID = 'workbench.action.openLogsFolder'; + static LABEL = nls.localize('openLogsFolder', "Open Logs Folder"); + + constructor(id: string, label: string, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IElectronService private readonly electronService: IElectronService, + ) { + super(id, label); + } + + run(): Promise { + return this.electronService.showItemInFolder(URI.file(join(this.environmentService.logsPath, 'main.log')).fsPath); + } +} diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts index daa2adf2ccd..0509b63e0d3 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupProfiler.ts @@ -18,6 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { URI } from 'vs/base/common/uri'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IElectronService } from 'vs/platform/electron/node/electron'; export class StartupProfiler implements IWorkbenchContribution { @@ -29,7 +30,8 @@ export class StartupProfiler implements IWorkbenchContribution { @IClipboardService private readonly _clipboardService: IClipboardService, @ILifecycleService lifecycleService: ILifecycleService, @IExtensionService extensionService: IExtensionService, - @IOpenerService private readonly _openerService: IOpenerService + @IOpenerService private readonly _openerService: IOpenerService, + @IElectronService private readonly _electronService: IElectronService ) { // wait for everything to be ready Promise.all([ @@ -81,7 +83,7 @@ export class StartupProfiler implements IWorkbenchContribution { }).then(res => { if (res.confirmed) { Promise.all([ - this._windowsService.showItemInFolder(URI.file(join(dir, files[0]))), + this._electronService.showItemInFolder(URI.file(join(dir, files[0])).fsPath), this._createPerfIssue(files) ]).then(() => { // keep window stable until restart is selected diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d650e0a1594..80eadd8163a 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -55,6 +55,7 @@ import { IMenubarService, IMenubarData, IMenubarMenu, IMenubarKeybinding, IMenub import { withNullAsUndefined } from 'vs/base/common/types'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { Schemas } from 'vs/base/common/network'; +import { IElectronService } from 'vs/platform/electron/node/electron'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -102,7 +103,8 @@ export class ElectronWindow extends Disposable { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ITextFileService private readonly textFileService: ITextFileService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IOpenerService private readonly openerService: IOpenerService + @IOpenerService private readonly openerService: IOpenerService, + @IElectronService private readonly electronService: IElectronService ) { super(); @@ -371,7 +373,7 @@ export class ElectronWindow extends Disposable { const success = await $this.windowsService.openExternal(encodeURI(resource.toString(true))); if (!success && resource.scheme === Schemas.file) { // if opening failed, and this is a file, we can still try to reveal it - await $this.windowsService.showItemInFolder(resource); + await $this.electronService.showItemInFolder(resource.fsPath); } return true; diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index ad9ae1c822d..73a3517bd60 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -1494,10 +1494,6 @@ export class TestWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - showItemInFolder(_path: URI): Promise { - return Promise.resolve(); - } - newWindowTab(): Promise { return Promise.resolve(); } diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index f22592cb8fe..7739c33362a 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -90,6 +90,9 @@ registerSingleton(IElectronService, ElectronService, true); // Localizations import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; +// Logs +import 'vs/workbench/contrib/logs/electron-browser/logs.contribution'; + // Stats import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; @@ -97,6 +100,9 @@ import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; // Rapid Render Splash import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; +// Explorer +import 'vs/workbench/contrib/files/electron-browser/fileActions.contribution'; + // Debug import 'vs/workbench/contrib/debug/node/debugHelperService'; import 'vs/workbench/contrib/debug/electron-browser/extensionHostDebugService'; From 6d7917cd3c4ecc17f249583daf9c2f6c23e6d6e2 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 18 Sep 2019 12:14:32 +0200 Subject: [PATCH 63/82] Add some C++ scopes to dark+ and light+ themes Part of #80783 --- .../test/colorize-results/test-23630_cpp.json | 32 ++++----- .../test/colorize-results/test-23850_cpp.json | 32 ++++----- .../test/colorize-results/test-78769_cpp.json | 28 ++++---- .../cpp/test/colorize-results/test_cc.json | 26 +++---- .../cpp/test/colorize-results/test_cpp.json | 28 ++++---- .../theme-defaults/themes/dark_plus.json | 67 +++++++++++++++++++ .../theme-defaults/themes/light_plus.json | 50 +++++++++++++- 7 files changed, 189 insertions(+), 74 deletions(-) diff --git a/extensions/cpp/test/colorize-results/test-23630_cpp.json b/extensions/cpp/test/colorize-results/test-23630_cpp.json index 08d81e6afff..26da4333e92 100644 --- a/extensions/cpp/test/colorize-results/test-23630_cpp.json +++ b/extensions/cpp/test/colorize-results/test-23630_cpp.json @@ -3,8 +3,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.conditional.ifndef.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -14,8 +14,8 @@ "c": "ifndef", "t": "source.cpp keyword.control.directive.conditional.ifndef.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -36,8 +36,8 @@ "c": "_UCRT", "t": "source.cpp meta.preprocessor.conditional.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -58,8 +58,8 @@ "c": "#", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -69,8 +69,8 @@ "c": "define", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -91,8 +91,8 @@ "c": "_UCRT", "t": "source.cpp meta.preprocessor.macro.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -102,8 +102,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.endif.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -113,8 +113,8 @@ "c": "endif", "t": "source.cpp keyword.control.directive.endif.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" diff --git a/extensions/cpp/test/colorize-results/test-23850_cpp.json b/extensions/cpp/test/colorize-results/test-23850_cpp.json index 4ba6b59dc9b..9a0466d8c29 100644 --- a/extensions/cpp/test/colorize-results/test-23850_cpp.json +++ b/extensions/cpp/test/colorize-results/test-23850_cpp.json @@ -3,8 +3,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.conditional.ifndef.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -14,8 +14,8 @@ "c": "ifndef", "t": "source.cpp keyword.control.directive.conditional.ifndef.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -36,8 +36,8 @@ "c": "_UCRT", "t": "source.cpp meta.preprocessor.conditional.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -47,8 +47,8 @@ "c": "#", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -58,8 +58,8 @@ "c": "define", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -80,8 +80,8 @@ "c": "_UCRT", "t": "source.cpp meta.preprocessor.macro.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -91,8 +91,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.endif.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -102,8 +102,8 @@ "c": "endif", "t": "source.cpp keyword.control.directive.endif.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" diff --git a/extensions/cpp/test/colorize-results/test-78769_cpp.json b/extensions/cpp/test/colorize-results/test-78769_cpp.json index e714cf5e26b..da4cbdd99b2 100644 --- a/extensions/cpp/test/colorize-results/test-78769_cpp.json +++ b/extensions/cpp/test/colorize-results/test-78769_cpp.json @@ -3,8 +3,8 @@ "c": "#", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -14,8 +14,8 @@ "c": "define", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -36,8 +36,8 @@ "c": "DOCTEST_IMPLEMENT_FIXTURE", "t": "source.cpp meta.preprocessor.macro.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -58,8 +58,8 @@ "c": "der", "t": "source.cpp meta.preprocessor.macro.cpp variable.parameter.preprocessor.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "variable: #9CDCFE" @@ -91,8 +91,8 @@ "c": "base", "t": "source.cpp meta.preprocessor.macro.cpp variable.parameter.preprocessor.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "variable: #9CDCFE" @@ -124,8 +124,8 @@ "c": "func", "t": "source.cpp meta.preprocessor.macro.cpp variable.parameter.preprocessor.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "variable: #9CDCFE" @@ -157,8 +157,8 @@ "c": "decorators", "t": "source.cpp meta.preprocessor.macro.cpp variable.parameter.preprocessor.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "variable: #9CDCFE" diff --git a/extensions/cpp/test/colorize-results/test_cc.json b/extensions/cpp/test/colorize-results/test_cc.json index 902ef645164..6c3e21a12a3 100644 --- a/extensions/cpp/test/colorize-results/test_cc.json +++ b/extensions/cpp/test/colorize-results/test_cc.json @@ -3,8 +3,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.conditional.if.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -14,8 +14,8 @@ "c": "if", "t": "source.cpp keyword.control.directive.conditional.if.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -36,8 +36,8 @@ "c": "B4G_DEBUG_CHECK", "t": "source.cpp meta.preprocessor.conditional.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -652,8 +652,8 @@ "c": "#", "t": "source.cpp keyword.control.directive.endif.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -663,8 +663,8 @@ "c": "endif", "t": "source.cpp keyword.control.directive.endif.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -751,8 +751,8 @@ "c": "obj", "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", "hc_black": "variable: #9CDCFE" @@ -1037,7 +1037,7 @@ "c": "x", "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp variable.other.property.cpp", "r": { - "dark_plus": "variable: #9CDCFE", + "dark_plus": "source.cpp variable.other.property: #DADADA", "light_plus": "variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", diff --git a/extensions/cpp/test/colorize-results/test_cpp.json b/extensions/cpp/test/colorize-results/test_cpp.json index f84d916afa3..9a6fe977b57 100644 --- a/extensions/cpp/test/colorize-results/test_cpp.json +++ b/extensions/cpp/test/colorize-results/test_cpp.json @@ -25,8 +25,8 @@ "c": "#", "t": "source.cpp meta.preprocessor.include.cpp keyword.control.directive.include.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -36,8 +36,8 @@ "c": "include", "t": "source.cpp meta.preprocessor.include.cpp keyword.control.directive.include.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -157,8 +157,8 @@ "c": "#", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp punctuation.definition.directive.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -168,8 +168,8 @@ "c": "define", "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp", "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", + "dark_plus": "source.cpp keyword.control.directive: #9B9B9B", + "light_plus": "source.cpp keyword.control.directive: #808080", "dark_vs": "keyword.control: #569CD6", "light_vs": "keyword.control: #0000FF", "hc_black": "keyword.control: #C586C0" @@ -190,8 +190,8 @@ "c": "EXTERN_C", "t": "source.cpp meta.preprocessor.macro.cpp entity.name.function.preprocessor.cpp", "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", + "dark_plus": "source.cpp entity.name.function.preprocessor: #C586C0", + "light_plus": "source.cpp entity.name.function.preprocessor: #AF00DB", "dark_vs": "meta.preprocessor: #569CD6", "light_vs": "meta.preprocessor: #0000FF", "hc_black": "entity.name.function: #DCDCAA" @@ -817,8 +817,8 @@ "c": "x", "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", "hc_black": "variable: #9CDCFE" @@ -872,8 +872,8 @@ "c": "y", "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "source.cpp variable.parameter: #7F7F7F", + "light_plus": "source.cpp variable.parameter: #808080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", "hc_black": "variable: #9CDCFE" diff --git a/extensions/theme-defaults/themes/dark_plus.json b/extensions/theme-defaults/themes/dark_plus.json index f12d3d7633e..3efcc124ff0 100644 --- a/extensions/theme-defaults/themes/dark_plus.json +++ b/extensions/theme-defaults/themes/dark_plus.json @@ -170,6 +170,73 @@ "settings": { "foreground": "#d7ba7d" } + }, + // Scopes that are potentially C++ only follow + { + "scope": "source.cpp entity.name", + "settings": { + "foreground": "#C8C8C8" + } + }, + { + "scope": "source.cpp keyword.control.directive", + "settings": { + "foreground": "#9B9B9B" + } + }, + { + "scope": "source.cpp entity.name.function.operator", + "settings": { + "foreground": "#B4B4B4" + } + }, + { + "scope": "source.cpp entity.name.function.preprocessor", + "settings": { + "foreground": "#C586C0" + } + }, + { + "scope": "source.cpp entity.name.label", + "settings": { + "foreground": "#C8C8C8" + } + }, + { + "scope": "source.cpp entity.name.operator.custom-literal", + "settings": { + "foreground": "#DADADA" + } + }, + { + "scope": "source.cpp entity.name.operator.custom-literal.number", + "settings": { + "foreground": "#B5CEA8" + } + }, + { + "scope": "source.cpp entity.name.operator.custom-literal.string", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "source.cpp variable.other.enummember", + "settings": { + "foreground": "#B8D7A3" + } + }, + { + "scope": "source.cpp variable.other.property", + "settings": { + "foreground": "#DADADA" + } + }, + { + "scope": "source.cpp variable.parameter", + "settings": { + "foreground": "#7F7F7F" + } } ] } diff --git a/extensions/theme-defaults/themes/light_plus.json b/extensions/theme-defaults/themes/light_plus.json index 3d30c5d17fb..e6a4c922357 100644 --- a/extensions/theme-defaults/themes/light_plus.json +++ b/extensions/theme-defaults/themes/light_plus.json @@ -170,7 +170,55 @@ "settings": { "foreground": "#ff0000" } + }, + // Scopes that are potentially C++ only follow + { + "scope": "source.cpp entity.name", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "source.cpp keyword.control.directive", + "settings": { + "foreground": "#808080" + } + }, + { + "scope": "source.cpp entity.name.function.operator", + "settings": { + "foreground": "#008080" + } + }, + { + "scope": "source.cpp entity.name.function.preprocessor", + "settings": { + "foreground": "#AF00DB" + } + }, + { + "scope": "source.cpp entity.name.label", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "source.cpp entity.name.operator.custom-literal.string", + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": "source.cpp variable.other.enummember", + "settings": { + "foreground": "#2F4F4F" + } + }, + { + "scope": "source.cpp variable.parameter", + "settings": { + "foreground": "#808080" + } } - ] } From c0072b61ee458fbabae30fcb40c12f6528bdef39 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 12:15:30 +0200 Subject: [PATCH 64/82] use if match and if not match headers --- .../userDataSync/common/settingsSync.ts | 20 +++++------ .../userDataSync/common/userDataSync.ts | 6 ++-- .../common/userDataSyncStoreService.ts | 36 ++++++++++++++----- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index f408d51a7c6..d16ac10bad3 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -18,7 +18,7 @@ import { joinPath } from 'vs/base/common/resources'; interface ISyncPreviewResult { readonly fileContent: IFileContent | null; - readonly remoteUserData: IUserData | null; + readonly remoteUserData: IUserData; readonly hasLocalChanged: boolean; readonly hasRemoteChanged: boolean; readonly hasConflicts: boolean; @@ -135,13 +135,13 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { let { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged } = await this.syncPreviewResultPromise; if (hasRemoteChanged) { - const ref = await this.writeToRemote(content, remoteUserData ? remoteUserData.ref : null); + const ref = await this.writeToRemote(content, remoteUserData.ref); remoteUserData = { ref, content }; } if (hasLocalChanged) { await this.writeToLocal(content, fileContent); } - if (remoteUserData) { + if (remoteUserData.content) { await this.updateLastSyncValue(remoteUserData); } @@ -167,7 +167,9 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } private async generatePreview(): Promise { - const remoteUserData = await this.userDataSyncStoreService.read(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY); + const lastSyncData = await this.getLastSyncUserData(); + const remoteUserData = await this.userDataSyncStoreService.read(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY, lastSyncData); + const remoteContent: string | null = remoteUserData.content; // Get file content last to get the latest const fileContent = await this.getLocalFileContent(); let hasLocalChanged: boolean = false; @@ -175,7 +177,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { let hasConflicts: boolean = false; // First time sync to remote - if (fileContent && !remoteUserData) { + if (fileContent && !remoteContent) { this.logService.trace('Settings Sync: Remote contents does not exist. So sync with settings file.'); hasRemoteChanged = true; await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(fileContent.value.toString())); @@ -183,17 +185,15 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser { } // Settings file does not exist, so sync with remote contents. - if (remoteUserData && !fileContent) { + if (remoteContent && !fileContent) { this.logService.trace('Settings Sync: Settings file does not exist. So sync with remote contents'); hasLocalChanged = true; - await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(remoteUserData.content)); + await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(remoteContent)); return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts }; } - if (fileContent && remoteUserData) { + if (fileContent && remoteContent) { const localContent: string = fileContent.value.toString(); - const remoteContent: string = remoteUserData.content; - const lastSyncData = await this.getLastSyncUserData(); if (!lastSyncData // First time sync || lastSyncData.content !== localContent // Local has moved forwarded || lastSyncData.content !== remoteContent // Remote has moved forwarded diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 3204cc95aaa..c480d229989 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -8,7 +8,7 @@ import { Event } from 'vs/base/common/event'; export interface IUserData { ref: string; - content: string; + content: string | null; } export enum UserDataSyncStoreErrorCode { @@ -36,7 +36,7 @@ export interface IUserDataSyncStoreService { login(): Promise; logout(): Promise; - read(key: string, oldValue: IUserData | null): Promise; + read(key: string, oldValue: IUserData | null): Promise; write(key: string, content: string, ref: string | null): Promise; } @@ -74,6 +74,6 @@ export interface ISettingsMergeService { _serviceBrand: undefined; - merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{mergeContent: string, hasChanges: boolean, hasConflicts: boolean}>; + merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }>; } diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 83103e414a7..1447ce9be71 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, } from 'vs/base/common/lifecycle'; -import { IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserData, IUserDataSyncStoreService, UserDataSyncStoreErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { IProductService } from 'vs/platform/product/common/productService'; import { Emitter, Event } from 'vs/base/common/event'; -import { IRequestService, asJson, asText } from 'vs/platform/request/common/request'; +import { IRequestService, asText } from 'vs/platform/request/common/request'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -37,31 +37,51 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn async logout(): Promise { } - async read(key: string, oldValue: IUserData | null): Promise { + async read(key: string, oldValue: IUserData | null): Promise { if (!this.enabled) { return Promise.reject(new Error('No settings sync store url configured.')); } + const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); const headers: IHeaders = {}; if (oldValue) { headers['If-None-Match'] = oldValue.ref; } + const context = await this.requestService.request({ type: 'GET', url, headers }, CancellationToken.None); - return asJson(context); + + if (context.res.statusCode === 304) { + // There is no new value. Hence return the old value. + return oldValue!; + } + + const ref = context.res.headers['etag']; + if (!ref) { + throw new Error('Server did not return the ref'); + } + const content = await asText(context); + return { ref, content }; } - async write(key: string, content: string, ref: string | null): Promise { + async write(key: string, data: string, ref: string | null): Promise { if (!this.enabled) { return Promise.reject(new Error('No settings sync store url configured.')); } + const url = joinPath(URI.parse(this.productService.settingsSyncStoreUrl!), key).toString(); - const data = JSON.stringify({ content, ref }); - const headers: IHeaders = { 'Content-Type': 'application/json' }; + const headers: IHeaders = { 'Content-Type': 'text/plain' }; if (ref) { headers['If-Match'] = ref; } + const context = await this.requestService.request({ type: 'POST', url, data, headers }, CancellationToken.None); - const newRef = await asText(context); + + if (context.res.statusCode === 412) { + // There is a new value. Throw Rejected Error + throw new UserDataSyncStoreError('New data exists', UserDataSyncStoreErrorCode.Rejected); + } + + const newRef = context.res.headers['etag']; if (!newRef) { throw new Error('Server did not return the ref'); } From d9ec15cda43b96eff8946bbab0c7890cfb3291f5 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 12:16:09 +0200 Subject: [PATCH 65/82] debt - introduce simple IPC helpers for basic communication forwarding using proxys --- src/vs/base/parts/ipc/common/ipc.ts | 27 ++++++++++++++++- src/vs/code/electron-main/app.ts | 9 +++--- .../electron-browser/electronService.ts | 18 ++--------- .../electron-main/electronMainService.ts | 28 ----------------- .../electron-browser/mainProcessService.ts | 16 ++++++++++ .../issue/electron-browser/issueService.ts | 23 +++----------- .../platform/issue/electron-main/issueIpc.ts | 30 ------------------- 7 files changed, 53 insertions(+), 98 deletions(-) delete mode 100644 src/vs/platform/issue/electron-main/issueIpc.ts diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index e0205092202..cb81bef96bc 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -32,7 +32,6 @@ export interface IServerChannel { listen(ctx: TContext, event: string, arg?: any): Event; } - export const enum RequestType { Promise = 100, PromiseCancel = 101, @@ -833,3 +832,29 @@ export class StaticRouter implements IClientRouter return await this.route(hub); } } + +export class SimpleServiceProxyChannel implements IServerChannel { + + private service: { [key: string]: unknown }; + + constructor(service: unknown) { + this.service = service as { [key: string]: unknown }; + } + + listen(_: unknown, event: string): Event { + throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`); + } + + call(_: unknown, command: string, arg?: any): Promise { + const target = this.service[command]; + if (typeof target === 'function') { + if (Array.isArray(arg)) { + return target.apply(this.service, arg); + } + + return target.call(this.service, arg); + } + + throw new Error(`Call Not Found: ${command}`); + } +} diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 72b1fdc43fb..8f18f8d7915 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -32,7 +32,7 @@ import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; +import { getDelayedChannel, StaticRouter, SimpleServiceProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import product from 'vs/platform/product/common/product'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -45,7 +45,6 @@ import { Win32UpdateService } from 'vs/platform/update/electron-main/updateServi import { LinuxUpdateService } from 'vs/platform/update/electron-main/updateService.linux'; import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateService.darwin'; import { IIssueService } from 'vs/platform/issue/node/issue'; -import { IssueChannel } from 'vs/platform/issue/electron-main/issueIpc'; import { IssueMainService } from 'vs/platform/issue/electron-main/issueMainService'; import { LoggerChannel } from 'vs/platform/log/common/logIpc'; import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/errors'; @@ -77,7 +76,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; import { IElectronService } from 'vs/platform/electron/node/electron'; -import { ElectronMainService, ElectronChannel } from 'vs/platform/electron/electron-main/electronMainService'; +import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; export class CodeApplication extends Disposable { @@ -539,11 +538,11 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel('update', updateChannel); const issueService = accessor.get(IIssueService); - const issueChannel = new IssueChannel(issueService); + const issueChannel = new SimpleServiceProxyChannel(issueService); electronIpcServer.registerChannel('issue', issueChannel); const electronService = accessor.get(IElectronService); - const electronChannel = new ElectronChannel(electronService); + const electronChannel = new SimpleServiceProxyChannel(electronService); electronIpcServer.registerChannel('electron', electronChannel); const workspacesMainService = accessor.get(IWorkspacesMainService); diff --git a/src/vs/platform/electron/electron-browser/electronService.ts b/src/vs/platform/electron/electron-browser/electronService.ts index fa2b5f09b18..3633f642e94 100644 --- a/src/vs/platform/electron/electron-browser/electronService.ts +++ b/src/vs/platform/electron/electron-browser/electronService.ts @@ -3,26 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IMainProcessService, createSimpleMainChannelProxy } from 'vs/platform/ipc/electron-browser/mainProcessService'; export class ElectronService { _serviceBrand: undefined; constructor(@IMainProcessService mainProcessService: IMainProcessService) { - const channel = mainProcessService.getChannel('electron'); - - // Proxy: forward any property access to the channel - return new Proxy({}, { - get(_target, propKey, _receiver) { - if (typeof propKey === 'string') { - return function (...args: any[]) { - return channel.call(propKey, ...args); - }; - } - - throw new Error(`Not Implemented in ElectronService: ${String(propKey)}`); - } - }) as ElectronService; + return createSimpleMainChannelProxy('electron', mainProcessService); } } diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index bcdee9d4a02..1846a5cb086 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -6,8 +6,6 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { MessageBoxOptions, MessageBoxReturnValue, shell } from 'electron'; -import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Event } from 'vs/base/common/event'; export class ElectronMainService implements IElectronService { @@ -35,29 +33,3 @@ export class ElectronMainService implements IElectronService { shell.showItemInFolder(path); } } - -export class ElectronChannel implements IServerChannel { - - private service: { [key: string]: unknown }; - - constructor(service: IElectronService) { - this.service = service as unknown as { [key: string]: unknown }; - } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - const target = this.service[command]; - if (typeof target === 'function') { - if (Array.isArray(arg)) { - return target.apply(this.service, arg); - } - - return target.call(this.service, arg); - } - - throw new Error(`Call Not Found in ElectronService: ${command}`); - } -} diff --git a/src/vs/platform/ipc/electron-browser/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts index c72b1c703d3..ca24035c1e2 100644 --- a/src/vs/platform/ipc/electron-browser/mainProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/mainProcessService.ts @@ -41,3 +41,19 @@ export class MainProcessService extends Disposable implements IMainProcessServic this.mainProcessConnection.registerChannel(channelName, channel); } } + +export function createSimpleMainChannelProxy(channelName: string, mainProcessService: IMainProcessService): T { + const channel = mainProcessService.getChannel(channelName); + + return new Proxy({}, { + get(_target, propKey, _receiver) { + if (typeof propKey === 'string') { + return function (...args: any[]) { + return channel.call(propKey, ...args); + }; + } + + throw new Error(`Unable to provide main channel proxy implementation for: ${String(propKey)} in ${channelName}`); + } + }) as T; +} diff --git a/src/vs/platform/issue/electron-browser/issueService.ts b/src/vs/platform/issue/electron-browser/issueService.ts index 56068fab19e..f7e67b7a3ac 100644 --- a/src/vs/platform/issue/electron-browser/issueService.ts +++ b/src/vs/platform/issue/electron-browser/issueService.ts @@ -3,29 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IIssueService, IssueReporterData, ProcessExplorerData } from 'vs/platform/issue/node/issue'; -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { IIssueService } from 'vs/platform/issue/node/issue'; +import { IMainProcessService, createSimpleMainChannelProxy } from 'vs/platform/ipc/electron-browser/mainProcessService'; -export class IssueService implements IIssueService { +export class IssueService { _serviceBrand: undefined; - private channel: IChannel; - constructor(@IMainProcessService mainProcessService: IMainProcessService) { - this.channel = mainProcessService.getChannel('issue'); - } - - openReporter(data: IssueReporterData): Promise { - return this.channel.call('openIssueReporter', data); - } - - openProcessExplorer(data: ProcessExplorerData): Promise { - return this.channel.call('openProcessExplorer', data); - } - - getSystemStatus(): Promise { - return this.channel.call('getSystemStatus'); + return createSimpleMainChannelProxy('issue', mainProcessService); } } diff --git a/src/vs/platform/issue/electron-main/issueIpc.ts b/src/vs/platform/issue/electron-main/issueIpc.ts deleted file mode 100644 index 271bcf5ceee..00000000000 --- a/src/vs/platform/issue/electron-main/issueIpc.ts +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Event } from 'vs/base/common/event'; -import { IIssueService } from 'vs/platform/issue/node/issue'; - -export class IssueChannel implements IServerChannel { - - constructor(private service: IIssueService) { } - - listen(_: unknown, event: string): Event { - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'openIssueReporter': - return this.service.openReporter(arg); - case 'openProcessExplorer': - return this.service.openProcessExplorer(arg); - case 'getSystemStatus': - return this.service.getSystemStatus(); - } - - throw new Error(`Call not found: ${command}`); - } -} \ No newline at end of file From 7ccfc2dcc5e7b163ff68ee1500112f44f9f92e8e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 12:21:34 +0200 Subject: [PATCH 66/82] remove user data api implementation --- src/vs/vscode.proposed.d.ts | 55 -------- .../api/browser/extensionHost.contribution.ts | 1 - .../api/browser/mainThreadUserData.ts | 48 ------- .../workbench/api/common/extHost.api.impl.ts | 7 - .../workbench/api/common/extHost.protocol.ts | 13 -- src/vs/workbench/api/common/extHostTypes.ts | 24 ---- .../workbench/api/common/extHostUserData.ts | 48 ------- .../userDataSync/common/userDataSyncStores.ts | 128 ------------------ 8 files changed, 324 deletions(-) delete mode 100644 src/vs/workbench/api/browser/mainThreadUserData.ts delete mode 100644 src/vs/workbench/api/common/extHostUserData.ts delete mode 100644 src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 8ca0b13ea65..7dc2a800f64 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1089,59 +1089,4 @@ declare module 'vscode' { } //#endregion - - // #region Sandy - User data synchronization - - export namespace window { - - /** - * Register an [UserDataSyncProvider](#UserDataSyncProvider) to read and write user data. - * @param name Name of the user data sync provider - * @param userDataSyncProvider [UserDataSyncProvider](#UserDataSyncProvider) to read and write user data - */ - export function registerUserDataSyncProvider(name: string, userDataSyncProvider: UserDataSyncProvider): Disposable; - - } - - export class UserDataError extends Error { - - /** - * Create an error to signal that writing user data with given ref is rejected, becase of new ref. - */ - static Rejected(): FileSystemError; - - /** - * Creates a new userData error. - */ - constructor(); - } - - /** - * User data sync provider to read and write user data. - */ - export interface UserDataSyncProvider { - - /** - * Reads the content and its ref for the given key. - * Return null if key does not exists. - * - * @param key key of the content to read - * @returns the content and its ref for the given key. Return null if key does not exists. - */ - read(key: string): Promise<{ content: string, ref: string } | null>; - - /** - * Writes the new content based on the given ref for the given key. - * - * @param key key of the content to write - * @param content new content to write - * @param ref ref of the content on which the content to write is based on - * @throws [Rejected](#UserDataError.Rejected) if the ref is not the latest. - * @returns the latest ref of the content. - */ - write(key: string, content: string, ref: string | null): Promise; - - } - - //#endregion } diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index 3201bfc181d..2905c524113 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -18,7 +18,6 @@ import './mainThreadCodeInsets'; import './mainThreadClipboard'; import './mainThreadCommands'; import './mainThreadConfiguration'; -import './mainThreadUserData'; import './mainThreadConsole'; import './mainThreadDebugService'; import './mainThreadDecorations'; diff --git a/src/vs/workbench/api/browser/mainThreadUserData.ts b/src/vs/workbench/api/browser/mainThreadUserData.ts deleted file mode 100644 index 509f8566752..00000000000 --- a/src/vs/workbench/api/browser/mainThreadUserData.ts +++ /dev/null @@ -1,48 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Disposable } from 'vs/base/common/lifecycle'; -import { MainContext, ExtHostContext, IExtHostContext, MainThreadUserDataShape, ExtHostUserDataShape } from '../common/extHost.protocol'; -import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IUserDataSyncStoresRegistry, Extensions } from 'vs/workbench/services/userDataSync/common/userDataSyncStores'; - -@extHostNamedCustomer(MainContext.MainThreadUserData) -export class MainThreadUserData extends Disposable implements MainThreadUserDataShape { - - private readonly proxy: ExtHostUserDataShape; - - constructor( - extHostContext: IExtHostContext, - ) { - super(); - this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostUserData); - } - - $registerUserDataProvider(id: string, name: string): void { - const proxy = this.proxy; - Registry.as(Extensions.UserDataSyncStoresRegistry).registerUserDataSyncStore({ - id, - name, - read(key: string): Promise { - return proxy.$read(key); - }, - write(key: string, content: string, ref: string): Promise { - return proxy.$write(key, content, ref); - } - }); - } - - $deregisterUserDataProvider(id: string): void { - Registry.as(Extensions.UserDataSyncStoresRegistry).deregisterUserDataSyncStore(id); - } - - dispose(): void { - const registry = Registry.as(Extensions.UserDataSyncStoresRegistry); - registry.all.forEach(store => registry.deregisterUserDataSyncStore(store.id)); - } - -} diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 8eeb8078ea4..417b85c2883 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -68,7 +68,6 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { ExtHostUserData } from 'vs/workbench/api/common/extHostUserData'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -125,7 +124,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol)); const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress))); const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol)); - const extHostUserData = rpcProtocol.set(ExtHostContext.ExtHostUserData, new ExtHostUserData(rpcProtocol.getProxy(MainContext.MainThreadUserData), extHostLogService)); // Check that no named customers are missing const expected: ProxyIdentifier[] = values(ExtHostContext); @@ -545,10 +543,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, createInputBox(): vscode.InputBox { return extHostQuickOpen.createInputBox(extension.identifier); - }, - registerUserDataSyncProvider: (name: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable => { - checkProposedApiEnabled(extension); - return extHostUserData.registerUserDataProvider(extension.identifier.value, name, userDataProvider); } }; @@ -907,7 +901,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall, CallHierarchyItem: extHostTypes.CallHierarchyItem, Decoration: extHostTypes.Decoration, - UserDataError: extHostTypes.UserDataError, WebviewEditorState: extHostTypes.WebviewEditorState, UIKind: UIKind }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 55bcebff44e..c62623e3929 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -46,7 +46,6 @@ import { ExtensionActivationError } from 'vs/workbench/services/extensions/commo import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as search from 'vs/workbench/services/search/common/search'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; -import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; export interface IEnvironment { isExtensionDevelopmentDebug: boolean; @@ -146,11 +145,6 @@ export interface MainThreadConfigurationShape extends IDisposable { $removeConfigurationOption(target: ConfigurationTarget | null, key: string, resource: UriComponents | undefined): Promise; } -export interface MainThreadUserDataShape extends IDisposable { - $registerUserDataProvider(id: string, name: string): void; - $deregisterUserDataProvider(id: string): void; -} - export interface MainThreadDiagnosticsShape extends IDisposable { $changeMany(owner: string, entries: [UriComponents, IMarkerData[] | undefined][]): void; $clear(owner: string): void; @@ -758,11 +752,6 @@ export interface ExtHostConfigurationShape { $acceptConfigurationChanged(data: IConfigurationInitData, eventData: IWorkspaceConfigurationChangeEventData): void; } -export interface ExtHostUserDataShape { - $read(key: string): Promise; - $write(key: string, content: string, ref: string): Promise; -} - export interface ExtHostDiagnosticsShape { $acceptMarkersChange(data: [UriComponents, IMarkerData[]][]): void; } @@ -1336,7 +1325,6 @@ export const MainContext = { MainThreadCommands: createMainId('MainThreadCommands'), MainThreadComments: createMainId('MainThreadComments'), MainThreadConfiguration: createMainId('MainThreadConfiguration'), - MainThreadUserData: createMainId('MainThreadUserData'), MainThreadConsole: createMainId('MainThreadConsole'), MainThreadDebugService: createMainId('MainThreadDebugService'), MainThreadDecorations: createMainId('MainThreadDecorations'), @@ -1376,7 +1364,6 @@ export const MainContext = { export const ExtHostContext = { ExtHostCommands: createExtId('ExtHostCommands'), ExtHostConfiguration: createExtId('ExtHostConfiguration'), - ExtHostUserData: createExtId('ExtHostUserData'), ExtHostDiagnostics: createExtId('ExtHostDiagnostics'), ExtHostDebugService: createExtId('ExtHostDebugService'), ExtHostDecorations: createExtId('ExtHostDecorations'), diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 6462f5b3b9e..f75f09034e7 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -14,8 +14,6 @@ import { generateUuid } from 'vs/base/common/uuid'; import * as vscode from 'vscode'; import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files'; import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { UserDataSyncStoreErrorCode } from 'vs/platform/userDataSync/common/userDataSync'; -import { markAsUserDataSyncStoreError } from 'vs/workbench/services/userDataSync/common/userDataSyncStores'; function es5ClassCompat(target: Function): any { ///@ts-ignore @@ -2385,28 +2383,6 @@ export class Decoration { bubble?: boolean; } -@es5ClassCompat -export class UserDataError extends Error { - - static Rejected(message?: string): UserDataError { - return new UserDataError(message, UserDataSyncStoreErrorCode.Rejected); - } - - constructor(message?: string, code: UserDataSyncStoreErrorCode = UserDataSyncStoreErrorCode.Unknown) { - super(message); - - // mark the error as user data provider error so that - // we can extract the error code on the receiving side - markAsUserDataSyncStoreError(this, code); - - // workaround when extending builtin objects and when compiling to ES5, see: - // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work - if (typeof (Object).setPrototypeOf === 'function') { - (Object).setPrototypeOf(this, UserDataError.prototype); - } - } -} - export enum WebviewEditorState { Readonly = 1, Unchanged = 2, diff --git a/src/vs/workbench/api/common/extHostUserData.ts b/src/vs/workbench/api/common/extHostUserData.ts deleted file mode 100644 index de5e565f7cb..00000000000 --- a/src/vs/workbench/api/common/extHostUserData.ts +++ /dev/null @@ -1,48 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ExtHostUserDataShape, MainThreadUserDataShape } from './extHost.protocol'; -import * as vscode from 'vscode'; -import { toDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IUserData } from 'vs/platform/userDataSync/common/userDataSync'; - -export class ExtHostUserData implements ExtHostUserDataShape { - - private name: string | null = null; - private userDataProvider: vscode.UserDataSyncProvider | null = null; - - constructor( - private readonly proxy: MainThreadUserDataShape, - private readonly logService: ILogService, - ) { - } - - registerUserDataProvider(id: string, name: string, userDataProvider: vscode.UserDataSyncProvider): vscode.Disposable { - if (this.userDataProvider) { - this.logService.warn(`A user data provider '${this.name}' already exists hence ignoring the remote user data provider '${name}'.`); - return Disposable.None; - } - this.userDataProvider = userDataProvider; - this.name = name; - this.proxy.$registerUserDataProvider(id, name); - return toDisposable(() => this.proxy.$deregisterUserDataProvider(id)); - } - - $read(key: string): Promise { - if (!this.userDataProvider) { - throw new Error('No remote user data provider exists.'); - } - return this.userDataProvider.read(key); - } - - $write(key: string, content: string, ref: string): Promise { - if (!this.userDataProvider) { - throw new Error('No remote user data provider exists.'); - } - return this.userDataProvider.write(key, content, ref); - } - -} diff --git a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts b/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts deleted file mode 100644 index cd83212d09b..00000000000 --- a/src/vs/workbench/services/userDataSync/common/userDataSyncStores.ts +++ /dev/null @@ -1,128 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event, Emitter } from 'vs/base/common/event'; -import { IUserData, UserDataSyncStoreErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { values } from 'vs/base/common/map'; -import { Registry } from 'vs/platform/registry/common/platform'; - -export function markAsUserDataSyncStoreError(error: Error, code: UserDataSyncStoreErrorCode): Error { - error.name = code ? `${code} (UserDataSyncStoreError)` : `UserDataSyncStoreError`; - - return error; -} - -export function toUserDataSyncStoreErrorCode(error: Error | undefined | null): UserDataSyncStoreErrorCode { - - // Guard against abuse - if (!error) { - return UserDataSyncStoreErrorCode.Unknown; - } - - // FileSystemProviderError comes with the code - if (error instanceof UserDataSyncStoreError) { - return error.code; - } - - // Any other error, check for name match by assuming that the error - // went through the markAsUserDataSyncStoreError() method - const match = /^(.+) \(UserDataSyncStoreError\)$/.exec(error.name); - if (!match) { - return UserDataSyncStoreErrorCode.Unknown; - } - - switch (match[1]) { - case UserDataSyncStoreErrorCode.Rejected: return UserDataSyncStoreErrorCode.Rejected; - } - - return UserDataSyncStoreErrorCode.Unknown; -} - -export interface IUserDataSyncStore { - readonly id: string; - readonly name: string; - read(key: string): Promise; - write(key: string, content: string, ref: string | null): Promise; -} - -export namespace Extensions { - export const UserDataSyncStoresRegistry = 'workbench.registry.userData.syncStores'; -} - -export interface IUserDataSyncStoresRegistry { - /** - * An event that is triggerred when a user data sync store is registered. - */ - readonly onDidRegister: Event; - - /** - * An event that is triggerred when a user data sync store is deregistered. - */ - readonly onDidDeregister: Event; - - /** - * All registered user data sync stores - */ - readonly all: IUserDataSyncStore[]; - - /** - * Registers a user data sync store - * - * @param userDataSyncStore to register - */ - registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void; - - /** - * Deregisters the user data sync store with given id - */ - deregisterUserDataSyncStore(id: string): void; - - /** - * Returns the user data sync store with given id. - * - * @returns the user data sync store with given id. - */ - get(id: string): IUserDataSyncStore | undefined; -} - -class UserDataSyncStoresRegistryImpl extends Disposable implements IUserDataSyncStoresRegistry { - - private readonly _onDidRegister = this._register(new Emitter()); - readonly onDidRegister: Event = this._onDidRegister.event; - - private readonly _onDidDeregister = this._register(new Emitter()); - readonly onDidDeregister: Event = this._onDidDeregister.event; - - private userDataSyncStores: Map = new Map(); - - get all(): IUserDataSyncStore[] { - return values(this.userDataSyncStores); - } - - registerUserDataSyncStore(userDataSyncStore: IUserDataSyncStore): void { - const existing = this.userDataSyncStores.get(userDataSyncStore.id); - if (existing) { - return; - } - - this.userDataSyncStores.set(userDataSyncStore.id, userDataSyncStore); - this._onDidRegister.fire(userDataSyncStore); - } - - deregisterUserDataSyncStore(id: string): void { - const existing = this.userDataSyncStores.get(id); - if (existing) { - this.userDataSyncStores.delete(id); - this._onDidDeregister.fire(id); - } - } - - get(id: string): IUserDataSyncStore | undefined { - return this.userDataSyncStores.get(id); - } -} - -Registry.add(Extensions.UserDataSyncStoresRegistry, new UserDataSyncStoresRegistryImpl()); From 7f182c40a991d22e64be500663522b3e0d9ea71f Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Sep 2019 12:34:19 +0200 Subject: [PATCH 67/82] debug brekpoints: polish inline breakpoint decorations --- .../browser/breakpointEditorContribution.ts | 20 +++++++++---------- .../contrib/debug/browser/debugSession.ts | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 4515fd4dfdd..d905e63ad14 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -68,7 +68,7 @@ async function createCandidateDecorations(model: ITextModel, lineNumbers: number const result: { range: Range; options: IModelDecorationOptions; }[] = []; const session = debugService.getViewModel().focusedSession; if (session && session.capabilities.supportsBreakpointLocationsRequest) { - lineNumbers.forEach(async lineNumber => { + await Promise.all(lineNumbers.map(async lineNumber => { const positions = await session.breakpointsLocations(model.uri, lineNumber); positions.forEach(p => { result.push({ @@ -79,7 +79,7 @@ async function createCandidateDecorations(model: ITextModel, lineNumbers: number } }); }); - }); + })); } return result; @@ -114,7 +114,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { private breakpointWidgetVisible: IContextKey; private toDispose: IDisposable[] = []; private ignoreDecorationsChangedEvent = false; - private ignoreFirstBreakpointsChangeEvent = false; + private ignoreBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; private candidateDecoraions: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = []; @@ -222,11 +222,9 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { await this.setDecorations(); })); this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => { - if (this.ignoreFirstBreakpointsChangeEvent) { - this.ignoreFirstBreakpointsChangeEvent = false; - return; + if (!this.ignoreBreakpointsChangeEvent) { + await this.setDecorations(); } - await this.setDecorations(); })); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); } @@ -298,7 +296,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { nls.localize('addLogPoint', "Add Logpoint..."), undefined, true, - () => Promise.resolve(this.showBreakpointWidget(lineNumber, BreakpointWidgetContext.LOG_MESSAGE)) + () => Promise.resolve(this.showBreakpointWidget(lineNumber, column, BreakpointWidgetContext.LOG_MESSAGE)) )); } @@ -378,7 +376,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { const lineNumbers = distinct(this.breakpointDecorations.map(bpd => bpd.range.startLineNumber)); let desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), lineNumbers, this.debugService); desiredCandidateDecorations = desiredCandidateDecorations.filter(dbd => { - const breakpointDecorationAlreadyAtCandidateLocation = this.breakpointDecorations.filter(bd => bd.range.equalsRange(dbd.range)).length >= 0; + const breakpointDecorationAlreadyAtCandidateLocation = this.breakpointDecorations.filter(bd => bd.range.equalsRange(dbd.range)).length > 0; return !breakpointDecorationAlreadyAtCandidateLocation; }); const candidateDecorationids = this.editor.deltaDecorations(this.candidateDecoraions.map(c => c.decorationId), desiredCandidateDecorations); @@ -436,10 +434,10 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } try { - this.ignoreFirstBreakpointsChangeEvent = true; + this.ignoreBreakpointsChangeEvent = true; await this.debugService.updateBreakpoints(model.uri, data, true); } finally { - this.ignoreFirstBreakpointsChangeEvent = false; + this.ignoreBreakpointsChangeEvent = false; } } diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 0f53246d206..928e9d322ed 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -376,7 +376,7 @@ export class DebugSession implements IDebugSession { const response = await this.raw.breakpointLocations({ source, line: lineNumber }); const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 })); - return distinct(positions, p => p.toString()); + return distinct(positions, p => `${p.lineNumber}:${p.column}`); } return Promise.reject(new Error('no debug adapter')); } From 1e1021685619cf2c66554e05f52831cefd0f026c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 18 Sep 2019 12:37:21 +0200 Subject: [PATCH 68/82] trigger sync after closing the conflicts editor --- build/lib/i18n.resources.json | 4 ++++ .../browser/userDataSync.contribution.ts | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index e8301efbeca..1987d5ca9c0 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -186,6 +186,10 @@ "name": "vs/workbench/contrib/outline", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/userDataSync", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/actions", "project": "vscode-workbench" diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts index b3c153261d4..df9bc5323a5 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts @@ -153,7 +153,17 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi }, mode: 'jsonc' }; - this.editorService.openEditor(resourceInput).then(() => this.historyService.remove(resourceInput)); + this.editorService.openEditor(resourceInput) + .then(editor => { + this.historyService.remove(resourceInput); + if (editor && editor.input) { + // Trigger sync after closing the conflicts editor. + const disposable = editor.input.onDispose(() => { + disposable.dispose(); + this.userDataSyncService.sync(true); + }); + } + }); } } From a0e65a532d668d0cb96cf8e4815431ddc42e0c6f Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Sep 2019 12:57:34 +0200 Subject: [PATCH 69/82] breakpoints: update decorations with a minor timeout to react once to multiple nearby events --- .../contrib/debug/browser/breakpointEditorContribution.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index d905e63ad14..29030b4537b 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -29,6 +29,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { memoize } from 'vs/base/common/decorators'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { distinct } from 'vs/base/common/arrays'; +import { RunOnceScheduler } from 'vs/base/common/async'; const $ = dom.$; @@ -117,6 +118,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { private ignoreBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; private candidateDecoraions: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = []; + private setDecorationsScheduler: RunOnceScheduler; constructor( private readonly editor: ICodeEditor, @@ -128,6 +130,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { ) { this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); this.registerListeners(); + this.setDecorationsScheduler = new RunOnceScheduler(() => this.setDecorations(), 30); } getId(): string { @@ -222,8 +225,8 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { await this.setDecorations(); })); this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => { - if (!this.ignoreBreakpointsChangeEvent) { - await this.setDecorations(); + if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) { + this.setDecorationsScheduler.schedule(); } })); this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged())); From c3d611c7ad601dbf095cc8e7ad8f9a0ec43c879d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 13:05:38 +0200 Subject: [PATCH 70/82] debt - introduce and use simpleIpcProxy --- src/vs/base/parts/ipc/common/ipc.ts | 26 ---------- src/vs/code/electron-main/app.ts | 3 +- .../electron-browser/electronService.ts | 5 +- .../electron-browser/mainProcessService.ts | 16 ------- src/vs/platform/ipc/node/simpleIpcProxy.ts | 48 +++++++++++++++++++ .../issue/electron-browser/issueService.ts | 5 +- 6 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 src/vs/platform/ipc/node/simpleIpcProxy.ts diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index cb81bef96bc..392cfeaeae7 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -832,29 +832,3 @@ export class StaticRouter implements IClientRouter return await this.route(hub); } } - -export class SimpleServiceProxyChannel implements IServerChannel { - - private service: { [key: string]: unknown }; - - constructor(service: unknown) { - this.service = service as { [key: string]: unknown }; - } - - listen(_: unknown, event: string): Event { - throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - const target = this.service[command]; - if (typeof target === 'function') { - if (Array.isArray(arg)) { - return target.apply(this.service, arg); - } - - return target.call(this.service, arg); - } - - throw new Error(`Call Not Found: ${command}`); - } -} diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 8f18f8d7915..e7eac8d5f3d 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -32,7 +32,8 @@ import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { getDelayedChannel, StaticRouter, SimpleServiceProxyChannel } from 'vs/base/parts/ipc/common/ipc'; +import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; +import { SimpleServiceProxyChannel } from 'vs/platform/ipc/node/simpleIpcProxy'; import product from 'vs/platform/product/common/product'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; import { Disposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/platform/electron/electron-browser/electronService.ts b/src/vs/platform/electron/electron-browser/electronService.ts index 3633f642e94..0a88c90efc5 100644 --- a/src/vs/platform/electron/electron-browser/electronService.ts +++ b/src/vs/platform/electron/electron-browser/electronService.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IElectronService } from 'vs/platform/electron/node/electron'; -import { IMainProcessService, createSimpleMainChannelProxy } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; export class ElectronService { _serviceBrand: undefined; constructor(@IMainProcessService mainProcessService: IMainProcessService) { - return createSimpleMainChannelProxy('electron', mainProcessService); + return createSimpleChannelProxy(mainProcessService.getChannel('electron')); } } diff --git a/src/vs/platform/ipc/electron-browser/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts index ca24035c1e2..c72b1c703d3 100644 --- a/src/vs/platform/ipc/electron-browser/mainProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/mainProcessService.ts @@ -41,19 +41,3 @@ export class MainProcessService extends Disposable implements IMainProcessServic this.mainProcessConnection.registerChannel(channelName, channel); } } - -export function createSimpleMainChannelProxy(channelName: string, mainProcessService: IMainProcessService): T { - const channel = mainProcessService.getChannel(channelName); - - return new Proxy({}, { - get(_target, propKey, _receiver) { - if (typeof propKey === 'string') { - return function (...args: any[]) { - return channel.call(propKey, ...args); - }; - } - - throw new Error(`Unable to provide main channel proxy implementation for: ${String(propKey)} in ${channelName}`); - } - }) as T; -} diff --git a/src/vs/platform/ipc/node/simpleIpcProxy.ts b/src/vs/platform/ipc/node/simpleIpcProxy.ts new file mode 100644 index 00000000000..43e4cdbc31f --- /dev/null +++ b/src/vs/platform/ipc/node/simpleIpcProxy.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; + +// +// Use both `SimpleServiceProxyChannel` and `createSimpleChannelProxy` +// for a very basic process <=> process communication over methods. +// + +export class SimpleServiceProxyChannel implements IServerChannel { + + private service: { [key: string]: unknown }; + + constructor(service: unknown) { + this.service = service as { [key: string]: unknown }; + } + + listen(_: unknown, event: string): Event { + throw new Error(`Events are currently unsupported by SimpleServiceProxyChannel: ${event}`); + } + + call(_: unknown, command: string, args: any[]): Promise { + const target = this.service[command]; + if (typeof target === 'function') { + return target.apply(this.service, args); + } + + throw new Error(`Method not found: ${command}`); + } +} + +export function createSimpleChannelProxy(channel: IChannel): T { + return new Proxy({}, { + get(_target, propKey, _receiver) { + if (typeof propKey === 'string') { + return function (...args: any[]) { + return channel.call(propKey, args); + }; + } + + throw new Error(`Unable to provide main channel proxy implementation for: ${String(propKey)}`); + } + }) as T; +} diff --git a/src/vs/platform/issue/electron-browser/issueService.ts b/src/vs/platform/issue/electron-browser/issueService.ts index f7e67b7a3ac..72502019070 100644 --- a/src/vs/platform/issue/electron-browser/issueService.ts +++ b/src/vs/platform/issue/electron-browser/issueService.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { IIssueService } from 'vs/platform/issue/node/issue'; -import { IMainProcessService, createSimpleMainChannelProxy } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; export class IssueService { _serviceBrand: undefined; constructor(@IMainProcessService mainProcessService: IMainProcessService) { - return createSimpleMainChannelProxy('issue', mainProcessService); + return createSimpleChannelProxy(mainProcessService.getChannel('issue')); } } From afde7913ebfba84852df795bfae33f6609843a97 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 13:55:03 +0200 Subject: [PATCH 71/82] build - set no-sandbox everywhere (#81096) --- build/azure-pipelines/linux/product-build-linux.yml | 2 +- resources/linux/code-url-handler.desktop | 2 +- resources/linux/code.desktop | 4 ++-- scripts/test-integration.sh | 4 ++-- scripts/test.sh | 2 +- src/vs/code/node/cli.ts | 6 +++++- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 0d0b2608757..0d01ba8a608 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -100,7 +100,7 @@ steps: - script: | set -e - DISPLAY=:10 ./scripts/test.sh --build --tfs --no-sandbox "Unit Tests" + DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" displayName: Run unit tests condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) diff --git a/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop index 7106e0e0969..b85525fbd04 100644 --- a/resources/linux/code-url-handler.desktop +++ b/resources/linux/code-url-handler.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ - URL Handler Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=@@EXEC@@ --open-url %U +Exec=@@EXEC@@ --no-sandbox --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 1273bb2db7c..b975e1094a2 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=@@EXEC@@ --unity-launch %F +Exec=@@EXEC@@ --no-sandbox --unity-launch %F Icon=@@ICON@@ Type=Application StartupNotify=false @@ -14,5 +14,5 @@ Keywords=vscode; [Desktop Action new-empty-window] Name=New Empty Window -Exec=@@EXEC@@ --new-window %F +Exec=@@EXEC@@ --no-sandbox --new-window %F Icon=@@ICON@@ diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 143e2ff4eb4..2c3a571ffc7 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -8,7 +8,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then else ROOT=$(dirname $(dirname $(readlink -f $0))) VSCODEUSERDATADIR=`mktemp -d 2>/dev/null` - LINUX_NO_SANDBOX="--no-sandbox" # workaround Electron 6 issue on Linux when running tests in container + LINUX_NO_SANDBOX="--no-sandbox" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. fi cd $ROOT @@ -34,7 +34,7 @@ else fi # Integration tests in AMD -./scripts/test.sh $LINUX_NO_SANDBOX --runGlob **/*.integrationTest.js "$@" +./scripts/test.sh --runGlob **/*.integrationTest.js "$@" # Tests in the extension host "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR diff --git a/scripts/test.sh b/scripts/test.sh index e1ed5aa65c7..630af4e53e5 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -34,5 +34,5 @@ else cd $ROOT ; \ ELECTRON_ENABLE_LOGGING=1 \ "$CODE" \ - test/electron/index.js "$@" + test/electron/index.js --no-sandbox "$@" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. fi diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 84997b65040..6dc1c356bac 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -15,7 +15,7 @@ import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { resolveTerminalEncoding } from 'vs/base/node/encoding'; import * as iconv from 'iconv-lite'; -import { isWindows } from 'vs/base/common/platform'; +import { isWindows, isLinux } from 'vs/base/common/platform'; import { ProfilingSession, Target } from 'v8-inspect-profiler'; import { isString } from 'vs/base/common/types'; @@ -360,6 +360,10 @@ export async function main(argv: string[]): Promise { options['stdio'] = 'ignore'; } + if (isLinux) { + addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox + } + const child = spawn(process.execPath, argv.slice(2), options); if (args.wait && waitMarkerFilePath) { From fb7991a3fd5392e3f3abb5d2f5fd7e5a89ab4445 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 15:03:24 +0200 Subject: [PATCH 72/82] debt - bring back macOS custom title menu --- src/vs/platform/actions/common/actions.ts | 1 + .../browser/parts/titlebar/titlebarPart.ts | 82 +++++-------------- src/vs/workbench/electron-browser/window.ts | 50 ++++++++++- .../services/title/common/titleService.ts | 3 +- 4 files changed, 73 insertions(+), 63 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 7a409b98a5e..c7bcd9b066c 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -93,6 +93,7 @@ export const enum MenuId { SearchContext, StatusBarWindowIndicatorMenu, TouchBarContext, + TitleBarContext, ViewItemContext, ViewTitle, CommentThreadTitle, diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index f222733af9d..394f522bd67 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -4,18 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/titlebarpart'; -import { dirname, posix } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; import { Part } from 'vs/workbench/browser/part'; import { ITitleService, ITitleProperties } from 'vs/workbench/services/title/common/titleService'; import { getZoomFactor } from 'vs/base/browser/browser'; -import { IWindowService, IWindowsService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IAction, Action } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore, dispose } from 'vs/base/common/lifecycle'; import * as nls from 'vs/nls'; import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workbench/common/editor'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -29,7 +28,7 @@ import { trim } from 'vs/base/common/strings'; import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { template, getBaseLabel } from 'vs/base/common/labels'; +import { template } from 'vs/base/common/labels'; import { ILabelService } from 'vs/platform/label/common/label'; import { Event, Emitter } from 'vs/base/common/event'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -37,6 +36,9 @@ import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/bro import { RunOnceScheduler } from 'vs/base/common/async'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Schemas } from 'vs/base/common/network'; +import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export class TitlebarPart extends Part implements ITitleService { @@ -71,7 +73,6 @@ export class TitlebarPart extends Part implements ITitleService { private lastLayoutDimensions: Dimension; private pendingTitle: string; - private representedFileName: string; private isInactive: boolean; @@ -80,11 +81,12 @@ export class TitlebarPart extends Part implements ITitleService { private titleUpdater: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.doUpdateTitle(), 0)); + private contextMenu: IMenu; + constructor( @IContextMenuService private readonly contextMenuService: IContextMenuService, @IWindowService private readonly windowService: IWindowService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IWindowsService private readonly windowsService: IWindowsService, @IEditorService private readonly editorService: IEditorService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -92,10 +94,14 @@ export class TitlebarPart extends Part implements ITitleService { @IThemeService themeService: IThemeService, @ILabelService private readonly labelService: ILabelService, @IStorageService storageService: IStorageService, - @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService ) { super(Parts.TITLEBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); + this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService)); + this.registerListeners(); } @@ -181,9 +187,6 @@ export class TitlebarPart extends Part implements ITitleService { // Apply to window this.windowService.setRepresentedFilename(path); - - // Keep for context menu - this.representedFileName = path; } private doUpdateTitle(): void { @@ -502,44 +505,16 @@ export class TitlebarPart extends Part implements ITitleService { const event = new StandardMouseEvent(e); const anchor = { x: event.posx, y: event.posy }; - // Show menu - const actions = this.getContextMenuActions(); - if (actions.length) { - this.contextMenuService.showContextMenu({ - getAnchor: () => anchor, - getActions: () => actions, - onHide: () => actions.forEach(a => a.dispose()) - }); - } - } - - private getContextMenuActions(): IAction[] { + // Fill in contributed actions const actions: IAction[] = []; + const actionsDisposable = createAndFillInContextMenuActions(this.contextMenu, undefined, actions, this.contextMenuService); - if (this.representedFileName) { - const segments = this.representedFileName.split(posix.sep); - for (let i = segments.length; i > 0; i--) { - const isFile = (i === segments.length); - - let pathOffset = i; - if (!isFile) { - pathOffset++; // for segments which are not the file name we want to open the folder - } - - const path = segments.slice(0, pathOffset).join(posix.sep); - - let label: string; - if (!isFile) { - label = getBaseLabel(dirname(path)); - } else { - label = getBaseLabel(path); - } - - actions.push(new ShowItemInFolderAction(path, label || posix.sep, this.windowsService)); - } - } - - return actions; + // Show it + this.contextMenuService.showContextMenu({ + getAnchor: () => anchor, + getActions: () => actions, + onHide: () => dispose(actionsDisposable) + }); } private adjustTitleMarginToCenter(): void { @@ -604,19 +579,6 @@ export class TitlebarPart extends Part implements ITitleService { } } -class ShowItemInFolderAction extends Action { - - constructor(private path: string, label: string, private windowsService: IWindowsService) { - super('showItemInFolder.action.id', label); - } - - run(): Promise { - if (this.path && this.windowsService) { } - return Promise.resolve(); - // return this.windowsService.showItemInFolder(URI.file(this.path)); - } -} - registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const titlebarActiveFg = theme.getColor(TITLE_BAR_ACTIVE_FOREGROUND); if (titlebarActiveFg) { diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 80eadd8163a..31cb64f2d5b 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -19,12 +19,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as browser from 'vs/base/browser/browser'; -import { ICommandService } from 'vs/platform/commands/common/commands'; +import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction, SubmenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -56,6 +56,8 @@ import { withNullAsUndefined } from 'vs/base/common/types'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { Schemas } from 'vs/base/common/network'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { posix, dirname } from 'vs/base/common/path'; +import { getBaseLabel } from 'vs/base/common/labels'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -74,6 +76,8 @@ export class ElectronWindow extends Disposable { private readonly touchBarDisposables = this._register(new DisposableStore()); private lastInstalledTouchedBar: ICommandAction[][] | undefined; + private customTitleContextMenuDisposable = this._register(new DisposableStore()); + private previousConfiguredZoomLevel: number | undefined; private addFoldersScheduler: RunOnceScheduler; @@ -245,6 +249,11 @@ export class ElectronWindow extends Disposable { this._register(this.trackClosedWaitFiles(waitMarkerFile, resourcesToWaitFor)); } + + // macOS custom title menu + if (isMacintosh) { + this._register(this.editorService.onDidActiveEditorChange(() => this.provideCustomTitleContextMenu())); + } } private onDidVisibleEditorsChange(): void { @@ -308,6 +317,43 @@ export class ElectronWindow extends Disposable { } } + private provideCustomTitleContextMenu(): void { + + // Clear old menu + this.customTitleContextMenuDisposable.clear(); + + // Provide new menu if a file is opened and we are on a custom title + const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.file }); + if (!fileResource || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') { + return; + } + + // Split up filepath into segments + const filePath = fileResource.fsPath; + const segments = filePath.split(posix.sep); + for (let i = segments.length; i > 0; i--) { + const isFile = (i === segments.length); + + let pathOffset = i; + if (!isFile) { + pathOffset++; // for segments which are not the file name we want to open the folder + } + + const path = segments.slice(0, pathOffset).join(posix.sep); + + let label: string; + if (!isFile) { + label = getBaseLabel(dirname(path)); + } else { + label = getBaseLabel(path); + } + + const commandId = `workbench.action.revealPathInFinder${i}`; + this.customTitleContextMenuDisposable.add(CommandsRegistry.registerCommand(commandId, () => this.electronService.showItemInFolder(path))); + this.customTitleContextMenuDisposable.add(MenuRegistry.appendMenuItem(MenuId.TitleBarContext, { command: { id: commandId, title: label || posix.sep }, order: -i })); + } + } + private create(): void { // Native menu controller diff --git a/src/vs/workbench/services/title/common/titleService.ts b/src/vs/workbench/services/title/common/titleService.ts index b3476f94deb..a827857a797 100644 --- a/src/vs/workbench/services/title/common/titleService.ts +++ b/src/vs/workbench/services/title/common/titleService.ts @@ -14,6 +14,7 @@ export interface ITitleProperties { } export interface ITitleService { + _serviceBrand: undefined; /** @@ -25,4 +26,4 @@ export interface ITitleService { * Update some environmental title properties. */ updateProperties(properties: ITitleProperties): void; -} \ No newline at end of file +} From 6789fa221879a840690f1cc66feaed6b47b444ed Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 18 Sep 2019 06:08:07 -0700 Subject: [PATCH 73/82] Make .icon inline-block --- src/vs/base/browser/ui/actionbar/actionbar.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 08b4920ae47..f2eff2c7f66 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -40,6 +40,7 @@ transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */ } +.monaco-action-bar .action-item .icon, .monaco-action-bar .action-item .codicon { display: inline-block; } From bcaf8121316794c17e38c07682899c3dfbfadb6d Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Sep 2019 16:27:01 +0200 Subject: [PATCH 74/82] breakpoints: make the candidate breakpoints look more clickable --- .../contrib/debug/browser/media/debug.contribution.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 69be074454c..08d90c5579a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -21,6 +21,10 @@ background: url('breakpoint-disabled.svg') center center no-repeat; } +.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled:hover { + background: url('breakpoint-hint.svg') center center no-repeat; +} + .debug-breakpoint-unverified, .monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified { background: url('breakpoint-unverified.svg') center center no-repeat; @@ -57,6 +61,7 @@ width: 1.3em; height: 1.3em; margin-left: 0.61em; + cursor: pointer; } .debug-function-breakpoint { From 6a54c8176fd60745ad7f2ba9dc89af4631752bae Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 18 Sep 2019 07:51:50 -0700 Subject: [PATCH 75/82] Update action label classes --- src/vs/base/browser/ui/splitview/panelview.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css index d4def58461f..194ef683029 100644 --- a/src/vs/base/browser/ui/splitview/panelview.css +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -68,7 +68,8 @@ } /* TODO: actions should be part of the panel, but they aren't yet */ -.monaco-panel-view .panel > .panel-header > .actions .action-label.icon { +.monaco-panel-view .panel > .panel-header > .actions .action-label.icon, +.monaco-panel-view .panel > .panel-header > .actions .action-label.codicon { width: 28px; height: 22px; background-size: 16px; From 9c85ca3757812664246e009403320ea54bbdd89c Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 18 Sep 2019 18:00:52 +0200 Subject: [PATCH 76/82] breakpoint inline candidate polish --- .../browser/breakpointEditorContribution.ts | 87 ++++++++++--------- .../browser/media/debug.contribution.css | 4 + 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 29030b4537b..fda9ec6e6ea 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -35,7 +35,7 @@ const $ = dom.$; interface IBreakpointDecoration { decorationId: string; - breakpointId: string; + breakpoint: IBreakpoint; range: Range; inlineWidget?: InlineBreakpointWidget; } @@ -65,28 +65,6 @@ function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArr return result; } -async function createCandidateDecorations(model: ITextModel, lineNumbers: number[], debugService: IDebugService): Promise<{ range: Range; options: IModelDecorationOptions; }[]> { - const result: { range: Range; options: IModelDecorationOptions; }[] = []; - const session = debugService.getViewModel().focusedSession; - if (session && session.capabilities.supportsBreakpointLocationsRequest) { - await Promise.all(lineNumbers.map(async lineNumber => { - const positions = await session.breakpointsLocations(model.uri, lineNumber); - positions.forEach(p => { - result.push({ - range: new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1), - options: { - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - beforeContentClassName: `debug-breakpoint-placeholder` - } - }); - }); - })); - } - - return result; -} - - function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService): IModelDecorationOptions { const { className, message } = getBreakpointMessageAndClassName(debugService, breakpoint); let glyphMarginHoverMessage: MarkdownString | undefined; @@ -108,6 +86,39 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi }; } +async function createCandidateDecorations(model: ITextModel, breakpointDecorations: IBreakpointDecoration[], debugService: IDebugService): Promise<{ range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[]> { + const lineNumbers = distinct(breakpointDecorations.map(bpd => bpd.range.startLineNumber)); + const result: { range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[] = []; + const session = debugService.getViewModel().focusedSession; + if (session && session.capabilities.supportsBreakpointLocationsRequest) { + await Promise.all(lineNumbers.map(async lineNumber => { + const positions = await session.breakpointsLocations(model.uri, lineNumber); + if (positions.length > 1) { + // Do not render candidates if there is only one, since it is already covered by the line breakpoint + positions.forEach(p => { + const range = new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1); + const breakpointAtPosition = breakpointDecorations.filter(bpd => bpd.range.equalsRange(range)).pop(); + if (breakpointAtPosition && breakpointAtPosition.inlineWidget) { + // Space already occupied, do not render candidate. + return; + } + result.push({ + range, + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + beforeContentClassName: `debug-breakpoint-placeholder` + }, + breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined + }); + }); + } + })); + } + + return result; +} + + class BreakpointEditorContribution implements IBreakpointEditorContribution { private breakpointHintDecoration: string[] = []; @@ -117,7 +128,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { private ignoreDecorationsChangedEvent = false; private ignoreBreakpointsChangeEvent = false; private breakpointDecorations: IBreakpointDecoration[] = []; - private candidateDecoraions: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = []; + private candidateDecorations: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = []; private setDecorationsScheduler: RunOnceScheduler; constructor( @@ -365,7 +376,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { return { decorationId, - breakpointId: breakpoint.getId(), + breakpoint, range: desiredBreakpointDecorations[index].range, inlineWidget }; @@ -376,19 +387,15 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } // Set breakpoint candidate decorations - const lineNumbers = distinct(this.breakpointDecorations.map(bpd => bpd.range.startLineNumber)); - let desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), lineNumbers, this.debugService); - desiredCandidateDecorations = desiredCandidateDecorations.filter(dbd => { - const breakpointDecorationAlreadyAtCandidateLocation = this.breakpointDecorations.filter(bd => bd.range.equalsRange(dbd.range)).length > 0; - return !breakpointDecorationAlreadyAtCandidateLocation; - }); - const candidateDecorationids = this.editor.deltaDecorations(this.candidateDecoraions.map(c => c.decorationId), desiredCandidateDecorations); - this.candidateDecoraions.forEach(candidate => { + const desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), this.breakpointDecorations, this.debugService); + const candidateDecorationIds = this.editor.deltaDecorations(this.candidateDecorations.map(c => c.decorationId), desiredCandidateDecorations); + this.candidateDecorations.forEach(candidate => { candidate.inlineWidget.dispose(); }); - this.candidateDecoraions = candidateDecorationids.map((decorationId, index) => { + this.candidateDecorations = candidateDecorationIds.map((decorationId, index) => { const candidate = desiredCandidateDecorations[index]; - const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, 'debug-breakpoint-disabled', undefined, this.debugService, this.contextMenuService, () => this.getContextMenuActions([], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn)); + const cssClass = candidate.breakpoint ? undefined : 'debug-breakpoint-disabled'; + const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn)); return { decorationId, @@ -419,18 +426,16 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution { } const data = new Map(); - const breakpoints = this.debugService.getModel().getBreakpoints(); for (let i = 0, len = this.breakpointDecorations.length; i < len; i++) { const breakpointDecoration = this.breakpointDecorations[i]; const decorationRange = model.getDecorationRange(breakpointDecoration.decorationId); // check if the line got deleted. if (decorationRange) { - const breakpoint = breakpoints.filter(bp => bp.getId() === breakpointDecoration.breakpointId).pop(); // since we know it is collapsed, it cannot grow to multiple lines - if (breakpoint) { - data.set(breakpoint.getId(), { + if (breakpointDecoration.breakpoint) { + data.set(breakpointDecoration.breakpoint.getId(), { lineNumber: decorationRange.startLineNumber, - column: breakpoint.column ? decorationRange.startColumn : undefined, + column: breakpointDecoration.breakpoint.column ? decorationRange.startColumn : undefined, }); } } @@ -544,6 +549,8 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable { if (!this.range) { return null; } + // Workaround: since the content widget can not be placed before the first column we need to force the left position + dom.toggleClass(this.domNode, 'line-start', this.range.startColumn === 1); return { position: { lineNumber: this.range.startLineNumber, column: this.range.startColumn - 1 }, diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 08d90c5579a..4576abcbe9a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -25,6 +25,10 @@ background: url('breakpoint-hint.svg') center center no-repeat; } +.monaco-editor .inline-breakpoint-widget.line-start { + left: -0.45em !important; +} + .debug-breakpoint-unverified, .monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified { background: url('breakpoint-unverified.svg') center center no-repeat; From b5a0ab0c94057eca2df3969306d94eac619f8eb4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 19:01:59 +0200 Subject: [PATCH 77/82] debt - introduce IHostService and distinguish between web and desktop --- .../electron-main/electronMainService.ts | 12 + src/vs/platform/electron/node/electron.ts | 3 + src/vs/platform/windows/common/windows.ts | 1 - src/vs/platform/windows/common/windowsIpc.ts | 1 - .../electron-browser/windowsService.ts | 4 - .../workbench/browser/web.simpleservices.ts | 6 - .../customEditor/browser/customEditorInput.ts | 2 +- .../electron-browser/startupTimings.ts | 4 +- .../gettingStarted/browser/telemetryOptOut.ts | 4 +- .../host/browser/browserHostService.ts | 20 + .../workbench/services/host/browser/host.ts | 22 + .../electron-browser/desktopHostService.ts | 23 + .../browser/browserTextFileService.ts | 62 + .../textfile/browser/textFileService.ts | 1085 ++++++++++++++++- .../textfile/common/textFileService.ts | 1069 ---------------- .../nativeTextFileService.ts} | 6 +- .../textfile/test/textFileService.io.test.ts | 6 +- .../textfile/test/textFileService.test.ts | 8 +- .../timer/electron-browser/timerService.ts | 6 +- .../browser/workspaceEditingService.ts | 6 +- .../workbench/test/workbenchTestServices.ts | 23 +- src/vs/workbench/workbench.common.main.ts | 1 + src/vs/workbench/workbench.desktop.main.ts | 3 +- src/vs/workbench/workbench.web.main.ts | 2 +- 24 files changed, 1230 insertions(+), 1149 deletions(-) create mode 100644 src/vs/workbench/services/host/browser/browserHostService.ts create mode 100644 src/vs/workbench/services/host/browser/host.ts create mode 100644 src/vs/workbench/services/host/electron-browser/desktopHostService.ts create mode 100644 src/vs/workbench/services/textfile/browser/browserTextFileService.ts delete mode 100644 src/vs/workbench/services/textfile/common/textFileService.ts rename src/vs/workbench/services/textfile/{node/textFileService.ts => electron-browser/nativeTextFileService.ts} (98%) diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index 1846a5cb086..d51d4b65d3e 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -16,10 +16,20 @@ export class ElectronMainService implements IElectronService { ) { } + //#region Window + private get window(): ICodeWindow | undefined { return this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); } + async windowCount(): Promise { + return this.windowsMainService.getWindowCount(); + } + + //#endregion + + //#region Other + async showMessageBox(options: MessageBoxOptions): Promise { const result = await this.windowsMainService.showMessageBox(options, this.window); @@ -32,4 +42,6 @@ export class ElectronMainService implements IElectronService { async showItemInFolder(path: string): Promise { shell.showItemInFolder(path); } + + //#endregion } diff --git a/src/vs/platform/electron/node/electron.ts b/src/vs/platform/electron/node/electron.ts index 5411269d98e..8257bf0eee2 100644 --- a/src/vs/platform/electron/node/electron.ts +++ b/src/vs/platform/electron/node/electron.ts @@ -12,6 +12,9 @@ export interface IElectronService { _serviceBrand: undefined; + // Window + windowCount(): Promise; + // Dialogs showMessageBox(options: MessageBoxOptions): Promise; diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index a34ebe2978c..8d713a46ec6 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -155,7 +155,6 @@ export interface IWindowsService { openNewWindow(options?: INewWindowOptions): Promise; openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise; getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>; - getWindowCount(): Promise; getActiveWindowId(): Promise; // This needs to be handled from browser process to prevent diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index 6534f2f56d3..a17937f4455 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -104,7 +104,6 @@ export class WindowsChannel implements IServerChannel { case 'openNewWindow': return this.service.openNewWindow(arg); case 'openExtensionDevelopmentHostWindow': return this.service.openExtensionDevelopmentHostWindow(arg[0], arg[1]); case 'getWindows': return this.service.getWindows(); - case 'getWindowCount': return this.service.getWindowCount(); case 'relaunch': return this.service.relaunch(arg[0]); case 'whenSharedProcessReady': return this.service.whenSharedProcessReady(); case 'toggleSharedProcess': return this.service.toggleSharedProcess(); diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts index 4e983130529..92808158543 100644 --- a/src/vs/platform/windows/electron-browser/windowsService.ts +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -222,10 +222,6 @@ export class WindowsService implements IWindowsService { return result; } - getWindowCount(): Promise { - return this.channel.call('getWindowCount'); - } - getActiveWindowId(): Promise { return this.channel.call('getActiveWindowId'); } diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index a0fe7aa1915..53fb58d10a2 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -318,8 +318,6 @@ registerSingleton(IWindowService, SimpleWindowService); export class SimpleWindowsService implements IWindowsService { _serviceBrand: undefined; - windowCount = 1; - readonly onWindowOpen: Event = Event.None; readonly onWindowFocus: Event = Event.None; readonly onWindowBlur: Event = Event.None; @@ -461,10 +459,6 @@ export class SimpleWindowsService implements IWindowsService { return Promise.resolve([]); } - getWindowCount(): Promise { - return Promise.resolve(this.windowCount); - } - newWindowTab(): Promise { return Promise.resolve(); } diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 776eb29464f..2a5c59429a3 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -17,7 +17,7 @@ import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webvi import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { promptSave } from 'vs/workbench/services/textfile/common/textFileService'; +import { promptSave } from 'vs/workbench/services/textfile/browser/textFileService'; export class CustomFileEditorInput extends WebviewInput { diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts index c4d1c7cd4c1..e0c7f7f6bd2 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts @@ -21,6 +21,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { didUseCachedData, ITimerService } from 'vs/workbench/services/timer/electron-browser/timerService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { getEntries } from 'vs/base/common/performance'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class StartupTimings implements IWorkbenchContribution { @@ -34,6 +35,7 @@ export class StartupTimings implements IWorkbenchContribution { @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IUpdateService private readonly _updateService: IUpdateService, @IEnvironmentService private readonly _envService: IEnvironmentService, + @IHostService private readonly _hostService: IHostService ) { // this._report().catch(onUnexpectedError); @@ -91,7 +93,7 @@ export class StartupTimings implements IWorkbenchContribution { if (this._lifecycleService.startupKind !== StartupKind.NewWindow) { return false; } - if (await this._windowsService.getWindowCount() !== 1) { + if (await this._hostService.windowCount !== 1) { return false; } const activeViewlet = this._viewletService.getActiveViewlet(); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts index 9752407f3f8..c942edef9c9 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts @@ -18,6 +18,7 @@ import { language, locale } from 'vs/base/common/platform'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IProductService } from 'vs/platform/product/common/productService'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class TelemetryOptOut implements IWorkbenchContribution { @@ -30,6 +31,7 @@ export class TelemetryOptOut implements IWorkbenchContribution { @INotificationService private readonly notificationService: INotificationService, @IWindowService windowService: IWindowService, @IWindowsService windowsService: IWindowsService, + @IHostService hostService: IHostService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IExperimentService private readonly experimentService: IExperimentService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -42,7 +44,7 @@ export class TelemetryOptOut implements IWorkbenchContribution { const experimentId = 'telemetryOptOut'; Promise.all([ windowService.isFocused(), - windowsService.getWindowCount(), + hostService.windowCount, experimentService.getExperimentById(experimentId) ]).then(([focused, count, experimentState]) => { if (!focused && count > 1) { diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts new file mode 100644 index 00000000000..a452c20287c --- /dev/null +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class BrowserHostService implements IHostService { + + _serviceBrand: undefined; + + //#region Window + + readonly windowCount = Promise.resolve(1); + + //#endregion +} + +registerSingleton(IHostService, BrowserHostService, true); diff --git a/src/vs/workbench/services/host/browser/host.ts b/src/vs/workbench/services/host/browser/host.ts new file mode 100644 index 00000000000..735b21869e9 --- /dev/null +++ b/src/vs/workbench/services/host/browser/host.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const IHostService = createDecorator('hostService'); + +export interface IHostService { + + _serviceBrand: undefined; + + //#region Window + + /** + * The number of windows that belong to the current client session. + */ + readonly windowCount: Promise; + + //#endregion +} diff --git a/src/vs/workbench/services/host/electron-browser/desktopHostService.ts b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts new file mode 100644 index 00000000000..833310b965c --- /dev/null +++ b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class DesktopHostService implements IHostService { + + _serviceBrand: undefined; + + constructor(@IElectronService private readonly electronService: IElectronService) { } + + //#region Window + + get windowCount() { return this.electronService.windowCount(); } + + //#endregion +} + +registerSingleton(IHostService, DesktopHostService, true); diff --git a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts new file mode 100644 index 00000000000..4cdfa523db0 --- /dev/null +++ b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AbstractTextFileService } from 'vs/workbench/services/textfile/browser/textFileService'; +import { ITextFileService, IResourceEncodings, IResourceEncoding, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; + +export class BrowserTextFileService extends AbstractTextFileService { + + readonly encoding: IResourceEncodings = { + getPreferredWriteEncoding(): IResourceEncoding { + return { encoding: 'utf8', hasBOM: false }; + } + }; + + protected onBeforeShutdown(reason: ShutdownReason): boolean { + // Web: we cannot perform long running in the shutdown phase + // As such we need to check sync if there are any dirty files + // that have not been backed up yet and then prevent the shutdown + // if that is the case. + return this.doBeforeShutdownSync(); + } + + private doBeforeShutdownSync(): boolean { + if (this.models.getAll().some(model => model.hasState(ModelState.PENDING_SAVE) || model.hasState(ModelState.PENDING_AUTO_SAVE))) { + return true; // files are pending to be saved: veto + } + + const dirtyResources = this.getDirty(); + if (!dirtyResources.length) { + return false; // no dirty: no veto + } + + if (!this.isHotExitEnabled) { + return true; // dirty without backup: veto + } + + for (const dirtyResource of dirtyResources) { + let hasBackup = false; + + if (this.fileService.canHandleResource(dirtyResource)) { + const model = this.models.get(dirtyResource); + hasBackup = !!(model && model.hasBackup()); + } else if (dirtyResource.scheme === Schemas.untitled) { + hasBackup = this.untitledEditorService.hasBackup(dirtyResource); + } + + if (!hasBackup) { + console.warn('Unload prevented: pending backups'); + return true; // dirty without backup: veto + } + } + + return false; // dirty with backups: no veto + } +} + +registerSingleton(ITextFileService, BrowserTextFileService); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index ed7f5273046..0925a9f3504 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -3,60 +3,1067 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; -import { ITextFileService, IResourceEncodings, IResourceEncoding, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import * as nls from 'vs/nls'; +import { URI } from 'vs/base/common/uri'; +import * as errors from 'vs/base/common/errors'; +import * as objects from 'vs/base/common/objects'; +import { Event, Emitter } from 'vs/base/common/event'; +import * as platform from 'vs/base/common/platform'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, IWillMoveEvent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; +import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions } from 'vs/platform/files/common/files'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; +import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename, toLocalResource } from 'vs/base/common/resources'; +import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { coalesce } from 'vs/base/common/arrays'; +import { trim } from 'vs/base/common/strings'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { ITextSnapshot } from 'vs/editor/common/model'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class BrowserTextFileService extends TextFileService { +/** + * The workbench file service implementation implements the raw file service spec and adds additional methods on top. + */ +export abstract class AbstractTextFileService extends Disposable implements ITextFileService { - readonly encoding: IResourceEncodings = { - getPreferredWriteEncoding(): IResourceEncoding { - return { encoding: 'utf8', hasBOM: false }; - } - }; + _serviceBrand: undefined; - protected onBeforeShutdown(reason: ShutdownReason): boolean { - // Web: we cannot perform long running in the shutdown phase - // As such we need to check sync if there are any dirty files - // that have not been backed up yet and then prevent the shutdown - // if that is the case. - return this.doBeforeShutdownSync(); + private readonly _onAutoSaveConfigurationChange: Emitter = this._register(new Emitter()); + readonly onAutoSaveConfigurationChange: Event = this._onAutoSaveConfigurationChange.event; + + private readonly _onFilesAssociationChange: Emitter = this._register(new Emitter()); + readonly onFilesAssociationChange: Event = this._onFilesAssociationChange.event; + + private readonly _onWillMove = this._register(new Emitter()); + readonly onWillMove: Event = this._onWillMove.event; + + private _models: TextFileEditorModelManager; + get models(): ITextFileEditorModelManager { return this._models; } + + abstract get encoding(): IResourceEncodings; + + private currentFilesAssociationConfig: { [key: string]: string; }; + private configuredAutoSaveDelay?: number; + private configuredAutoSaveOnFocusChange: boolean | undefined; + private configuredAutoSaveOnWindowChange: boolean | undefined; + private configuredHotExit: string | undefined; + private autoSaveContext: IContextKey; + + constructor( + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IFileService protected readonly fileService: IFileService, + @IUntitledEditorService protected readonly untitledEditorService: IUntitledEditorService, + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IInstantiationService protected instantiationService: IInstantiationService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IModeService private readonly modeService: IModeService, + @IModelService private readonly modelService: IModelService, + @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, + @INotificationService private readonly notificationService: INotificationService, + @IBackupFileService private readonly backupFileService: IBackupFileService, + @IHostService private readonly hostService: IHostService, + @IHistoryService private readonly historyService: IHistoryService, + @IContextKeyService contextKeyService: IContextKeyService, + @IDialogService private readonly dialogService: IDialogService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, + @IEditorService private readonly editorService: IEditorService, + @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService + ) { + super(); + + this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); + this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); + + const configuration = configurationService.getValue(); + this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; + + this.onFilesConfigurationChange(configuration); + + this.registerListeners(); } - private doBeforeShutdownSync(): boolean { - if (this.models.getAll().some(model => model.hasState(ModelState.PENDING_SAVE) || model.hasState(ModelState.PENDING_AUTO_SAVE))) { - return true; // files are pending to be saved: veto - } + //#region event handling - const dirtyResources = this.getDirty(); - if (!dirtyResources.length) { - return false; // no dirty: no veto - } + private registerListeners(): void { - if (!this.isHotExitEnabled) { - return true; // dirty without backup: veto - } + // Lifecycle + this.lifecycleService.onBeforeShutdown(event => event.veto(this.onBeforeShutdown(event.reason))); + this.lifecycleService.onShutdown(this.dispose, this); - for (const dirtyResource of dirtyResources) { - let hasBackup = false; + // Files configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getValue()); + } + })); + } - if (this.fileService.canHandleResource(dirtyResource)) { - const model = this.models.get(dirtyResource); - hasBackup = !!(model && model.hasBackup()); - } else if (dirtyResource.scheme === Schemas.untitled) { - hasBackup = this.untitledEditorService.hasBackup(dirtyResource); + protected onBeforeShutdown(reason: ShutdownReason): boolean | Promise { + + // Dirty files need treatment on shutdown + const dirty = this.getDirty(); + if (dirty.length) { + + // If auto save is enabled, save all files and then check again for dirty files + // We DO NOT run any save participant if we are in the shutdown phase for performance reasons + if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { + return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { + + // If we still have dirty files, we either have untitled ones or files that cannot be saved + const remainingDirty = this.getDirty(); + if (remainingDirty.length) { + return this.handleDirtyBeforeShutdown(remainingDirty, reason); + } + + return false; + }); } - if (!hasBackup) { - console.warn('Unload prevented: pending backups'); - return true; // dirty without backup: veto + // Auto save is not enabled + return this.handleDirtyBeforeShutdown(dirty, reason); + } + + // No dirty files: no veto + return this.noVeto({ cleanUpBackups: true }); + } + + private handleDirtyBeforeShutdown(dirty: URI[], reason: ShutdownReason): boolean | Promise { + + // If hot exit is enabled, backup dirty files and allow to exit without confirmation + if (this.isHotExitEnabled) { + return this.backupBeforeShutdown(dirty, reason).then(didBackup => { + if (didBackup) { + return this.noVeto({ cleanUpBackups: false }); // no veto and no backup cleanup (since backup was successful) + } + + // since a backup did not happen, we have to confirm for the dirty files now + return this.confirmBeforeShutdown(); + }, error => { + this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", error.message)); + + return true; // veto, the backups failed + }); + } + + // Otherwise just confirm from the user what to do with the dirty files + return this.confirmBeforeShutdown(); + } + + private async backupBeforeShutdown(dirtyToBackup: URI[], reason: ShutdownReason): Promise { + const windowCount = await this.hostService.windowCount; + + // When quit is requested skip the confirm callback and attempt to backup all workspaces. + // When quit is not requested the confirm callback should be shown when the window being + // closed is the only VS Code window open, except for on Mac where hot exit is only + // ever activated when quit is requested. + + let doBackup: boolean | undefined; + switch (reason) { + case ShutdownReason.CLOSE: + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured + } else if (windowCount > 1 || platform.isMacintosh) { + doBackup = false; // do not backup if a window is closed that does not cause quitting of the application + } else { + doBackup = true; // backup if last window is closed on win/linux where the application quits right after + } + break; + + case ShutdownReason.QUIT: + doBackup = true; // backup because next start we restore all backups + break; + + case ShutdownReason.RELOAD: + doBackup = true; // backup because after window reload, backups restore + break; + + case ShutdownReason.LOAD: + if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured + } else { + doBackup = false; // do not backup because we are switching contexts + } + break; + } + + if (!doBackup) { + return false; + } + + await this.backupAll(dirtyToBackup); + + return true; + } + + private backupAll(dirtyToBackup: URI[]): Promise { + + // split up between files and untitled + const filesToBackup: ITextFileEditorModel[] = []; + const untitledToBackup: URI[] = []; + dirtyToBackup.forEach(dirty => { + if (this.fileService.canHandleResource(dirty)) { + const model = this.models.get(dirty); + if (model) { + filesToBackup.push(model); + } + } else if (dirty.scheme === Schemas.untitled) { + untitledToBackup.push(dirty); + } + }); + + return this.doBackupAll(filesToBackup, untitledToBackup); + } + + private async doBackupAll(dirtyFileModels: ITextFileEditorModel[], untitledResources: URI[]): Promise { + + // Handle file resources first + await Promise.all(dirtyFileModels.map(model => model.backup())); + + // Handle untitled resources + await Promise.all(untitledResources + .filter(untitled => this.untitledEditorService.exists(untitled)) + .map(async untitled => (await this.untitledEditorService.loadOrCreate({ resource: untitled })).backup())); + } + + private async confirmBeforeShutdown(): Promise { + const confirm = await this.confirmSave(); + + // Save + if (confirm === ConfirmResult.SAVE) { + const result = await this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }); + + if (result.results.some(r => !r.success)) { + return true; // veto if some saves failed + } + + return this.noVeto({ cleanUpBackups: true }); + } + + // Don't Save + else if (confirm === ConfirmResult.DONT_SAVE) { + + // Make sure to revert untitled so that they do not restore + // see https://github.com/Microsoft/vscode/issues/29572 + this.untitledEditorService.revertAll(); + + return this.noVeto({ cleanUpBackups: true }); + } + + // Cancel + else if (confirm === ConfirmResult.CANCEL) { + return true; // veto + } + + return false; + } + + private noVeto(options: { cleanUpBackups: boolean }): boolean | Promise { + if (!options.cleanUpBackups) { + return false; + } + + if (this.lifecycleService.phase < LifecyclePhase.Restored) { + return false; // if editors have not restored, we are not up to speed with backups and thus should not clean them + } + + return this.cleanupBackupsBeforeShutdown().then(() => false, () => false); + } + + protected async cleanupBackupsBeforeShutdown(): Promise { + if (this.environmentService.isExtensionDevelopment) { + return; + } + + await this.backupFileService.discardAllWorkspaceBackups(); + } + + protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { + const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); + + const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; + this.autoSaveContext.set(autoSaveMode); + switch (autoSaveMode) { + case AutoSaveConfiguration.AFTER_DELAY: + this.configuredAutoSaveDelay = configuration && configuration.files && configuration.files.autoSaveDelay; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_FOCUS_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = true; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_WINDOW_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = true; + break; + + default: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + } + + // Emit as event + this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); + + // save all dirty when enabling auto save + if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { + this.saveAll(); + } + + // Check for change in files associations + const filesAssociation = configuration && configuration.files && configuration.files.associations; + if (!objects.equals(this.currentFilesAssociationConfig, filesAssociation)) { + this.currentFilesAssociationConfig = filesAssociation; + this._onFilesAssociationChange.fire(); + } + + // Hot exit + const hotExitMode = configuration && configuration.files && configuration.files.hotExit; + if (hotExitMode === HotExitConfiguration.OFF || hotExitMode === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { + this.configuredHotExit = hotExitMode; + } else { + this.configuredHotExit = HotExitConfiguration.ON_EXIT; + } + } + + //#endregion + + //#region primitives (read, create, move, delete, update) + + async read(resource: URI, options?: IReadTextFileOptions): Promise { + const content = await this.fileService.readFile(resource, options); + + // in case of acceptTextOnly: true, we check the first + // chunk for possibly being binary by looking for 0-bytes + // we limit this check to the first 512 bytes + this.validateBinary(content.value, options); + + return { + ...content, + encoding: 'utf8', + value: content.value.toString() + }; + } + + async readStream(resource: URI, options?: IReadTextFileOptions): Promise { + const stream = await this.fileService.readFileStream(resource, options); + + // in case of acceptTextOnly: true, we check the first + // chunk for possibly being binary by looking for 0-bytes + // we limit this check to the first 512 bytes + let checkedForBinary = false; + const throwOnBinary = (data: VSBuffer): Error | undefined => { + if (!checkedForBinary) { + checkedForBinary = true; + + this.validateBinary(data, options); + } + + return undefined; + }; + + return { + ...stream, + encoding: 'utf8', + value: await createTextBufferFactoryFromStream(stream.value, undefined, options && options.acceptTextOnly ? throwOnBinary : undefined) + }; + } + + private validateBinary(buffer: VSBuffer, options?: IReadTextFileOptions): void { + if (!options || !options.acceptTextOnly) { + return; // no validation needed + } + + // in case of acceptTextOnly: true, we check the first + // chunk for possibly being binary by looking for 0-bytes + // we limit this check to the first 512 bytes + for (let i = 0; i < buffer.byteLength && i < 512; i++) { + if (buffer.readUInt8(i) === 0) { + throw new TextFileOperationError(nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options); + } + } + } + + async create(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise { + const stat = await this.doCreate(resource, value, options); + + // If we had an existing model for the given resource, load + // it again to make sure it is up to date with the contents + // we just wrote into the underlying resource by calling + // revert() + const existingModel = this.models.get(resource); + if (existingModel && !existingModel.isDisposed()) { + await existingModel.revert(); + } + + return stat; + } + + protected doCreate(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise { + return this.fileService.createFile(resource, toBufferOrReadable(value), options); + } + + async write(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise { + return this.fileService.writeFile(resource, toBufferOrReadable(value), options); + } + + async delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise { + const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); + + await this.revertAll(dirtyFiles, { soft: true }); + + return this.fileService.del(resource, options); + } + + async move(source: URI, target: URI, overwrite?: boolean): Promise { + + // await onWillMove event joiners + await this.notifyOnWillMove(source, target); + + // find all models that related to either source or target (can be many if resource is a folder) + const sourceModels: ITextFileEditorModel[] = []; + const conflictingModels: ITextFileEditorModel[] = []; + for (const model of this.getFileModels()) { + const resource = model.getResource(); + + if (isEqualOrParent(resource, target, false /* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) { + conflictingModels.push(model); + } + + if (isEqualOrParent(resource, source)) { + sourceModels.push(model); } } - return false; // dirty with backups: no veto + // remember each source model to load again after move is done + // with optional content to restore if it was dirty + type ModelToRestore = { resource: URI; snapshot?: ITextSnapshot }; + const modelsToRestore: ModelToRestore[] = []; + for (const sourceModel of sourceModels) { + const sourceModelResource = sourceModel.getResource(); + + // If the source is the actual model, just use target as new resource + let modelToRestoreResource: URI; + if (isEqual(sourceModelResource, source)) { + modelToRestoreResource = target; + } + + // Otherwise a parent folder of the source is being moved, so we need + // to compute the target resource based on that + else { + modelToRestoreResource = joinPath(target, sourceModelResource.path.substr(source.path.length + 1)); + } + + const modelToRestore: ModelToRestore = { resource: modelToRestoreResource }; + if (sourceModel.isDirty()) { + modelToRestore.snapshot = sourceModel.createSnapshot(); + } + + modelsToRestore.push(modelToRestore); + } + + // in order to move, we need to soft revert all dirty models, + // both from the source as well as the target if any + const dirtyModels = [...sourceModels, ...conflictingModels].filter(model => model.isDirty()); + await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.getResource()), { soft: true }); + + // now we can rename the source to target via file operation + let stat: IFileStatWithMetadata; + try { + stat = await this.fileService.move(source, target, overwrite); + } catch (error) { + + // in case of any error, ensure to set dirty flag back + dirtyModels.forEach(dirtyModel => dirtyModel.makeDirty()); + + throw error; + } + + // finally, restore models that we had loaded previously + await Promise.all(modelsToRestore.map(async modelToRestore => { + + // restore the model, forcing a reload. this is important because + // we know the file has changed on disk after the move and the + // model might have still existed with the previous state. this + // ensures we are not tracking a stale state. + const restoredModel = await this.models.loadOrCreate(modelToRestore.resource, { reload: { async: false } }); + + // restore previous dirty content if any and ensure to mark + // the model as dirty + if (modelToRestore.snapshot && restoredModel.isResolved()) { + this.modelService.updateModel(restoredModel.textEditorModel, createTextBufferFactoryFromSnapshot(modelToRestore.snapshot)); + + restoredModel.makeDirty(); + } + })); + + return stat; + } + + private async notifyOnWillMove(source: URI, target: URI): Promise { + const waitForPromises: Promise[] = []; + + // fire event + this._onWillMove.fire({ + oldResource: source, + newResource: target, + waitUntil(promise: Promise) { + waitForPromises.push(promise.then(undefined, errors.onUnexpectedError)); + } + }); + + // prevent async waitUntil-calls + Object.freeze(waitForPromises); + + await Promise.all(waitForPromises); + } + + //#endregion + + //#region save/revert + + async save(resource: URI, options?: ISaveOptions): Promise { + + // Run a forced save if we detect the file is not dirty so that save participants can still run + if (options && options.force && this.fileService.canHandleResource(resource) && !this.isDirty(resource)) { + const model = this._models.get(resource); + if (model) { + options.reason = SaveReason.EXPLICIT; + + await model.save(options); + + return !model.isDirty(); + } + } + + const result = await this.saveAll([resource], options); + + return result.results.length === 1 && !!result.results[0].success; + } + + async confirmSave(resources?: URI[]): Promise { + if (this.environmentService.isExtensionDevelopment) { + if (!this.environmentService.args['extension-development-confirm-save']) { + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) + } + } + + const resourcesToConfirm = this.getDirty(resources); + if (resourcesToConfirm.length === 0) { + return ConfirmResult.DONT_SAVE; + } + return promptSave(this.dialogService, resourcesToConfirm); + } + + async confirmOverwrite(resource: URI): Promise { + const confirm: IConfirmation = { + message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), + detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), + primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; + + return (await this.dialogService.confirm(confirm)).confirmed; + } + + saveAll(includeUntitled?: boolean, options?: ISaveOptions): Promise; + saveAll(resources: URI[], options?: ISaveOptions): Promise; + saveAll(arg1?: boolean | URI[], options?: ISaveOptions): Promise { + + // get all dirty + let toSave: URI[] = []; + if (Array.isArray(arg1)) { + toSave = this.getDirty(arg1); + } else { + toSave = this.getDirty(); + } + + // split up between files and untitled + const filesToSave: URI[] = []; + const untitledToSave: URI[] = []; + toSave.forEach(resourceToSave => { + if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && resourceToSave.scheme === Schemas.untitled) { + untitledToSave.push(resourceToSave); + } else { + filesToSave.push(resourceToSave); + } + }); + + return this.doSaveAll(filesToSave, untitledToSave, options); + } + + private async doSaveAll(fileResources: URI[], untitledResources: URI[], options?: ISaveOptions): Promise { + + // Handle files first that can just be saved + const result = await this.doSaveAllFiles(fileResources, options); + + // Preflight for untitled to handle cancellation from the dialog + const targetsForUntitled: URI[] = []; + for (const untitled of untitledResources) { + if (this.untitledEditorService.exists(untitled)) { + let targetUri: URI; + + // Untitled with associated file path don't need to prompt + if (this.untitledEditorService.hasAssociatedFilePath(untitled)) { + targetUri = toLocalResource(untitled, this.environmentService.configuration.remoteAuthority); + } + + // Otherwise ask user + else { + const targetPath = await this.promptForPath(untitled, this.suggestFileName(untitled)); + if (!targetPath) { + return { results: [...fileResources, ...untitledResources].map(r => ({ source: r })) }; + } + + targetUri = targetPath; + } + + targetsForUntitled.push(targetUri); + } + } + + // Handle untitled + await Promise.all(targetsForUntitled.map(async (target, index) => { + const uri = await this.saveAs(untitledResources[index], target); + + result.results.push({ + source: untitledResources[index], + target: uri, + success: !!uri + }); + })); + + return result; + } + + protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: string[]): Promise { + + // Help user to find a name for the file by opening it first + await this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true } }); + + return this.fileDialogService.pickFileToSave(this.getSaveDialogOptions(defaultUri, availableFileSystems)); + } + + private getSaveDialogOptions(defaultUri: URI, availableFileSystems?: string[]): ISaveDialogOptions { + const options: ISaveDialogOptions = { + defaultUri, + title: nls.localize('saveAsTitle', "Save As"), + availableFileSystems, + }; + + // Filters are only enabled on Windows where they work properly + if (!platform.isWindows) { + return options; + } + + interface IFilter { name: string; extensions: string[]; } + + // Build the file filter by using our known languages + const ext: string | undefined = defaultUri ? extname(defaultUri) : undefined; + let matchingFilter: IFilter | undefined; + const filters: IFilter[] = coalesce(this.modeService.getRegisteredLanguageNames().map(languageName => { + const extensions = this.modeService.getExtensions(languageName); + if (!extensions || !extensions.length) { + return null; + } + + const filter: IFilter = { name: languageName, extensions: extensions.slice(0, 10).map(e => trim(e, '.')) }; + + if (ext && extensions.indexOf(ext) >= 0) { + matchingFilter = filter; + + return null; // matching filter will be added last to the top + } + + return filter; + })); + + // Filters are a bit weird on Windows, based on having a match or not: + // Match: we put the matching filter first so that it shows up selected and the all files last + // No match: we put the all files filter first + const allFilesFilter = { name: nls.localize('allFiles', "All Files"), extensions: ['*'] }; + if (matchingFilter) { + filters.unshift(matchingFilter); + filters.unshift(allFilesFilter); + } else { + filters.unshift(allFilesFilter); + } + + // Allow to save file without extension + filters.push({ name: nls.localize('noExt', "No Extension"), extensions: [''] }); + + options.filters = filters; + + return options; + } + + private async doSaveAllFiles(resources?: URI[], options: ISaveOptions = Object.create(null)): Promise { + const dirtyFileModels = this.getDirtyFileModels(Array.isArray(resources) ? resources : undefined /* Save All */) + .filter(model => { + if ((model.hasState(ModelState.CONFLICT) || model.hasState(ModelState.ERROR)) && (options.reason === SaveReason.AUTO || options.reason === SaveReason.FOCUS_CHANGE || options.reason === SaveReason.WINDOW_CHANGE)) { + return false; // if model is in save conflict or error, do not save unless save reason is explicit or not provided at all + } + + return true; + }); + + const mapResourceToResult = new ResourceMap(); + dirtyFileModels.forEach(m => { + mapResourceToResult.set(m.getResource(), { + source: m.getResource() + }); + }); + + await Promise.all(dirtyFileModels.map(async model => { + await model.save(options); + + if (!model.isDirty()) { + const result = mapResourceToResult.get(model.getResource()); + if (result) { + result.success = true; + } + } + })); + + return { results: mapResourceToResult.values() }; + } + + private getFileModels(arg1?: URI | URI[]): ITextFileEditorModel[] { + if (Array.isArray(arg1)) { + const models: ITextFileEditorModel[] = []; + arg1.forEach(resource => { + models.push(...this.getFileModels(resource)); + }); + + return models; + } + + return this._models.getAll(arg1); + } + + private getDirtyFileModels(resources?: URI | URI[]): ITextFileEditorModel[] { + return this.getFileModels(resources).filter(model => model.isDirty()); + } + + async saveAs(resource: URI, targetResource?: URI, options?: ISaveOptions): Promise { + + // Get to target resource + if (!targetResource) { + let dialogPath = resource; + if (resource.scheme === Schemas.untitled) { + dialogPath = this.suggestFileName(resource); + } + + targetResource = await this.promptForPath(resource, dialogPath, options ? options.availableFileSystems : undefined); + } + + if (!targetResource) { + return; // user canceled + } + + // Just save if target is same as models own resource + if (resource.toString() === targetResource.toString()) { + await this.save(resource, options); + + return resource; + } + + // Do it + return this.doSaveAs(resource, targetResource, options); + } + + private async doSaveAs(resource: URI, target: URI, options?: ISaveOptions): Promise { + + // Retrieve text model from provided resource if any + let model: ITextFileEditorModel | UntitledEditorModel | undefined; + if (this.fileService.canHandleResource(resource)) { + model = this._models.get(resource); + } else if (resource.scheme === Schemas.untitled && this.untitledEditorService.exists(resource)) { + model = await this.untitledEditorService.loadOrCreate({ resource }); + } + + // We have a model: Use it (can be null e.g. if this file is binary and not a text file or was never opened before) + let result: boolean; + if (model) { + result = await this.doSaveTextFileAs(model, resource, target, options); + } + + // Otherwise we can only copy + else { + await this.fileService.copy(resource, target); + + result = true; + } + + // Return early if the operation was not running + if (!result) { + return target; + } + + // Revert the source + await this.revert(resource); + + return target; + } + + private async doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI, options?: ISaveOptions): Promise { + + // Prefer an existing model if it is already loaded for the given target resource + let targetExists: boolean = false; + let targetModel = this.models.get(target); + if (targetModel && targetModel.isResolved()) { + targetExists = true; + } + + // Otherwise create the target file empty if it does not exist already and resolve it from there + else { + targetExists = await this.fileService.exists(target); + + // create target model adhoc if file does not exist yet + if (!targetExists) { + await this.create(target, ''); + } + + targetModel = await this.models.loadOrCreate(target); + } + + try { + + // Confirm to overwrite if we have an untitled file with associated file where + // the file actually exists on disk and we are instructed to save to that file + // path. This can happen if the file was created after the untitled file was opened. + // See https://github.com/Microsoft/vscode/issues/67946 + let write: boolean; + if (sourceModel instanceof UntitledEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.getResource(), this.environmentService.configuration.remoteAuthority))) { + write = await this.confirmOverwrite(target); + } else { + write = true; + } + + if (!write) { + return false; + } + + // take over model value, encoding and mode (only if more specific) from source model + targetModel.updatePreferredEncoding(sourceModel.getEncoding()); + if (sourceModel.isResolved() && targetModel.isResolved()) { + this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); + + const sourceMode = sourceModel.textEditorModel.getLanguageIdentifier(); + const targetMode = targetModel.textEditorModel.getLanguageIdentifier(); + if (sourceMode.language !== PLAINTEXT_MODE_ID && targetMode.language === PLAINTEXT_MODE_ID) { + targetModel.textEditorModel.setMode(sourceMode); // only use if more specific than plain/text + } + } + + // save model + await targetModel.save(options); + + return true; + } catch (error) { + + // binary model: delete the file and run the operation again + if ( + (error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY || + (error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE + ) { + await this.fileService.del(target); + + return this.doSaveTextFileAs(sourceModel, resource, target, options); + } + + throw error; + } + } + + private suggestFileName(untitledResource: URI): URI { + const untitledFileName = this.untitledEditorService.suggestFileName(untitledResource); + const remoteAuthority = this.environmentService.configuration.remoteAuthority; + const schemeFilter = remoteAuthority ? Schemas.vscodeRemote : Schemas.file; + + const lastActiveFile = this.historyService.getLastActiveFile(schemeFilter); + if (lastActiveFile) { + const lastDir = dirname(lastActiveFile); + return joinPath(lastDir, untitledFileName); + } + + const lastActiveFolder = this.historyService.getLastActiveWorkspaceRoot(schemeFilter); + if (lastActiveFolder) { + return joinPath(lastActiveFolder, untitledFileName); + } + + return untitledResource.with({ path: untitledFileName }); + } + + async revert(resource: URI, options?: IRevertOptions): Promise { + const result = await this.revertAll([resource], options); + + return result.results.length === 1 && !!result.results[0].success; + } + + async revertAll(resources?: URI[], options?: IRevertOptions): Promise { + + // Revert files first + const revertOperationResult = await this.doRevertAllFiles(resources, options); + + // Revert untitled + const untitledReverted = this.untitledEditorService.revertAll(resources); + untitledReverted.forEach(untitled => revertOperationResult.results.push({ source: untitled, success: true })); + + return revertOperationResult; + } + + private async doRevertAllFiles(resources?: URI[], options?: IRevertOptions): Promise { + const fileModels = options && options.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); + + const mapResourceToResult = new ResourceMap(); + fileModels.forEach(m => { + mapResourceToResult.set(m.getResource(), { + source: m.getResource() + }); + }); + + await Promise.all(fileModels.map(async model => { + try { + await model.revert(options && options.soft); + + if (!model.isDirty()) { + const result = mapResourceToResult.get(model.getResource()); + if (result) { + result.success = true; + } + } + } catch (error) { + + // FileNotFound means the file got deleted meanwhile, so still record as successful revert + if ((error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) { + const result = mapResourceToResult.get(model.getResource()); + if (result) { + result.success = true; + } + } + + // Otherwise bubble up the error + else { + throw error; + } + } + })); + + return { results: mapResourceToResult.values() }; + } + + getDirty(resources?: URI[]): URI[] { + + // Collect files + const dirty = this.getDirtyFileModels(resources).map(m => m.getResource()); + + // Add untitled ones + dirty.push(...this.untitledEditorService.getDirty(resources)); + + return dirty; + } + + isDirty(resource?: URI): boolean { + + // Check for dirty file + if (this._models.getAll(resource).some(model => model.isDirty())) { + return true; + } + + // Check for dirty untitled + return this.untitledEditorService.getDirty().some(dirty => !resource || dirty.toString() === resource.toString()); + } + + //#endregion + + //#region config + + getAutoSaveMode(): AutoSaveMode { + if (this.configuredAutoSaveOnFocusChange) { + return AutoSaveMode.ON_FOCUS_CHANGE; + } + + if (this.configuredAutoSaveOnWindowChange) { + return AutoSaveMode.ON_WINDOW_CHANGE; + } + + if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { + return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; + } + + return AutoSaveMode.OFF; + } + + getAutoSaveConfiguration(): IAutoSaveConfiguration { + return { + autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, + autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, + autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange + }; + } + + get isHotExitEnabled(): boolean { + return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; + } + + //#endregion + + dispose(): void { + + // Clear all caches + this._models.clear(); + + super.dispose(); + } +} + +export async function promptSave(dialogService: IDialogService, resourcesToConfirm: readonly URI[]) { + const message = resourcesToConfirm.length === 1 + ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) + : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); + + const buttons: string[] = [ + resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), + nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), + nls.localize('cancel', "Cancel") + ]; + + const { choice } = await dialogService.show(Severity.Warning, message, buttons, { + cancelId: 2, + detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") + }); + + switch (choice) { + case 0: return ConfirmResult.SAVE; + case 1: return ConfirmResult.DONT_SAVE; + default: return ConfirmResult.CANCEL; } } -registerSingleton(ITextFileService, BrowserTextFileService); diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts deleted file mode 100644 index 8c619f82fb8..00000000000 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ /dev/null @@ -1,1069 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { URI } from 'vs/base/common/uri'; -import * as errors from 'vs/base/common/errors'; -import * as objects from 'vs/base/common/objects'; -import { Event, Emitter } from 'vs/base/common/event'; -import * as platform from 'vs/base/common/platform'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, IWillMoveEvent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; -import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; -import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions } from 'vs/platform/files/common/files'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; -import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ResourceMap } from 'vs/base/common/map'; -import { Schemas } from 'vs/base/common/network'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename, toLocalResource } from 'vs/base/common/resources'; -import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { coalesce } from 'vs/base/common/arrays'; -import { trim } from 'vs/base/common/strings'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { ITextSnapshot } from 'vs/editor/common/model'; -import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; - -/** - * The workbench file service implementation implements the raw file service spec and adds additional methods on top. - */ -export abstract class TextFileService extends Disposable implements ITextFileService { - - _serviceBrand: undefined; - - private readonly _onAutoSaveConfigurationChange: Emitter = this._register(new Emitter()); - readonly onAutoSaveConfigurationChange: Event = this._onAutoSaveConfigurationChange.event; - - private readonly _onFilesAssociationChange: Emitter = this._register(new Emitter()); - readonly onFilesAssociationChange: Event = this._onFilesAssociationChange.event; - - private readonly _onWillMove = this._register(new Emitter()); - readonly onWillMove: Event = this._onWillMove.event; - - private _models: TextFileEditorModelManager; - get models(): ITextFileEditorModelManager { return this._models; } - - abstract get encoding(): IResourceEncodings; - - private currentFilesAssociationConfig: { [key: string]: string; }; - private configuredAutoSaveDelay?: number; - private configuredAutoSaveOnFocusChange: boolean | undefined; - private configuredAutoSaveOnWindowChange: boolean | undefined; - private configuredHotExit: string | undefined; - private autoSaveContext: IContextKey; - - constructor( - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IFileService protected readonly fileService: IFileService, - @IUntitledEditorService protected readonly untitledEditorService: IUntitledEditorService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IInstantiationService protected instantiationService: IInstantiationService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IModeService private readonly modeService: IModeService, - @IModelService private readonly modelService: IModelService, - @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, - @INotificationService private readonly notificationService: INotificationService, - @IBackupFileService private readonly backupFileService: IBackupFileService, - @IWindowsService private readonly windowsService: IWindowsService, - @IHistoryService private readonly historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, - @IDialogService private readonly dialogService: IDialogService, - @IFileDialogService private readonly fileDialogService: IFileDialogService, - @IEditorService private readonly editorService: IEditorService, - @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService - ) { - super(); - - this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); - this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); - - const configuration = configurationService.getValue(); - this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; - - this.onFilesConfigurationChange(configuration); - - this.registerListeners(); - } - - //#region event handling - - private registerListeners(): void { - - // Lifecycle - this.lifecycleService.onBeforeShutdown(event => event.veto(this.onBeforeShutdown(event.reason))); - this.lifecycleService.onShutdown(this.dispose, this); - - // Files configuration changes - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('files')) { - this.onFilesConfigurationChange(this.configurationService.getValue()); - } - })); - } - - protected onBeforeShutdown(reason: ShutdownReason): boolean | Promise { - - // Dirty files need treatment on shutdown - const dirty = this.getDirty(); - if (dirty.length) { - - // If auto save is enabled, save all files and then check again for dirty files - // We DO NOT run any save participant if we are in the shutdown phase for performance reasons - if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { - return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { - - // If we still have dirty files, we either have untitled ones or files that cannot be saved - const remainingDirty = this.getDirty(); - if (remainingDirty.length) { - return this.handleDirtyBeforeShutdown(remainingDirty, reason); - } - - return false; - }); - } - - // Auto save is not enabled - return this.handleDirtyBeforeShutdown(dirty, reason); - } - - // No dirty files: no veto - return this.noVeto({ cleanUpBackups: true }); - } - - private handleDirtyBeforeShutdown(dirty: URI[], reason: ShutdownReason): boolean | Promise { - - // If hot exit is enabled, backup dirty files and allow to exit without confirmation - if (this.isHotExitEnabled) { - return this.backupBeforeShutdown(dirty, reason).then(didBackup => { - if (didBackup) { - return this.noVeto({ cleanUpBackups: false }); // no veto and no backup cleanup (since backup was successful) - } - - // since a backup did not happen, we have to confirm for the dirty files now - return this.confirmBeforeShutdown(); - }, error => { - this.notificationService.error(nls.localize('files.backup.failSave', "Files that are dirty could not be written to the backup location (Error: {0}). Try saving your files first and then exit.", error.message)); - - return true; // veto, the backups failed - }); - } - - // Otherwise just confirm from the user what to do with the dirty files - return this.confirmBeforeShutdown(); - } - - private async backupBeforeShutdown(dirtyToBackup: URI[], reason: ShutdownReason): Promise { - const windowCount = await this.windowsService.getWindowCount(); - - // When quit is requested skip the confirm callback and attempt to backup all workspaces. - // When quit is not requested the confirm callback should be shown when the window being - // closed is the only VS Code window open, except for on Mac where hot exit is only - // ever activated when quit is requested. - - let doBackup: boolean | undefined; - switch (reason) { - case ShutdownReason.CLOSE: - if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { - doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured - } else if (windowCount > 1 || platform.isMacintosh) { - doBackup = false; // do not backup if a window is closed that does not cause quitting of the application - } else { - doBackup = true; // backup if last window is closed on win/linux where the application quits right after - } - break; - - case ShutdownReason.QUIT: - doBackup = true; // backup because next start we restore all backups - break; - - case ShutdownReason.RELOAD: - doBackup = true; // backup because after window reload, backups restore - break; - - case ShutdownReason.LOAD: - if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { - doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured - } else { - doBackup = false; // do not backup because we are switching contexts - } - break; - } - - if (!doBackup) { - return false; - } - - await this.backupAll(dirtyToBackup); - - return true; - } - - private backupAll(dirtyToBackup: URI[]): Promise { - - // split up between files and untitled - const filesToBackup: ITextFileEditorModel[] = []; - const untitledToBackup: URI[] = []; - dirtyToBackup.forEach(dirty => { - if (this.fileService.canHandleResource(dirty)) { - const model = this.models.get(dirty); - if (model) { - filesToBackup.push(model); - } - } else if (dirty.scheme === Schemas.untitled) { - untitledToBackup.push(dirty); - } - }); - - return this.doBackupAll(filesToBackup, untitledToBackup); - } - - private async doBackupAll(dirtyFileModels: ITextFileEditorModel[], untitledResources: URI[]): Promise { - - // Handle file resources first - await Promise.all(dirtyFileModels.map(model => model.backup())); - - // Handle untitled resources - await Promise.all(untitledResources - .filter(untitled => this.untitledEditorService.exists(untitled)) - .map(async untitled => (await this.untitledEditorService.loadOrCreate({ resource: untitled })).backup())); - } - - private async confirmBeforeShutdown(): Promise { - const confirm = await this.confirmSave(); - - // Save - if (confirm === ConfirmResult.SAVE) { - const result = await this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }); - - if (result.results.some(r => !r.success)) { - return true; // veto if some saves failed - } - - return this.noVeto({ cleanUpBackups: true }); - } - - // Don't Save - else if (confirm === ConfirmResult.DONT_SAVE) { - - // Make sure to revert untitled so that they do not restore - // see https://github.com/Microsoft/vscode/issues/29572 - this.untitledEditorService.revertAll(); - - return this.noVeto({ cleanUpBackups: true }); - } - - // Cancel - else if (confirm === ConfirmResult.CANCEL) { - return true; // veto - } - - return false; - } - - private noVeto(options: { cleanUpBackups: boolean }): boolean | Promise { - if (!options.cleanUpBackups) { - return false; - } - - if (this.lifecycleService.phase < LifecyclePhase.Restored) { - return false; // if editors have not restored, we are not up to speed with backups and thus should not clean them - } - - return this.cleanupBackupsBeforeShutdown().then(() => false, () => false); - } - - protected async cleanupBackupsBeforeShutdown(): Promise { - if (this.environmentService.isExtensionDevelopment) { - return; - } - - await this.backupFileService.discardAllWorkspaceBackups(); - } - - protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { - const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - - const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; - this.autoSaveContext.set(autoSaveMode); - switch (autoSaveMode) { - case AutoSaveConfiguration.AFTER_DELAY: - this.configuredAutoSaveDelay = configuration && configuration.files && configuration.files.autoSaveDelay; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_FOCUS_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = true; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_WINDOW_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = true; - break; - - default: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - } - - // Emit as event - this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); - - // save all dirty when enabling auto save - if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { - this.saveAll(); - } - - // Check for change in files associations - const filesAssociation = configuration && configuration.files && configuration.files.associations; - if (!objects.equals(this.currentFilesAssociationConfig, filesAssociation)) { - this.currentFilesAssociationConfig = filesAssociation; - this._onFilesAssociationChange.fire(); - } - - // Hot exit - const hotExitMode = configuration && configuration.files && configuration.files.hotExit; - if (hotExitMode === HotExitConfiguration.OFF || hotExitMode === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { - this.configuredHotExit = hotExitMode; - } else { - this.configuredHotExit = HotExitConfiguration.ON_EXIT; - } - } - - //#endregion - - //#region primitives (read, create, move, delete, update) - - async read(resource: URI, options?: IReadTextFileOptions): Promise { - const content = await this.fileService.readFile(resource, options); - - // in case of acceptTextOnly: true, we check the first - // chunk for possibly being binary by looking for 0-bytes - // we limit this check to the first 512 bytes - this.validateBinary(content.value, options); - - return { - ...content, - encoding: 'utf8', - value: content.value.toString() - }; - } - - async readStream(resource: URI, options?: IReadTextFileOptions): Promise { - const stream = await this.fileService.readFileStream(resource, options); - - // in case of acceptTextOnly: true, we check the first - // chunk for possibly being binary by looking for 0-bytes - // we limit this check to the first 512 bytes - let checkedForBinary = false; - const throwOnBinary = (data: VSBuffer): Error | undefined => { - if (!checkedForBinary) { - checkedForBinary = true; - - this.validateBinary(data, options); - } - - return undefined; - }; - - return { - ...stream, - encoding: 'utf8', - value: await createTextBufferFactoryFromStream(stream.value, undefined, options && options.acceptTextOnly ? throwOnBinary : undefined) - }; - } - - private validateBinary(buffer: VSBuffer, options?: IReadTextFileOptions): void { - if (!options || !options.acceptTextOnly) { - return; // no validation needed - } - - // in case of acceptTextOnly: true, we check the first - // chunk for possibly being binary by looking for 0-bytes - // we limit this check to the first 512 bytes - for (let i = 0; i < buffer.byteLength && i < 512; i++) { - if (buffer.readUInt8(i) === 0) { - throw new TextFileOperationError(nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), TextFileOperationResult.FILE_IS_BINARY, options); - } - } - } - - async create(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise { - const stat = await this.doCreate(resource, value, options); - - // If we had an existing model for the given resource, load - // it again to make sure it is up to date with the contents - // we just wrote into the underlying resource by calling - // revert() - const existingModel = this.models.get(resource); - if (existingModel && !existingModel.isDisposed()) { - await existingModel.revert(); - } - - return stat; - } - - protected doCreate(resource: URI, value?: string | ITextSnapshot, options?: ICreateFileOptions): Promise { - return this.fileService.createFile(resource, toBufferOrReadable(value), options); - } - - async write(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise { - return this.fileService.writeFile(resource, toBufferOrReadable(value), options); - } - - async delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise { - const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); - - await this.revertAll(dirtyFiles, { soft: true }); - - return this.fileService.del(resource, options); - } - - async move(source: URI, target: URI, overwrite?: boolean): Promise { - - // await onWillMove event joiners - await this.notifyOnWillMove(source, target); - - // find all models that related to either source or target (can be many if resource is a folder) - const sourceModels: ITextFileEditorModel[] = []; - const conflictingModels: ITextFileEditorModel[] = []; - for (const model of this.getFileModels()) { - const resource = model.getResource(); - - if (isEqualOrParent(resource, target, false /* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) { - conflictingModels.push(model); - } - - if (isEqualOrParent(resource, source)) { - sourceModels.push(model); - } - } - - // remember each source model to load again after move is done - // with optional content to restore if it was dirty - type ModelToRestore = { resource: URI; snapshot?: ITextSnapshot }; - const modelsToRestore: ModelToRestore[] = []; - for (const sourceModel of sourceModels) { - const sourceModelResource = sourceModel.getResource(); - - // If the source is the actual model, just use target as new resource - let modelToRestoreResource: URI; - if (isEqual(sourceModelResource, source)) { - modelToRestoreResource = target; - } - - // Otherwise a parent folder of the source is being moved, so we need - // to compute the target resource based on that - else { - modelToRestoreResource = joinPath(target, sourceModelResource.path.substr(source.path.length + 1)); - } - - const modelToRestore: ModelToRestore = { resource: modelToRestoreResource }; - if (sourceModel.isDirty()) { - modelToRestore.snapshot = sourceModel.createSnapshot(); - } - - modelsToRestore.push(modelToRestore); - } - - // in order to move, we need to soft revert all dirty models, - // both from the source as well as the target if any - const dirtyModels = [...sourceModels, ...conflictingModels].filter(model => model.isDirty()); - await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.getResource()), { soft: true }); - - // now we can rename the source to target via file operation - let stat: IFileStatWithMetadata; - try { - stat = await this.fileService.move(source, target, overwrite); - } catch (error) { - - // in case of any error, ensure to set dirty flag back - dirtyModels.forEach(dirtyModel => dirtyModel.makeDirty()); - - throw error; - } - - // finally, restore models that we had loaded previously - await Promise.all(modelsToRestore.map(async modelToRestore => { - - // restore the model, forcing a reload. this is important because - // we know the file has changed on disk after the move and the - // model might have still existed with the previous state. this - // ensures we are not tracking a stale state. - const restoredModel = await this.models.loadOrCreate(modelToRestore.resource, { reload: { async: false } }); - - // restore previous dirty content if any and ensure to mark - // the model as dirty - if (modelToRestore.snapshot && restoredModel.isResolved()) { - this.modelService.updateModel(restoredModel.textEditorModel, createTextBufferFactoryFromSnapshot(modelToRestore.snapshot)); - - restoredModel.makeDirty(); - } - })); - - return stat; - } - - private async notifyOnWillMove(source: URI, target: URI): Promise { - const waitForPromises: Promise[] = []; - - // fire event - this._onWillMove.fire({ - oldResource: source, - newResource: target, - waitUntil(promise: Promise) { - waitForPromises.push(promise.then(undefined, errors.onUnexpectedError)); - } - }); - - // prevent async waitUntil-calls - Object.freeze(waitForPromises); - - await Promise.all(waitForPromises); - } - - //#endregion - - //#region save/revert - - async save(resource: URI, options?: ISaveOptions): Promise { - - // Run a forced save if we detect the file is not dirty so that save participants can still run - if (options && options.force && this.fileService.canHandleResource(resource) && !this.isDirty(resource)) { - const model = this._models.get(resource); - if (model) { - options.reason = SaveReason.EXPLICIT; - - await model.save(options); - - return !model.isDirty(); - } - } - - const result = await this.saveAll([resource], options); - - return result.results.length === 1 && !!result.results[0].success; - } - - async confirmSave(resources?: URI[]): Promise { - if (this.environmentService.isExtensionDevelopment) { - if (!this.environmentService.args['extension-development-confirm-save']) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) - } - } - - const resourcesToConfirm = this.getDirty(resources); - if (resourcesToConfirm.length === 0) { - return ConfirmResult.DONT_SAVE; - } - return promptSave(this.dialogService, resourcesToConfirm); - } - - async confirmOverwrite(resource: URI): Promise { - const confirm: IConfirmation = { - message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), - detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), - primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; - - return (await this.dialogService.confirm(confirm)).confirmed; - } - - saveAll(includeUntitled?: boolean, options?: ISaveOptions): Promise; - saveAll(resources: URI[], options?: ISaveOptions): Promise; - saveAll(arg1?: boolean | URI[], options?: ISaveOptions): Promise { - - // get all dirty - let toSave: URI[] = []; - if (Array.isArray(arg1)) { - toSave = this.getDirty(arg1); - } else { - toSave = this.getDirty(); - } - - // split up between files and untitled - const filesToSave: URI[] = []; - const untitledToSave: URI[] = []; - toSave.forEach(resourceToSave => { - if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && resourceToSave.scheme === Schemas.untitled) { - untitledToSave.push(resourceToSave); - } else { - filesToSave.push(resourceToSave); - } - }); - - return this.doSaveAll(filesToSave, untitledToSave, options); - } - - private async doSaveAll(fileResources: URI[], untitledResources: URI[], options?: ISaveOptions): Promise { - - // Handle files first that can just be saved - const result = await this.doSaveAllFiles(fileResources, options); - - // Preflight for untitled to handle cancellation from the dialog - const targetsForUntitled: URI[] = []; - for (const untitled of untitledResources) { - if (this.untitledEditorService.exists(untitled)) { - let targetUri: URI; - - // Untitled with associated file path don't need to prompt - if (this.untitledEditorService.hasAssociatedFilePath(untitled)) { - targetUri = toLocalResource(untitled, this.environmentService.configuration.remoteAuthority); - } - - // Otherwise ask user - else { - const targetPath = await this.promptForPath(untitled, this.suggestFileName(untitled)); - if (!targetPath) { - return { results: [...fileResources, ...untitledResources].map(r => ({ source: r })) }; - } - - targetUri = targetPath; - } - - targetsForUntitled.push(targetUri); - } - } - - // Handle untitled - await Promise.all(targetsForUntitled.map(async (target, index) => { - const uri = await this.saveAs(untitledResources[index], target); - - result.results.push({ - source: untitledResources[index], - target: uri, - success: !!uri - }); - })); - - return result; - } - - protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: string[]): Promise { - - // Help user to find a name for the file by opening it first - await this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true } }); - - return this.fileDialogService.pickFileToSave(this.getSaveDialogOptions(defaultUri, availableFileSystems)); - } - - private getSaveDialogOptions(defaultUri: URI, availableFileSystems?: string[]): ISaveDialogOptions { - const options: ISaveDialogOptions = { - defaultUri, - title: nls.localize('saveAsTitle', "Save As"), - availableFileSystems, - }; - - // Filters are only enabled on Windows where they work properly - if (!platform.isWindows) { - return options; - } - - interface IFilter { name: string; extensions: string[]; } - - // Build the file filter by using our known languages - const ext: string | undefined = defaultUri ? extname(defaultUri) : undefined; - let matchingFilter: IFilter | undefined; - const filters: IFilter[] = coalesce(this.modeService.getRegisteredLanguageNames().map(languageName => { - const extensions = this.modeService.getExtensions(languageName); - if (!extensions || !extensions.length) { - return null; - } - - const filter: IFilter = { name: languageName, extensions: extensions.slice(0, 10).map(e => trim(e, '.')) }; - - if (ext && extensions.indexOf(ext) >= 0) { - matchingFilter = filter; - - return null; // matching filter will be added last to the top - } - - return filter; - })); - - // Filters are a bit weird on Windows, based on having a match or not: - // Match: we put the matching filter first so that it shows up selected and the all files last - // No match: we put the all files filter first - const allFilesFilter = { name: nls.localize('allFiles', "All Files"), extensions: ['*'] }; - if (matchingFilter) { - filters.unshift(matchingFilter); - filters.unshift(allFilesFilter); - } else { - filters.unshift(allFilesFilter); - } - - // Allow to save file without extension - filters.push({ name: nls.localize('noExt', "No Extension"), extensions: [''] }); - - options.filters = filters; - - return options; - } - - private async doSaveAllFiles(resources?: URI[], options: ISaveOptions = Object.create(null)): Promise { - const dirtyFileModels = this.getDirtyFileModels(Array.isArray(resources) ? resources : undefined /* Save All */) - .filter(model => { - if ((model.hasState(ModelState.CONFLICT) || model.hasState(ModelState.ERROR)) && (options.reason === SaveReason.AUTO || options.reason === SaveReason.FOCUS_CHANGE || options.reason === SaveReason.WINDOW_CHANGE)) { - return false; // if model is in save conflict or error, do not save unless save reason is explicit or not provided at all - } - - return true; - }); - - const mapResourceToResult = new ResourceMap(); - dirtyFileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() - }); - }); - - await Promise.all(dirtyFileModels.map(async model => { - await model.save(options); - - if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); - if (result) { - result.success = true; - } - } - })); - - return { results: mapResourceToResult.values() }; - } - - private getFileModels(arg1?: URI | URI[]): ITextFileEditorModel[] { - if (Array.isArray(arg1)) { - const models: ITextFileEditorModel[] = []; - arg1.forEach(resource => { - models.push(...this.getFileModels(resource)); - }); - - return models; - } - - return this._models.getAll(arg1); - } - - private getDirtyFileModels(resources?: URI | URI[]): ITextFileEditorModel[] { - return this.getFileModels(resources).filter(model => model.isDirty()); - } - - async saveAs(resource: URI, targetResource?: URI, options?: ISaveOptions): Promise { - - // Get to target resource - if (!targetResource) { - let dialogPath = resource; - if (resource.scheme === Schemas.untitled) { - dialogPath = this.suggestFileName(resource); - } - - targetResource = await this.promptForPath(resource, dialogPath, options ? options.availableFileSystems : undefined); - } - - if (!targetResource) { - return; // user canceled - } - - // Just save if target is same as models own resource - if (resource.toString() === targetResource.toString()) { - await this.save(resource, options); - - return resource; - } - - // Do it - return this.doSaveAs(resource, targetResource, options); - } - - private async doSaveAs(resource: URI, target: URI, options?: ISaveOptions): Promise { - - // Retrieve text model from provided resource if any - let model: ITextFileEditorModel | UntitledEditorModel | undefined; - if (this.fileService.canHandleResource(resource)) { - model = this._models.get(resource); - } else if (resource.scheme === Schemas.untitled && this.untitledEditorService.exists(resource)) { - model = await this.untitledEditorService.loadOrCreate({ resource }); - } - - // We have a model: Use it (can be null e.g. if this file is binary and not a text file or was never opened before) - let result: boolean; - if (model) { - result = await this.doSaveTextFileAs(model, resource, target, options); - } - - // Otherwise we can only copy - else { - await this.fileService.copy(resource, target); - - result = true; - } - - // Return early if the operation was not running - if (!result) { - return target; - } - - // Revert the source - await this.revert(resource); - - return target; - } - - private async doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI, options?: ISaveOptions): Promise { - - // Prefer an existing model if it is already loaded for the given target resource - let targetExists: boolean = false; - let targetModel = this.models.get(target); - if (targetModel && targetModel.isResolved()) { - targetExists = true; - } - - // Otherwise create the target file empty if it does not exist already and resolve it from there - else { - targetExists = await this.fileService.exists(target); - - // create target model adhoc if file does not exist yet - if (!targetExists) { - await this.create(target, ''); - } - - targetModel = await this.models.loadOrCreate(target); - } - - try { - - // Confirm to overwrite if we have an untitled file with associated file where - // the file actually exists on disk and we are instructed to save to that file - // path. This can happen if the file was created after the untitled file was opened. - // See https://github.com/Microsoft/vscode/issues/67946 - let write: boolean; - if (sourceModel instanceof UntitledEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.getResource(), this.environmentService.configuration.remoteAuthority))) { - write = await this.confirmOverwrite(target); - } else { - write = true; - } - - if (!write) { - return false; - } - - // take over model value, encoding and mode (only if more specific) from source model - targetModel.updatePreferredEncoding(sourceModel.getEncoding()); - if (sourceModel.isResolved() && targetModel.isResolved()) { - this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); - - const sourceMode = sourceModel.textEditorModel.getLanguageIdentifier(); - const targetMode = targetModel.textEditorModel.getLanguageIdentifier(); - if (sourceMode.language !== PLAINTEXT_MODE_ID && targetMode.language === PLAINTEXT_MODE_ID) { - targetModel.textEditorModel.setMode(sourceMode); // only use if more specific than plain/text - } - } - - // save model - await targetModel.save(options); - - return true; - } catch (error) { - - // binary model: delete the file and run the operation again - if ( - (error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY || - (error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE - ) { - await this.fileService.del(target); - - return this.doSaveTextFileAs(sourceModel, resource, target, options); - } - - throw error; - } - } - - private suggestFileName(untitledResource: URI): URI { - const untitledFileName = this.untitledEditorService.suggestFileName(untitledResource); - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - const schemeFilter = remoteAuthority ? Schemas.vscodeRemote : Schemas.file; - - const lastActiveFile = this.historyService.getLastActiveFile(schemeFilter); - if (lastActiveFile) { - const lastDir = dirname(lastActiveFile); - return joinPath(lastDir, untitledFileName); - } - - const lastActiveFolder = this.historyService.getLastActiveWorkspaceRoot(schemeFilter); - if (lastActiveFolder) { - return joinPath(lastActiveFolder, untitledFileName); - } - - return untitledResource.with({ path: untitledFileName }); - } - - async revert(resource: URI, options?: IRevertOptions): Promise { - const result = await this.revertAll([resource], options); - - return result.results.length === 1 && !!result.results[0].success; - } - - async revertAll(resources?: URI[], options?: IRevertOptions): Promise { - - // Revert files first - const revertOperationResult = await this.doRevertAllFiles(resources, options); - - // Revert untitled - const untitledReverted = this.untitledEditorService.revertAll(resources); - untitledReverted.forEach(untitled => revertOperationResult.results.push({ source: untitled, success: true })); - - return revertOperationResult; - } - - private async doRevertAllFiles(resources?: URI[], options?: IRevertOptions): Promise { - const fileModels = options && options.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); - - const mapResourceToResult = new ResourceMap(); - fileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() - }); - }); - - await Promise.all(fileModels.map(async model => { - try { - await model.revert(options && options.soft); - - if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); - if (result) { - result.success = true; - } - } - } catch (error) { - - // FileNotFound means the file got deleted meanwhile, so still record as successful revert - if ((error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) { - const result = mapResourceToResult.get(model.getResource()); - if (result) { - result.success = true; - } - } - - // Otherwise bubble up the error - else { - throw error; - } - } - })); - - return { results: mapResourceToResult.values() }; - } - - getDirty(resources?: URI[]): URI[] { - - // Collect files - const dirty = this.getDirtyFileModels(resources).map(m => m.getResource()); - - // Add untitled ones - dirty.push(...this.untitledEditorService.getDirty(resources)); - - return dirty; - } - - isDirty(resource?: URI): boolean { - - // Check for dirty file - if (this._models.getAll(resource).some(model => model.isDirty())) { - return true; - } - - // Check for dirty untitled - return this.untitledEditorService.getDirty().some(dirty => !resource || dirty.toString() === resource.toString()); - } - - //#endregion - - //#region config - - getAutoSaveMode(): AutoSaveMode { - if (this.configuredAutoSaveOnFocusChange) { - return AutoSaveMode.ON_FOCUS_CHANGE; - } - - if (this.configuredAutoSaveOnWindowChange) { - return AutoSaveMode.ON_WINDOW_CHANGE; - } - - if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { - return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; - } - - return AutoSaveMode.OFF; - } - - getAutoSaveConfiguration(): IAutoSaveConfiguration { - return { - autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, - autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, - autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange - }; - } - - get isHotExitEnabled(): boolean { - return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; - } - - //#endregion - - dispose(): void { - - // Clear all caches - this._models.clear(); - - super.dispose(); - } -} - -export async function promptSave(dialogService: IDialogService, resourcesToConfirm: readonly URI[]) { - const message = resourcesToConfirm.length === 1 - ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) - : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); - - const buttons: string[] = [ - resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), - nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), - nls.localize('cancel', "Cancel") - ]; - - const { choice } = await dialogService.show(Severity.Warning, message, buttons, { - cancelId: 2, - detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") - }); - - switch (choice) { - case 0: return ConfirmResult.SAVE; - case 1: return ConfirmResult.DONT_SAVE; - default: return ConfirmResult.CANCEL; - } -} - diff --git a/src/vs/workbench/services/textfile/node/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts similarity index 98% rename from src/vs/workbench/services/textfile/node/textFileService.ts rename to src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index ed012a4c702..d621479da05 100644 --- a/src/vs/workbench/services/textfile/node/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -5,7 +5,7 @@ import { tmpdir } from 'os'; import { localize } from 'vs/nls'; -import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; +import { AbstractTextFileService } from 'vs/workbench/services/textfile/browser/textFileService'; import { ITextFileService, ITextFileStreamContent, ITextFileContent, IResourceEncodings, IResourceEncoding, IReadTextFileOptions, IWriteTextFileOptions, stringToSnapshot, TextFileOperationResult, TextFileOperationError } from 'vs/workbench/services/textfile/common/textfiles'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { URI } from 'vs/base/common/uri'; @@ -28,7 +28,7 @@ import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textMo import { ITextSnapshot } from 'vs/editor/common/model'; import { nodeReadableToString, streamToNodeReadable, nodeStreamToVSBufferReadable } from 'vs/base/node/stream'; -export class NodeTextFileService extends TextFileService { +export class NativeTextFileService extends AbstractTextFileService { private _encoding!: EncodingOracle; get encoding(): EncodingOracle { @@ -404,4 +404,4 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { } } -registerSingleton(ITextFileService, NodeTextFileService); +registerSingleton(ITextFileService, NativeTextFileService); diff --git a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts index eab223e0d4a..6d8282d7830 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts @@ -22,7 +22,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { join, basename } from 'vs/base/common/path'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { UTF16be, UTF16le, UTF8_with_bom, UTF8 } from 'vs/base/node/encoding'; -import { NodeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workbench/services/textfile/node/textFileService'; +import { NativeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import { DefaultEndOfLine, ITextSnapshot } from 'vs/editor/common/model'; import { TextModel } from 'vs/editor/common/model/textModel'; import { isWindows } from 'vs/base/common/platform'; @@ -37,7 +37,7 @@ class ServiceAccessor { } } -class TestNodeTextFileService extends NodeTextFileService { +class TestNativeTextFileService extends NativeTextFileService { private _testEncoding: TestEncodingOracle | undefined; get encoding(): TestEncodingOracle { @@ -84,7 +84,7 @@ suite('Files - TextFileService i/o', () => { const collection = new ServiceCollection(); collection.set(IFileService, fileService); - service = instantiationService.createChild(collection).createInstance(TestNodeTextFileService); + service = instantiationService.createChild(collection).createInstance(TestNativeTextFileService); const id = generateUuid(); testDir = join(parentDir, id); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 07676420066..c8e4de0a55a 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -7,7 +7,7 @@ import * as sinon from 'sinon'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestWindowsService, TestContextService, TestFileService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestWindowsService, TestContextService, TestFileService, TestHostService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWindowsService } from 'vs/platform/windows/common/windows'; @@ -21,6 +21,7 @@ import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/commo import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; class ServiceAccessor { constructor( @@ -30,7 +31,8 @@ class ServiceAccessor { @IWindowsService public windowsService: TestWindowsService, @IWorkspaceContextService public contextService: TestContextService, @IModelService public modelService: ModelServiceImpl, - @IFileService public fileService: TestFileService + @IFileService public fileService: TestFileService, + @IHostService public hostService: TestHostService ) { } } @@ -424,7 +426,7 @@ suite('Files - TextFileService', () => { } // Set multiple windows if required if (multipleWindows) { - accessor.windowsService.windowCount = 2; + accessor.hostService.windowCount = Promise.resolve(2); } // Set cancel to force a veto if hot exit does not trigger service.setConfirmResult(ConfirmResult.CANCEL); diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index 3bf0c2fee4e..aefb915e2b6 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { virtualMachineHint } from 'vs/base/node/id'; import * as perf from 'vs/base/common/performance'; import * as os from 'os'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -308,7 +308,7 @@ class TimerService implements ITimerService { private _startupMetrics?: Promise; constructor( - @IWindowsService private readonly _windowsService: IWindowsService, + @IHostService private readonly _hostService: IHostService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @@ -380,7 +380,7 @@ class TimerService implements ITimerService { isLatestVersion: Boolean(await this._updateService.isLatestVersion()), didUseCachedData: didUseCachedData(), windowKind: this._lifecycleService.startupKind, - windowCount: await this._windowsService.getWindowCount(), + windowCount: await this._hostService.windowCount, viewletId: activeViewlet ? activeViewlet.getId() : undefined, editorIds: this._editorService.visibleEditors.map(input => input.getTypeId()), panelId: activePanel ? activePanel.getId() : undefined, diff --git a/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts index bffc453c49b..a97ea749b8a 100644 --- a/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/browser/workspaceEditingService.ts @@ -31,6 +31,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export class WorkspaceEditingService implements IWorkspaceEditingService { @@ -54,7 +55,8 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { @IFileDialogService private readonly fileDialogService: IFileDialogService, @IDialogService private readonly dialogService: IDialogService, @ILifecycleService readonly lifecycleService: ILifecycleService, - @ILabelService readonly labelService: ILabelService + @ILabelService readonly labelService: ILabelService, + @IHostService private readonly hostService: IHostService ) { this.registerListeners(); } @@ -82,7 +84,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return false; // only care about untitled workspaces to ask for saving } - const windowCount = await this.windowsService.getWindowCount(); + const windowCount = await this.hostService.windowCount; if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { return false; // Windows/Linux: quits when last window is closed, so do not ask then diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 73a3517bd60..4ed07ea15ed 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -82,10 +82,11 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedPr import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; -import { NodeTextFileService } from 'vs/workbench/services/textfile/node/textFileService'; +import { NativeTextFileService } from 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import { Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -180,7 +181,7 @@ export class TestContextService implements IWorkspaceContextService { } } -export class TestTextFileService extends NodeTextFileService { +export class TestTextFileService extends NativeTextFileService { public cleanupBackupsBeforeShutdownCalled: boolean; private promptPath: URI; @@ -199,7 +200,7 @@ export class TestTextFileService extends NodeTextFileService { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, - @IWindowsService windowsService: IWindowsService, + @IHostService hostService: IHostService, @IHistoryService historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @@ -219,7 +220,7 @@ export class TestTextFileService extends NodeTextFileService { environmentService, notificationService, backupFileService, - windowsService, + hostService, historyService, contextKeyService, dialogService, @@ -311,6 +312,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IDecorationsService, new TestDecorationsService()); instantiationService.stub(IExtensionService, new TestExtensionService()); instantiationService.stub(IWindowsService, new TestWindowsService()); + instantiationService.stub(IHostService, instantiationService.createInstance(TestHostService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(IThemeService, new TestThemeService()); @@ -1349,8 +1351,6 @@ export class TestWindowsService implements IWindowsService { _serviceBrand: undefined; - public windowCount = 1; - readonly onWindowOpen: Event = Event.None; readonly onWindowFocus: Event = Event.None; readonly onWindowBlur: Event = Event.None; @@ -1490,10 +1490,6 @@ export class TestWindowsService implements IWindowsService { throw new Error('not implemented'); } - getWindowCount(): Promise { - return Promise.resolve(this.windowCount); - } - newWindowTab(): Promise { return Promise.resolve(); } @@ -1634,3 +1630,10 @@ export class RemoteFileSystemProvider implements IFileSystemProvider { } export const productService: IProductService = { _serviceBrand: undefined, ...product }; + +export class TestHostService implements IHostService { + + _serviceBrand: undefined; + + windowCount = Promise.resolve(1); +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 73fc63f220c..edecfd44bc6 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -81,6 +81,7 @@ import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; import 'vs/workbench/services/userData/common/settingsMergeService'; import 'vs/workbench/services/workspace/browser/workspaceEditingService'; +import 'vs/workbench/services/host/browser/browserHostService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 7739c33362a..9afb71f520c 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -31,7 +31,7 @@ import 'vs/workbench/services/integrity/node/integrityService'; import 'vs/workbench/services/textMate/electron-browser/textMateService'; import 'vs/workbench/services/search/node/searchService'; import 'vs/workbench/services/output/node/outputChannelModelService'; -import 'vs/workbench/services/textfile/node/textFileService'; +import 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import 'vs/workbench/services/dialogs/electron-browser/dialogService'; import 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; import 'vs/workbench/services/keybinding/electron-browser/keybinding.contribution'; @@ -49,6 +49,7 @@ import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/credentials/node/credentialsService'; import 'vs/workbench/services/url/electron-browser/urlService'; import 'vs/workbench/services/workspace/electron-browser/workspacesService'; +import 'vs/workbench/services/host/electron-browser/desktopHostService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index dc8eb1bb5e6..2416a9fc371 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -30,7 +30,7 @@ import 'vs/workbench/services/integrity/browser/integrityService'; import 'vs/workbench/services/textMate/browser/textMateService'; import 'vs/workbench/services/search/common/searchService'; import 'vs/workbench/services/output/common/outputChannelModelService'; -import 'vs/workbench/services/textfile/browser/textFileService'; +import 'vs/workbench/services/textfile/browser/browserTextFileService'; import 'vs/workbench/services/keybinding/browser/keymapService'; import 'vs/workbench/services/extensions/browser/extensionService'; import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; From cd0f833fe096e0126d3b0dc2039b4913978277ff Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 19:14:09 +0200 Subject: [PATCH 78/82] title - introduce remoteName as variable --- .../src/settingsDocumentHelper.ts | 1 + .../browser/parts/titlebar/titlebarPart.ts | 3 +++ .../workbench/browser/workbench.contribution.ts | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index d4ac414897d..970f2a5ca18 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -54,6 +54,7 @@ export class SettingsDocument { completions.push(this.newSimpleCompletionItem('${folderName}', range, localize('folderName', "name of the workspace folder the file is contained in (e.g. myFolder)"))); completions.push(this.newSimpleCompletionItem('${folderPath}', range, localize('folderPath', "file path of the workspace folder the file is contained in (e.g. /Users/Development/myFolder)"))); completions.push(this.newSimpleCompletionItem('${appName}', range, localize('appName', "e.g. VS Code"))); + completions.push(this.newSimpleCompletionItem('${remoteName}', range, localize('remoteName', "e.g. SSH"))); completions.push(this.newSimpleCompletionItem('${dirty}', range, localize('dirty', "a dirty indicator if the active editor is dirty"))); completions.push(this.newSimpleCompletionItem('${separator}', range, localize('separator', "a conditional separator (' - ') that only shows when surrounded by variables with values"))); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 394f522bd67..c26623196d2 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -257,6 +257,7 @@ export class TitlebarPart extends Part implements ITitleService { * {folderName}: e.g. myFolder * {folderPath}: e.g. /Users/Development/myFolder * {appName}: e.g. VS Code + * {remoteName}: e.g. SSH * {dirty}: indicator * {separator}: conditional separator */ @@ -297,6 +298,7 @@ export class TitlebarPart extends Part implements ITitleService { const folderPath = folder ? this.labelService.getUriLabel(folder.uri) : ''; const dirty = editor && editor.isDirty() ? TitlebarPart.TITLE_DIRTY : ''; const appName = this.environmentService.appNameLong; + const remoteName = this.environmentService.configuration.remoteAuthority; const separator = TitlebarPart.TITLE_SEPARATOR; const titleTemplate = this.configurationService.getValue('window.title'); @@ -313,6 +315,7 @@ export class TitlebarPart extends Part implements ITitleService { folderPath, dirty, appName, + remoteName, separator: { label: separator } }); } diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 5504ef50307..1f4d4e11620 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -6,7 +6,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'; +import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; // Configuration (function registerConfiguration(): void { @@ -263,6 +263,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform' nls.localize('rootName', "`\${rootName}`: name of the workspace (e.g. myFolder or myWorkspace)."), nls.localize('rootPath', "`\${rootPath}`: file path of the workspace (e.g. /Users/Development/myWorkspace)."), nls.localize('appName', "`\${appName}`: e.g. VS Code."), + nls.localize('remoteName', "`\${remoteName}`: e.g. SSH"), nls.localize('dirty', "`\${dirty}`: a dirty indicator if the active editor is dirty."), nls.localize('separator', "`\${separator}`: a conditional separator (\" - \") that only shows when surrounded by variables with values or static text.") ].join('\n- '); // intentionally concatenated to not produce a string that is too long for translations @@ -275,7 +276,18 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform' 'properties': { 'window.title': { 'type': 'string', - 'default': isMacintosh ? '${activeEditorShort}${separator}${rootName}' : '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}', + 'default': (() => { + if (isMacintosh && isNative) { + return '${activeEditorShort}${separator}${rootName}'; // macOS has native dirty indicator + } + + const base = '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}'; + if (isWeb) { + return base + '${separator}${remoteName}'; // Web: always show remote indicator + } + + return base; + })(), 'markdownDescription': windowTitleDescription }, 'window.menuBarVisibility': { From bbb56dba81530874e64b6b9d74339b36375c97b6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 18 Sep 2019 19:23:34 +0200 Subject: [PATCH 79/82] web - preserve pathname in URL when opening windows or changing workspaces --- src/vs/workbench/browser/web.simpleservices.ts | 4 ++-- .../contrib/debug/browser/extensionHostDebugService.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 53fb58d10a2..a389464b265 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -241,7 +241,7 @@ export class SimpleWindowService extends Disposable implements IWindowService { for (let i = 0; i < _uris.length; i++) { const uri = _uris[i]; if ('folderUri' in uri) { - const newAddress = `${document.location.origin}/?folder=${uri.folderUri.path}`; + const newAddress = `${document.location.origin}${document.location.pathname}?folder=${uri.folderUri.path}`; if (openFolderInNewWindow) { window.open(newAddress); } else { @@ -249,7 +249,7 @@ export class SimpleWindowService extends Disposable implements IWindowService { } } if ('workspaceUri' in uri) { - const newAddress = `${document.location.origin}/?workspace=${uri.workspaceUri.path}`; + const newAddress = `${document.location.origin}${document.location.pathname}?workspace=${uri.workspaceUri.path}`; if (openFolderInNewWindow) { window.open(newAddress); } else { diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index af19c1bbe2e..f8ce2c468c0 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -51,7 +51,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise { // we pass the "ParsedArgs" as query parameters of the URL - let newAddress = `${document.location.origin}/?`; + let newAddress = `${document.location.origin}${document.location.pathname}?`; let gotFolder = false; const addQueryParameter = (key: string, value: string) => { From f973ba7fb56b34ba148cf9954ccd1bf8e3070bf3 Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 18 Sep 2019 12:41:15 -0700 Subject: [PATCH 80/82] Update `tools` Octicon to be an outline --- .../ui/octiconLabel/octicons/octicons2.css | 2 +- .../ui/octiconLabel/octicons/octicons2.ttf | Bin 35196 -> 35408 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css index 7e86f3a74ca..69e7dac4e6c 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.css @@ -1,6 +1,6 @@ @font-face { font-family: "octicons2"; - src: url("./octicons2.ttf?90586c9ac0aa804395e9c9c0d15d1094") format("truetype"); + src: url("./octicons2.ttf?aa78025ff36faa0aebb5b864685c6dc4") format("truetype"); } .octicon, .mega-octicon { diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons2.ttf index 793aba95d5f9bc54ee6a037e5f5f86da874ea38d..19f3d6e11ce831c241399bffc8d9ddf736051bf1 100644 GIT binary patch delta 516 zcmew}iRr==rU?!r*S2%GF)#>wFfiogWTYmhhy`zQnHZwO5*O~oH?c)YsD29r1Cvrg zesM|rmvavp7#eR(++iTYxZzD(JipCX25#mT3_x&mg?SN--ps(#l zT~yrIoYh#|T-{usk)KIiU7TH6ozYxeOay48x|%+SDPAuIRBNK9&OFzS%vX0A2SyxCo?-cn@wqE6sH*PCnjTQBS$w! zNi|VnUSlU^fub_4;=eHoI@($+e4ABGSc(-VGP%Sup3^=gDJg6!DZqVH`!EX|H#Zvx z3kwTV6iqpFfpWTH+$WvPd>qM(8VKO>`vV^u+Jmmn%JTwRQG^^fk~+# zzqq9R%ejXP42>)kcNoZgVve$l=ePOFz|H)E0SIm`s4sxgn^_n&g(QuP%ZxjWXBn?C z-eWqF_W?5!=rc1V%xfx`73yBx_7Z_yv z2#Wvn(oko7yl%39z#IV~MnM57c}ZyzVI~=%a>ga5dH+_MxrqyUXBy=DOXo`n0U00- bYU?MnFwGX!($f- Date: Wed, 18 Sep 2019 12:41:47 -0700 Subject: [PATCH 81/82] Increase Extension Octicon size to be visible --- .../contrib/extensions/browser/media/extensionsViewlet.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css index 57be7e4e1d4..2a7cd6a497e 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css @@ -197,7 +197,7 @@ } .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon { - font-size: 100%; + font-size: 120%; margin-right: 2px; } From b10bf696e4b8241a6ab29d646a83cfe628228543 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 18 Sep 2019 23:03:05 +0200 Subject: [PATCH 82/82] VSCode Insiders breaks into Chrome developer tools with "TypeError: Cannot read property 'layout' of undefined". Fixes #81063 --- src/vs/workbench/contrib/debug/browser/rawDebugSession.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 45ffb5776a8..16da4c39488 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -601,7 +601,7 @@ export class RawDebugSession implements IDisposable { } else { args[key] = [value]; } - } else if (key === 'extensionDevelopmentPath') { + } else if (key === 'extensionDevelopmentPath' || key === 'enable-proposed-api') { const v = args[key]; if (v) { v.push(value);